# HG changeset patch # User Sam Lantinga # Date 1296936071 28800 # Node ID bb45ecd958d86b48aa5d5e9ca06671f52d7ca1bc # Parent 69f47f2c18562456d1bd2fbec200b569cce7a544 Renamed files for consistency diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/SDL_render.c --- a/src/render/SDL_render.c Sat Feb 05 11:54:46 2011 -0800 +++ b/src/render/SDL_render.c Sat Feb 05 12:01:11 2011 -0800 @@ -27,7 +27,7 @@ #include "SDL_render.h" #include "SDL_sysrender.h" #include "../video/SDL_pixels_c.h" -#include "software/SDL_renderer_sw_c.h" +#include "software/SDL_render_sw_c.h" #define CHECK_RENDERER_MAGIC(renderer, retval) \ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/direct3d/SDL_d3drender.c --- a/src/render/direct3d/SDL_d3drender.c Sat Feb 05 11:54:46 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1048 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2010 Sam Lantinga - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ -#include "SDL_config.h" - -#if SDL_VIDEO_RENDER_D3D - -#include "../../core/windows/SDL_windows.h" - -#include "SDL_loadso.h" -#include "SDL_syswm.h" -#include "../SDL_sysrender.h" - -#if SDL_VIDEO_RENDER_D3D -#define D3D_DEBUG_INFO -#include -#endif - -#ifdef ASSEMBLE_SHADER -/////////////////////////////////////////////////////////////////////////// -// ID3DXBuffer: -// ------------ -// The buffer object is used by D3DX to return arbitrary size data. -// -// GetBufferPointer - -// Returns a pointer to the beginning of the buffer. -// -// GetBufferSize - -// Returns the size of the buffer, in bytes. -/////////////////////////////////////////////////////////////////////////// - -typedef interface ID3DXBuffer ID3DXBuffer; -typedef interface ID3DXBuffer *LPD3DXBUFFER; - -// {8BA5FB08-5195-40e2-AC58-0D989C3A0102} -DEFINE_GUID(IID_ID3DXBuffer, -0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2); - -#undef INTERFACE -#define INTERFACE ID3DXBuffer - -typedef interface ID3DXBuffer { - const struct ID3DXBufferVtbl FAR* lpVtbl; -} ID3DXBuffer; -typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl; -const struct ID3DXBufferVtbl -{ - // IUnknown - STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE; - STDMETHOD_(ULONG, AddRef)(THIS) PURE; - STDMETHOD_(ULONG, Release)(THIS) PURE; - - // ID3DXBuffer - STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE; - STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE; -}; - -HRESULT WINAPI - D3DXAssembleShader( - LPCSTR pSrcData, - UINT SrcDataLen, - CONST LPVOID* pDefines, - LPVOID pInclude, - DWORD Flags, - LPD3DXBUFFER* ppShader, - LPD3DXBUFFER* ppErrorMsgs); - -#endif /* ASSEMBLE_SHADER */ - - -/* Direct3D renderer implementation */ - -static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags); -static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, const void *pixels, - int pitch); -static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, void **pixels, int *pitch); -static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static int D3D_RenderDrawPoints(SDL_Renderer * renderer, - const SDL_Point * points, int count); -static int D3D_RenderDrawLines(SDL_Renderer * renderer, - const SDL_Point * points, int count); -static int D3D_RenderFillRects(SDL_Renderer * renderer, - const SDL_Rect ** rects, int count); -static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * srcrect, const SDL_Rect * dstrect); -static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - Uint32 format, void * pixels, int pitch); -static void D3D_RenderPresent(SDL_Renderer * renderer); -static void D3D_DestroyTexture(SDL_Renderer * renderer, - SDL_Texture * texture); -static void D3D_DestroyRenderer(SDL_Renderer * renderer); - - -SDL_RenderDriver D3D_RenderDriver = { - D3D_CreateRenderer, - { - "direct3d", - (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), - 1, - {SDL_PIXELFORMAT_ARGB8888}, - 0, - 0} -}; - -typedef struct -{ - void* d3dDLL; - IDirect3D9 *d3d; - IDirect3DDevice9 *device; - UINT adapter; - D3DPRESENT_PARAMETERS pparams; - SDL_bool beginScene; -} D3D_RenderData; - -typedef struct -{ - IDirect3DTexture9 *texture; -} D3D_TextureData; - -typedef struct -{ - float x, y, z; - float rhw; - DWORD color; - float u, v; -} Vertex; - -static void -D3D_SetError(const char *prefix, HRESULT result) -{ - const char *error; - - switch (result) { - case D3DERR_WRONGTEXTUREFORMAT: - error = "WRONGTEXTUREFORMAT"; - break; - case D3DERR_UNSUPPORTEDCOLOROPERATION: - error = "UNSUPPORTEDCOLOROPERATION"; - break; - case D3DERR_UNSUPPORTEDCOLORARG: - error = "UNSUPPORTEDCOLORARG"; - break; - case D3DERR_UNSUPPORTEDALPHAOPERATION: - error = "UNSUPPORTEDALPHAOPERATION"; - break; - case D3DERR_UNSUPPORTEDALPHAARG: - error = "UNSUPPORTEDALPHAARG"; - break; - case D3DERR_TOOMANYOPERATIONS: - error = "TOOMANYOPERATIONS"; - break; - case D3DERR_CONFLICTINGTEXTUREFILTER: - error = "CONFLICTINGTEXTUREFILTER"; - break; - case D3DERR_UNSUPPORTEDFACTORVALUE: - error = "UNSUPPORTEDFACTORVALUE"; - break; - case D3DERR_CONFLICTINGRENDERSTATE: - error = "CONFLICTINGRENDERSTATE"; - break; - case D3DERR_UNSUPPORTEDTEXTUREFILTER: - error = "UNSUPPORTEDTEXTUREFILTER"; - break; - case D3DERR_CONFLICTINGTEXTUREPALETTE: - error = "CONFLICTINGTEXTUREPALETTE"; - break; - case D3DERR_DRIVERINTERNALERROR: - error = "DRIVERINTERNALERROR"; - break; - case D3DERR_NOTFOUND: - error = "NOTFOUND"; - break; - case D3DERR_MOREDATA: - error = "MOREDATA"; - break; - case D3DERR_DEVICELOST: - error = "DEVICELOST"; - break; - case D3DERR_DEVICENOTRESET: - error = "DEVICENOTRESET"; - break; - case D3DERR_NOTAVAILABLE: - error = "NOTAVAILABLE"; - break; - case D3DERR_OUTOFVIDEOMEMORY: - error = "OUTOFVIDEOMEMORY"; - break; - case D3DERR_INVALIDDEVICE: - error = "INVALIDDEVICE"; - break; - case D3DERR_INVALIDCALL: - error = "INVALIDCALL"; - break; - case D3DERR_DRIVERINVALIDCALL: - error = "DRIVERINVALIDCALL"; - break; - case D3DERR_WASSTILLDRAWING: - error = "WASSTILLDRAWING"; - break; - default: - error = "UNKNOWN"; - break; - } - SDL_SetError("%s: %s", prefix, error); -} - -static D3DFORMAT -PixelFormatToD3DFMT(Uint32 format) -{ - switch (format) { - case SDL_PIXELFORMAT_RGB565: - return D3DFMT_R5G6B5; - case SDL_PIXELFORMAT_RGB888: - return D3DFMT_X8R8G8B8; - case SDL_PIXELFORMAT_ARGB8888: - return D3DFMT_A8R8G8B8; - default: - return D3DFMT_UNKNOWN; - } -} - -static Uint32 -D3DFMTToPixelFormat(D3DFORMAT format) -{ - switch (format) { - case D3DFMT_R5G6B5: - return SDL_PIXELFORMAT_RGB565; - case D3DFMT_X8R8G8B8: - return SDL_PIXELFORMAT_RGB888; - case D3DFMT_A8R8G8B8: - return SDL_PIXELFORMAT_ARGB8888; - default: - return SDL_PIXELFORMAT_UNKNOWN; - } -} - -SDL_Renderer * -D3D_CreateRenderer(SDL_Window * window, Uint32 flags) -{ - SDL_Renderer *renderer; - D3D_RenderData *data; - SDL_SysWMinfo windowinfo; - HRESULT result; - D3DPRESENT_PARAMETERS pparams; - IDirect3DSwapChain9 *chain; - D3DCAPS9 caps; - Uint32 window_flags; - int w, h; - SDL_DisplayMode fullscreen_mode; - - renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); - if (!renderer) { - SDL_OutOfMemory(); - return NULL; - } - - data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_free(renderer); - SDL_OutOfMemory(); - return NULL; - } - - data->d3dDLL = SDL_LoadObject("D3D9.DLL"); - if (data->d3dDLL) { - IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion); - - D3DCreate = - (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(data->d3dDLL, - "Direct3DCreate9"); - if (D3DCreate) { - data->d3d = D3DCreate(D3D_SDK_VERSION); - } - if (!data->d3d) { - SDL_UnloadObject(data->d3dDLL); - data->d3dDLL = NULL; - } - } - if (!data->d3d) { - SDL_free(renderer); - SDL_free(data); - SDL_SetError("Unable to create Direct3D interface"); - return NULL; - } - - renderer->CreateTexture = D3D_CreateTexture; - renderer->UpdateTexture = D3D_UpdateTexture; - renderer->LockTexture = D3D_LockTexture; - renderer->UnlockTexture = D3D_UnlockTexture; - renderer->RenderDrawPoints = D3D_RenderDrawPoints; - renderer->RenderDrawLines = D3D_RenderDrawLines; - renderer->RenderFillRects = D3D_RenderFillRects; - renderer->RenderCopy = D3D_RenderCopy; - renderer->RenderReadPixels = D3D_RenderReadPixels; - renderer->RenderPresent = D3D_RenderPresent; - renderer->DestroyTexture = D3D_DestroyTexture; - renderer->DestroyRenderer = D3D_DestroyRenderer; - renderer->info = D3D_RenderDriver.info; - renderer->driverdata = data; - - renderer->info.flags = SDL_RENDERER_ACCELERATED; - - SDL_VERSION(&windowinfo.version); - SDL_GetWindowWMInfo(window, &windowinfo); - - window_flags = SDL_GetWindowFlags(window); - SDL_GetWindowSize(window, &w, &h); - SDL_GetWindowDisplayMode(window, &fullscreen_mode); - - SDL_zero(pparams); - pparams.hDeviceWindow = windowinfo.info.win.window; - pparams.BackBufferWidth = w; - pparams.BackBufferHeight = h; - if (window_flags & SDL_WINDOW_FULLSCREEN) { - pparams.BackBufferFormat = - PixelFormatToD3DFMT(fullscreen_mode.format); - } else { - pparams.BackBufferFormat = D3DFMT_UNKNOWN; - } - pparams.BackBufferCount = 1; - pparams.SwapEffect = D3DSWAPEFFECT_DISCARD; - - if (window_flags & SDL_WINDOW_FULLSCREEN) { - pparams.Windowed = FALSE; - pparams.FullScreen_RefreshRateInHz = - fullscreen_mode.refresh_rate; - } else { - pparams.Windowed = TRUE; - pparams.FullScreen_RefreshRateInHz = 0; - } - if (flags & SDL_RENDERER_PRESENTVSYNC) { - pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - } else { - pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - } - - /* FIXME: Which adapter? */ - data->adapter = D3DADAPTER_DEFAULT; - IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps); - - result = IDirect3D9_CreateDevice(data->d3d, data->adapter, - D3DDEVTYPE_HAL, - pparams.hDeviceWindow, - (caps. - DevCaps & - D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? - D3DCREATE_HARDWARE_VERTEXPROCESSING : - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &pparams, &data->device); - if (FAILED(result)) { - D3D_DestroyRenderer(renderer); - D3D_SetError("CreateDevice()", result); - return NULL; - } - data->beginScene = SDL_TRUE; - - /* Get presentation parameters to fill info */ - result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain); - if (FAILED(result)) { - D3D_DestroyRenderer(renderer); - D3D_SetError("GetSwapChain()", result); - return NULL; - } - result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams); - if (FAILED(result)) { - IDirect3DSwapChain9_Release(chain); - D3D_DestroyRenderer(renderer); - D3D_SetError("GetPresentParameters()", result); - return NULL; - } - IDirect3DSwapChain9_Release(chain); - if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) { - renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; - } - data->pparams = pparams; - - IDirect3DDevice9_GetDeviceCaps(data->device, &caps); - renderer->info.max_texture_width = caps.MaxTextureWidth; - renderer->info.max_texture_height = caps.MaxTextureHeight; - - /* Set up parameters for rendering */ - IDirect3DDevice9_SetVertexShader(data->device, NULL); - IDirect3DDevice9_SetFVF(data->device, - D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_ZENABLE, D3DZB_FALSE); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE, - D3DCULL_NONE); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE); - /* Enable color modulation by diffuse color */ - IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLOROP, - D3DTOP_MODULATE); - IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG1, - D3DTA_TEXTURE); - IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG2, - D3DTA_DIFFUSE); - /* Enable alpha modulation by diffuse alpha */ - IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAOP, - D3DTOP_MODULATE); - IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG1, - D3DTA_TEXTURE); - IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG2, - D3DTA_DIFFUSE); - /* Disable second texture stage, since we're done */ - IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_COLOROP, - D3DTOP_DISABLE); - IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_ALPHAOP, - D3DTOP_DISABLE); - - return renderer; -} - -static int -D3D_Reset(SDL_Renderer * renderer) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - HRESULT result; - - result = IDirect3DDevice9_Reset(data->device, &data->pparams); - if (FAILED(result)) { - if (result == D3DERR_DEVICELOST) { - /* Don't worry about it, we'll reset later... */ - return 0; - } else { - D3D_SetError("Reset()", result); - return -1; - } - } - IDirect3DDevice9_SetVertexShader(data->device, NULL); - IDirect3DDevice9_SetFVF(data->device, - D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE, - D3DCULL_NONE); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE); - return 0; -} - -/* FIXME: This needs to be called... when? */ -#if 0 -static int -D3D_DisplayModeChanged(SDL_Renderer * renderer) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - SDL_Window *window = renderer->window; - SDL_VideoDisplay *display = window->display; - - data->pparams.BackBufferWidth = window->w; - data->pparams.BackBufferHeight = window->h; - if (window->flags & SDL_WINDOW_FULLSCREEN) { - data->pparams.BackBufferFormat = - PixelFormatToD3DFMT(window->fullscreen_mode.format); - } else { - data->pparams.BackBufferFormat = D3DFMT_UNKNOWN; - } - return D3D_Reset(renderer); -} -#endif - -static int -D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; - SDL_Window *window = renderer->window; - D3DFORMAT display_format = renderdata->pparams.BackBufferFormat; - D3D_TextureData *data; - D3DPOOL pool; - DWORD usage; - HRESULT result; - - data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_OutOfMemory(); - return -1; - } - - texture->driverdata = data; - -#ifdef USE_DYNAMIC_TEXTURE - if (texture->access == SDL_TEXTUREACCESS_STREAMING) { - pool = D3DPOOL_DEFAULT; - usage = D3DUSAGE_DYNAMIC; - } else -#endif - { - pool = D3DPOOL_MANAGED; - usage = 0; - } - - result = - IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, - texture->h, 1, usage, - PixelFormatToD3DFMT(texture->format), - pool, &data->texture, NULL); - if (FAILED(result)) { - D3D_SetError("CreateTexture()", result); - return -1; - } - - return 0; -} - -static int -D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, const void *pixels, int pitch) -{ - D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; - D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; - RECT d3drect; - D3DLOCKED_RECT locked; - const Uint8 *src; - Uint8 *dst; - int row, length; - HRESULT result; - -#ifdef USE_DYNAMIC_TEXTURE - if (texture->access == SDL_TEXTUREACCESS_STREAMING && - rect->x == 0 && rect->y == 0 && - rect->w == texture->w && rect->h == texture->h) { - result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, NULL, D3DLOCK_DISCARD); - } else -#endif - { - d3drect.left = rect->x; - d3drect.right = rect->x + rect->w; - d3drect.top = rect->y; - d3drect.bottom = rect->y + rect->h; - result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0); - } - - if (FAILED(result)) { - D3D_SetError("LockRect()", result); - return -1; - } - - src = pixels; - dst = locked.pBits; - length = rect->w * SDL_BYTESPERPIXEL(texture->format); - if (length == pitch && length == locked.Pitch) { - SDL_memcpy(dst, src, length*rect->h); - } else { - for (row = 0; row < rect->h; ++row) { - SDL_memcpy(dst, src, length); - src += pitch; - dst += locked.Pitch; - } - } - IDirect3DTexture9_UnlockRect(data->texture, 0); - - return 0; -} - -static int -D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, void **pixels, int *pitch) -{ - D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; - RECT d3drect; - D3DLOCKED_RECT locked; - HRESULT result; - - d3drect.left = rect->x; - d3drect.right = rect->x + rect->w; - d3drect.top = rect->y; - d3drect.bottom = rect->y + rect->h; - - result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0); - if (FAILED(result)) { - D3D_SetError("LockRect()", result); - return -1; - } - *pixels = locked.pBits; - *pitch = locked.Pitch; - return 0; -} - -static void -D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; - - IDirect3DTexture9_UnlockRect(data->texture, 0); -} - -static void -D3D_SetBlendMode(D3D_RenderData * data, int blendMode) -{ - switch (blendMode) { - case SDL_BLENDMODE_NONE: - IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, - FALSE); - break; - case SDL_BLENDMODE_BLEND: - IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, - TRUE); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, - D3DBLEND_SRCALPHA); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, - D3DBLEND_INVSRCALPHA); - break; - case SDL_BLENDMODE_ADD: - IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, - TRUE); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, - D3DBLEND_SRCALPHA); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, - D3DBLEND_ONE); - break; - case SDL_BLENDMODE_MOD: - IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, - TRUE); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, - D3DBLEND_ZERO); - IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, - D3DBLEND_SRCCOLOR); - break; - } -} - -static int -D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, - int count) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - DWORD color; - Vertex *vertices; - int i; - HRESULT result; - - if (data->beginScene) { - IDirect3DDevice9_BeginScene(data->device); - data->beginScene = SDL_FALSE; - } - - D3D_SetBlendMode(data, renderer->blendMode); - - result = - IDirect3DDevice9_SetTexture(data->device, 0, - (IDirect3DBaseTexture9 *) 0); - if (FAILED(result)) { - D3D_SetError("SetTexture()", result); - return -1; - } - - color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); - - vertices = SDL_stack_alloc(Vertex, count); - for (i = 0; i < count; ++i) { - vertices[i].x = (float) points[i].x; - vertices[i].y = (float) points[i].y; - vertices[i].z = 0.0f; - vertices[i].rhw = 1.0f; - vertices[i].color = color; - vertices[i].u = 0.0f; - vertices[i].v = 0.0f; - } - result = - IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count, - vertices, sizeof(*vertices)); - SDL_stack_free(vertices); - if (FAILED(result)) { - D3D_SetError("DrawPrimitiveUP()", result); - return -1; - } - return 0; -} - -static int -D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, - int count) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - DWORD color; - Vertex *vertices; - int i; - HRESULT result; - - if (data->beginScene) { - IDirect3DDevice9_BeginScene(data->device); - data->beginScene = SDL_FALSE; - } - - D3D_SetBlendMode(data, renderer->blendMode); - - result = - IDirect3DDevice9_SetTexture(data->device, 0, - (IDirect3DBaseTexture9 *) 0); - if (FAILED(result)) { - D3D_SetError("SetTexture()", result); - return -1; - } - - color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); - - vertices = SDL_stack_alloc(Vertex, count); - for (i = 0; i < count; ++i) { - vertices[i].x = (float) points[i].x; - vertices[i].y = (float) points[i].y; - vertices[i].z = 0.0f; - vertices[i].rhw = 1.0f; - vertices[i].color = color; - vertices[i].u = 0.0f; - vertices[i].v = 0.0f; - } - result = - IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1, - vertices, sizeof(*vertices)); - - /* DirectX 9 has the same line rasterization semantics as GDI, - so we need to close the endpoint of the line */ - if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) { - vertices[0].x = (float) points[count-1].x; - vertices[0].y = (float) points[count-1].y; - result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices)); - } - - SDL_stack_free(vertices); - if (FAILED(result)) { - D3D_SetError("DrawPrimitiveUP()", result); - return -1; - } - return 0; -} - -static int -D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, - int count) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - DWORD color; - int i; - float minx, miny, maxx, maxy; - Vertex vertices[4]; - HRESULT result; - - if (data->beginScene) { - IDirect3DDevice9_BeginScene(data->device); - data->beginScene = SDL_FALSE; - } - - D3D_SetBlendMode(data, renderer->blendMode); - - result = - IDirect3DDevice9_SetTexture(data->device, 0, - (IDirect3DBaseTexture9 *) 0); - if (FAILED(result)) { - D3D_SetError("SetTexture()", result); - return -1; - } - - color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); - - for (i = 0; i < count; ++i) { - const SDL_Rect *rect = rects[i]; - - minx = (float) rect->x; - miny = (float) rect->y; - maxx = (float) rect->x + rect->w; - maxy = (float) rect->y + rect->h; - - vertices[0].x = minx; - vertices[0].y = miny; - vertices[0].z = 0.0f; - vertices[0].rhw = 1.0f; - vertices[0].color = color; - vertices[0].u = 0.0f; - vertices[0].v = 0.0f; - - vertices[1].x = maxx; - vertices[1].y = miny; - vertices[1].z = 0.0f; - vertices[1].rhw = 1.0f; - vertices[1].color = color; - vertices[1].u = 0.0f; - vertices[1].v = 0.0f; - - vertices[2].x = maxx; - vertices[2].y = maxy; - vertices[2].z = 0.0f; - vertices[2].rhw = 1.0f; - vertices[2].color = color; - vertices[2].u = 0.0f; - vertices[2].v = 0.0f; - - vertices[3].x = minx; - vertices[3].y = maxy; - vertices[3].z = 0.0f; - vertices[3].rhw = 1.0f; - vertices[3].color = color; - vertices[3].u = 0.0f; - vertices[3].v = 0.0f; - - result = - IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, - 2, vertices, sizeof(*vertices)); - if (FAILED(result)) { - D3D_SetError("DrawPrimitiveUP()", result); - return -1; - } - } - return 0; -} - -static int -D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * srcrect, const SDL_Rect * dstrect) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; - LPDIRECT3DPIXELSHADER9 shader = NULL; - float minx, miny, maxx, maxy; - float minu, maxu, minv, maxv; - DWORD color; - Vertex vertices[4]; - HRESULT result; - - if (data->beginScene) { - IDirect3DDevice9_BeginScene(data->device); - data->beginScene = SDL_FALSE; - } - - minx = (float) dstrect->x - 0.5f; - miny = (float) dstrect->y - 0.5f; - maxx = (float) dstrect->x + dstrect->w - 0.5f; - maxy = (float) dstrect->y + dstrect->h - 0.5f; - - minu = (float) srcrect->x / texture->w; - maxu = (float) (srcrect->x + srcrect->w) / texture->w; - minv = (float) srcrect->y / texture->h; - maxv = (float) (srcrect->y + srcrect->h) / texture->h; - - color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b); - - vertices[0].x = minx; - vertices[0].y = miny; - vertices[0].z = 0.0f; - vertices[0].rhw = 1.0f; - vertices[0].color = color; - vertices[0].u = minu; - vertices[0].v = minv; - - vertices[1].x = maxx; - vertices[1].y = miny; - vertices[1].z = 0.0f; - vertices[1].rhw = 1.0f; - vertices[1].color = color; - vertices[1].u = maxu; - vertices[1].v = minv; - - vertices[2].x = maxx; - vertices[2].y = maxy; - vertices[2].z = 0.0f; - vertices[2].rhw = 1.0f; - vertices[2].color = color; - vertices[2].u = maxu; - vertices[2].v = maxv; - - vertices[3].x = minx; - vertices[3].y = maxy; - vertices[3].z = 0.0f; - vertices[3].rhw = 1.0f; - vertices[3].color = color; - vertices[3].u = minu; - vertices[3].v = maxv; - - D3D_SetBlendMode(data, texture->blendMode); - - IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER, - D3DTEXF_LINEAR); - IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER, - D3DTEXF_LINEAR); - - result = - IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *) - texturedata->texture); - if (FAILED(result)) { - D3D_SetError("SetTexture()", result); - return -1; - } - if (shader) { - result = IDirect3DDevice9_SetPixelShader(data->device, shader); - if (FAILED(result)) { - D3D_SetError("SetShader()", result); - return -1; - } - } - result = - IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, - vertices, sizeof(*vertices)); - if (FAILED(result)) { - D3D_SetError("DrawPrimitiveUP()", result); - return -1; - } - if (shader) { - result = IDirect3DDevice9_SetPixelShader(data->device, NULL); - if (FAILED(result)) { - D3D_SetError("SetShader()", result); - return -1; - } - } - return 0; -} - -static int -D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - Uint32 format, void * pixels, int pitch) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - D3DSURFACE_DESC desc; - LPDIRECT3DSURFACE9 backBuffer; - LPDIRECT3DSURFACE9 surface; - RECT d3drect; - D3DLOCKED_RECT locked; - HRESULT result; - - result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer); - if (FAILED(result)) { - D3D_SetError("GetBackBuffer()", result); - return -1; - } - - result = IDirect3DSurface9_GetDesc(backBuffer, &desc); - if (FAILED(result)) { - D3D_SetError("GetDesc()", result); - IDirect3DSurface9_Release(backBuffer); - return -1; - } - - result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL); - if (FAILED(result)) { - D3D_SetError("CreateOffscreenPlainSurface()", result); - IDirect3DSurface9_Release(backBuffer); - return -1; - } - - result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface); - if (FAILED(result)) { - D3D_SetError("GetRenderTargetData()", result); - IDirect3DSurface9_Release(surface); - IDirect3DSurface9_Release(backBuffer); - return -1; - } - - d3drect.left = rect->x; - d3drect.right = rect->x + rect->w; - d3drect.top = rect->y; - d3drect.bottom = rect->y + rect->h; - - result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY); - if (FAILED(result)) { - D3D_SetError("LockRect()", result); - IDirect3DSurface9_Release(surface); - IDirect3DSurface9_Release(backBuffer); - return -1; - } - - SDL_ConvertPixels(rect->w, rect->h, - D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch, - format, pixels, pitch); - - IDirect3DSurface9_UnlockRect(surface); - - IDirect3DSurface9_Release(surface); - IDirect3DSurface9_Release(backBuffer); - - return 0; -} - -static void -D3D_RenderPresent(SDL_Renderer * renderer) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - HRESULT result; - - if (!data->beginScene) { - IDirect3DDevice9_EndScene(data->device); - data->beginScene = SDL_TRUE; - } - - result = IDirect3DDevice9_TestCooperativeLevel(data->device); - if (result == D3DERR_DEVICELOST) { - /* We'll reset later */ - return; - } - if (result == D3DERR_DEVICENOTRESET) { - D3D_Reset(renderer); - } - result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL); - if (FAILED(result)) { - D3D_SetError("Present()", result); - } -} - -static void -D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; - - if (!data) { - return; - } - if (data->texture) { - IDirect3DTexture9_Release(data->texture); - } - SDL_free(data); - texture->driverdata = NULL; -} - -static void -D3D_DestroyRenderer(SDL_Renderer * renderer) -{ - D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; - - if (data) { - if (data->device) { - IDirect3DDevice9_Release(data->device); - } - if (data->d3d) { - IDirect3D9_Release(data->d3d); - SDL_UnloadObject(data->d3dDLL); - } - SDL_free(data); - } - SDL_free(renderer); -} - -#endif /* SDL_VIDEO_RENDER_D3D */ - -/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/direct3d/SDL_render_d3d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/render/direct3d/SDL_render_d3d.c Sat Feb 05 12:01:11 2011 -0800 @@ -0,0 +1,1048 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_RENDER_D3D + +#include "../../core/windows/SDL_windows.h" + +#include "SDL_loadso.h" +#include "SDL_syswm.h" +#include "../SDL_sysrender.h" + +#if SDL_VIDEO_RENDER_D3D +#define D3D_DEBUG_INFO +#include +#endif + +#ifdef ASSEMBLE_SHADER +/////////////////////////////////////////////////////////////////////////// +// ID3DXBuffer: +// ------------ +// The buffer object is used by D3DX to return arbitrary size data. +// +// GetBufferPointer - +// Returns a pointer to the beginning of the buffer. +// +// GetBufferSize - +// Returns the size of the buffer, in bytes. +/////////////////////////////////////////////////////////////////////////// + +typedef interface ID3DXBuffer ID3DXBuffer; +typedef interface ID3DXBuffer *LPD3DXBUFFER; + +// {8BA5FB08-5195-40e2-AC58-0D989C3A0102} +DEFINE_GUID(IID_ID3DXBuffer, +0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2); + +#undef INTERFACE +#define INTERFACE ID3DXBuffer + +typedef interface ID3DXBuffer { + const struct ID3DXBufferVtbl FAR* lpVtbl; +} ID3DXBuffer; +typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl; +const struct ID3DXBufferVtbl +{ + // IUnknown + STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // ID3DXBuffer + STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE; + STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE; +}; + +HRESULT WINAPI + D3DXAssembleShader( + LPCSTR pSrcData, + UINT SrcDataLen, + CONST LPVOID* pDefines, + LPVOID pInclude, + DWORD Flags, + LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs); + +#endif /* ASSEMBLE_SHADER */ + + +/* Direct3D renderer implementation */ + +static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags); +static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, + int pitch); +static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch); +static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int D3D_RenderDrawPoints(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int D3D_RenderDrawLines(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int D3D_RenderFillRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, int count); +static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect); +static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, void * pixels, int pitch); +static void D3D_RenderPresent(SDL_Renderer * renderer); +static void D3D_DestroyTexture(SDL_Renderer * renderer, + SDL_Texture * texture); +static void D3D_DestroyRenderer(SDL_Renderer * renderer); + + +SDL_RenderDriver D3D_RenderDriver = { + D3D_CreateRenderer, + { + "direct3d", + (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), + 1, + {SDL_PIXELFORMAT_ARGB8888}, + 0, + 0} +}; + +typedef struct +{ + void* d3dDLL; + IDirect3D9 *d3d; + IDirect3DDevice9 *device; + UINT adapter; + D3DPRESENT_PARAMETERS pparams; + SDL_bool beginScene; +} D3D_RenderData; + +typedef struct +{ + IDirect3DTexture9 *texture; +} D3D_TextureData; + +typedef struct +{ + float x, y, z; + float rhw; + DWORD color; + float u, v; +} Vertex; + +static void +D3D_SetError(const char *prefix, HRESULT result) +{ + const char *error; + + switch (result) { + case D3DERR_WRONGTEXTUREFORMAT: + error = "WRONGTEXTUREFORMAT"; + break; + case D3DERR_UNSUPPORTEDCOLOROPERATION: + error = "UNSUPPORTEDCOLOROPERATION"; + break; + case D3DERR_UNSUPPORTEDCOLORARG: + error = "UNSUPPORTEDCOLORARG"; + break; + case D3DERR_UNSUPPORTEDALPHAOPERATION: + error = "UNSUPPORTEDALPHAOPERATION"; + break; + case D3DERR_UNSUPPORTEDALPHAARG: + error = "UNSUPPORTEDALPHAARG"; + break; + case D3DERR_TOOMANYOPERATIONS: + error = "TOOMANYOPERATIONS"; + break; + case D3DERR_CONFLICTINGTEXTUREFILTER: + error = "CONFLICTINGTEXTUREFILTER"; + break; + case D3DERR_UNSUPPORTEDFACTORVALUE: + error = "UNSUPPORTEDFACTORVALUE"; + break; + case D3DERR_CONFLICTINGRENDERSTATE: + error = "CONFLICTINGRENDERSTATE"; + break; + case D3DERR_UNSUPPORTEDTEXTUREFILTER: + error = "UNSUPPORTEDTEXTUREFILTER"; + break; + case D3DERR_CONFLICTINGTEXTUREPALETTE: + error = "CONFLICTINGTEXTUREPALETTE"; + break; + case D3DERR_DRIVERINTERNALERROR: + error = "DRIVERINTERNALERROR"; + break; + case D3DERR_NOTFOUND: + error = "NOTFOUND"; + break; + case D3DERR_MOREDATA: + error = "MOREDATA"; + break; + case D3DERR_DEVICELOST: + error = "DEVICELOST"; + break; + case D3DERR_DEVICENOTRESET: + error = "DEVICENOTRESET"; + break; + case D3DERR_NOTAVAILABLE: + error = "NOTAVAILABLE"; + break; + case D3DERR_OUTOFVIDEOMEMORY: + error = "OUTOFVIDEOMEMORY"; + break; + case D3DERR_INVALIDDEVICE: + error = "INVALIDDEVICE"; + break; + case D3DERR_INVALIDCALL: + error = "INVALIDCALL"; + break; + case D3DERR_DRIVERINVALIDCALL: + error = "DRIVERINVALIDCALL"; + break; + case D3DERR_WASSTILLDRAWING: + error = "WASSTILLDRAWING"; + break; + default: + error = "UNKNOWN"; + break; + } + SDL_SetError("%s: %s", prefix, error); +} + +static D3DFORMAT +PixelFormatToD3DFMT(Uint32 format) +{ + switch (format) { + case SDL_PIXELFORMAT_RGB565: + return D3DFMT_R5G6B5; + case SDL_PIXELFORMAT_RGB888: + return D3DFMT_X8R8G8B8; + case SDL_PIXELFORMAT_ARGB8888: + return D3DFMT_A8R8G8B8; + default: + return D3DFMT_UNKNOWN; + } +} + +static Uint32 +D3DFMTToPixelFormat(D3DFORMAT format) +{ + switch (format) { + case D3DFMT_R5G6B5: + return SDL_PIXELFORMAT_RGB565; + case D3DFMT_X8R8G8B8: + return SDL_PIXELFORMAT_RGB888; + case D3DFMT_A8R8G8B8: + return SDL_PIXELFORMAT_ARGB8888; + default: + return SDL_PIXELFORMAT_UNKNOWN; + } +} + +SDL_Renderer * +D3D_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + SDL_Renderer *renderer; + D3D_RenderData *data; + SDL_SysWMinfo windowinfo; + HRESULT result; + D3DPRESENT_PARAMETERS pparams; + IDirect3DSwapChain9 *chain; + D3DCAPS9 caps; + Uint32 window_flags; + int w, h; + SDL_DisplayMode fullscreen_mode; + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + + data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + SDL_free(renderer); + SDL_OutOfMemory(); + return NULL; + } + + data->d3dDLL = SDL_LoadObject("D3D9.DLL"); + if (data->d3dDLL) { + IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion); + + D3DCreate = + (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(data->d3dDLL, + "Direct3DCreate9"); + if (D3DCreate) { + data->d3d = D3DCreate(D3D_SDK_VERSION); + } + if (!data->d3d) { + SDL_UnloadObject(data->d3dDLL); + data->d3dDLL = NULL; + } + } + if (!data->d3d) { + SDL_free(renderer); + SDL_free(data); + SDL_SetError("Unable to create Direct3D interface"); + return NULL; + } + + renderer->CreateTexture = D3D_CreateTexture; + renderer->UpdateTexture = D3D_UpdateTexture; + renderer->LockTexture = D3D_LockTexture; + renderer->UnlockTexture = D3D_UnlockTexture; + renderer->RenderDrawPoints = D3D_RenderDrawPoints; + renderer->RenderDrawLines = D3D_RenderDrawLines; + renderer->RenderFillRects = D3D_RenderFillRects; + renderer->RenderCopy = D3D_RenderCopy; + renderer->RenderReadPixels = D3D_RenderReadPixels; + renderer->RenderPresent = D3D_RenderPresent; + renderer->DestroyTexture = D3D_DestroyTexture; + renderer->DestroyRenderer = D3D_DestroyRenderer; + renderer->info = D3D_RenderDriver.info; + renderer->driverdata = data; + + renderer->info.flags = SDL_RENDERER_ACCELERATED; + + SDL_VERSION(&windowinfo.version); + SDL_GetWindowWMInfo(window, &windowinfo); + + window_flags = SDL_GetWindowFlags(window); + SDL_GetWindowSize(window, &w, &h); + SDL_GetWindowDisplayMode(window, &fullscreen_mode); + + SDL_zero(pparams); + pparams.hDeviceWindow = windowinfo.info.win.window; + pparams.BackBufferWidth = w; + pparams.BackBufferHeight = h; + if (window_flags & SDL_WINDOW_FULLSCREEN) { + pparams.BackBufferFormat = + PixelFormatToD3DFMT(fullscreen_mode.format); + } else { + pparams.BackBufferFormat = D3DFMT_UNKNOWN; + } + pparams.BackBufferCount = 1; + pparams.SwapEffect = D3DSWAPEFFECT_DISCARD; + + if (window_flags & SDL_WINDOW_FULLSCREEN) { + pparams.Windowed = FALSE; + pparams.FullScreen_RefreshRateInHz = + fullscreen_mode.refresh_rate; + } else { + pparams.Windowed = TRUE; + pparams.FullScreen_RefreshRateInHz = 0; + } + if (flags & SDL_RENDERER_PRESENTVSYNC) { + pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + } else { + pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } + + /* FIXME: Which adapter? */ + data->adapter = D3DADAPTER_DEFAULT; + IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps); + + result = IDirect3D9_CreateDevice(data->d3d, data->adapter, + D3DDEVTYPE_HAL, + pparams.hDeviceWindow, + (caps. + DevCaps & + D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? + D3DCREATE_HARDWARE_VERTEXPROCESSING : + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &pparams, &data->device); + if (FAILED(result)) { + D3D_DestroyRenderer(renderer); + D3D_SetError("CreateDevice()", result); + return NULL; + } + data->beginScene = SDL_TRUE; + + /* Get presentation parameters to fill info */ + result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain); + if (FAILED(result)) { + D3D_DestroyRenderer(renderer); + D3D_SetError("GetSwapChain()", result); + return NULL; + } + result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams); + if (FAILED(result)) { + IDirect3DSwapChain9_Release(chain); + D3D_DestroyRenderer(renderer); + D3D_SetError("GetPresentParameters()", result); + return NULL; + } + IDirect3DSwapChain9_Release(chain); + if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) { + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } + data->pparams = pparams; + + IDirect3DDevice9_GetDeviceCaps(data->device, &caps); + renderer->info.max_texture_width = caps.MaxTextureWidth; + renderer->info.max_texture_height = caps.MaxTextureHeight; + + /* Set up parameters for rendering */ + IDirect3DDevice9_SetVertexShader(data->device, NULL); + IDirect3DDevice9_SetFVF(data->device, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_ZENABLE, D3DZB_FALSE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE, + D3DCULL_NONE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE); + /* Enable color modulation by diffuse color */ + IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLOROP, + D3DTOP_MODULATE); + IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG1, + D3DTA_TEXTURE); + IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG2, + D3DTA_DIFFUSE); + /* Enable alpha modulation by diffuse alpha */ + IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAOP, + D3DTOP_MODULATE); + IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG1, + D3DTA_TEXTURE); + IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG2, + D3DTA_DIFFUSE); + /* Disable second texture stage, since we're done */ + IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_COLOROP, + D3DTOP_DISABLE); + IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_ALPHAOP, + D3DTOP_DISABLE); + + return renderer; +} + +static int +D3D_Reset(SDL_Renderer * renderer) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + HRESULT result; + + result = IDirect3DDevice9_Reset(data->device, &data->pparams); + if (FAILED(result)) { + if (result == D3DERR_DEVICELOST) { + /* Don't worry about it, we'll reset later... */ + return 0; + } else { + D3D_SetError("Reset()", result); + return -1; + } + } + IDirect3DDevice9_SetVertexShader(data->device, NULL); + IDirect3DDevice9_SetFVF(data->device, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE, + D3DCULL_NONE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE); + return 0; +} + +/* FIXME: This needs to be called... when? */ +#if 0 +static int +D3D_DisplayModeChanged(SDL_Renderer * renderer) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + SDL_VideoDisplay *display = window->display; + + data->pparams.BackBufferWidth = window->w; + data->pparams.BackBufferHeight = window->h; + if (window->flags & SDL_WINDOW_FULLSCREEN) { + data->pparams.BackBufferFormat = + PixelFormatToD3DFMT(window->fullscreen_mode.format); + } else { + data->pparams.BackBufferFormat = D3DFMT_UNKNOWN; + } + return D3D_Reset(renderer); +} +#endif + +static int +D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + D3DFORMAT display_format = renderdata->pparams.BackBufferFormat; + D3D_TextureData *data; + D3DPOOL pool; + DWORD usage; + HRESULT result; + + data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + SDL_OutOfMemory(); + return -1; + } + + texture->driverdata = data; + +#ifdef USE_DYNAMIC_TEXTURE + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + pool = D3DPOOL_DEFAULT; + usage = D3DUSAGE_DYNAMIC; + } else +#endif + { + pool = D3DPOOL_MANAGED; + usage = 0; + } + + result = + IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, + texture->h, 1, usage, + PixelFormatToD3DFMT(texture->format), + pool, &data->texture, NULL); + if (FAILED(result)) { + D3D_SetError("CreateTexture()", result); + return -1; + } + + return 0; +} + +static int +D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, int pitch) +{ + D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; + D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; + RECT d3drect; + D3DLOCKED_RECT locked; + const Uint8 *src; + Uint8 *dst; + int row, length; + HRESULT result; + +#ifdef USE_DYNAMIC_TEXTURE + if (texture->access == SDL_TEXTUREACCESS_STREAMING && + rect->x == 0 && rect->y == 0 && + rect->w == texture->w && rect->h == texture->h) { + result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, NULL, D3DLOCK_DISCARD); + } else +#endif + { + d3drect.left = rect->x; + d3drect.right = rect->x + rect->w; + d3drect.top = rect->y; + d3drect.bottom = rect->y + rect->h; + result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0); + } + + if (FAILED(result)) { + D3D_SetError("LockRect()", result); + return -1; + } + + src = pixels; + dst = locked.pBits; + length = rect->w * SDL_BYTESPERPIXEL(texture->format); + if (length == pitch && length == locked.Pitch) { + SDL_memcpy(dst, src, length*rect->h); + } else { + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += locked.Pitch; + } + } + IDirect3DTexture9_UnlockRect(data->texture, 0); + + return 0; +} + +static int +D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch) +{ + D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; + RECT d3drect; + D3DLOCKED_RECT locked; + HRESULT result; + + d3drect.left = rect->x; + d3drect.right = rect->x + rect->w; + d3drect.top = rect->y; + d3drect.bottom = rect->y + rect->h; + + result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0); + if (FAILED(result)) { + D3D_SetError("LockRect()", result); + return -1; + } + *pixels = locked.pBits; + *pitch = locked.Pitch; + return 0; +} + +static void +D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; + + IDirect3DTexture9_UnlockRect(data->texture, 0); +} + +static void +D3D_SetBlendMode(D3D_RenderData * data, int blendMode) +{ + switch (blendMode) { + case SDL_BLENDMODE_NONE: + IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, + FALSE); + break; + case SDL_BLENDMODE_BLEND: + IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, + TRUE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, + D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, + D3DBLEND_INVSRCALPHA); + break; + case SDL_BLENDMODE_ADD: + IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, + TRUE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, + D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, + D3DBLEND_ONE); + break; + case SDL_BLENDMODE_MOD: + IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, + TRUE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, + D3DBLEND_ZERO); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, + D3DBLEND_SRCCOLOR); + break; + } +} + +static int +D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, + int count) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + DWORD color; + Vertex *vertices; + int i; + HRESULT result; + + if (data->beginScene) { + IDirect3DDevice9_BeginScene(data->device); + data->beginScene = SDL_FALSE; + } + + D3D_SetBlendMode(data, renderer->blendMode); + + result = + IDirect3DDevice9_SetTexture(data->device, 0, + (IDirect3DBaseTexture9 *) 0); + if (FAILED(result)) { + D3D_SetError("SetTexture()", result); + return -1; + } + + color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); + + vertices = SDL_stack_alloc(Vertex, count); + for (i = 0; i < count; ++i) { + vertices[i].x = (float) points[i].x; + vertices[i].y = (float) points[i].y; + vertices[i].z = 0.0f; + vertices[i].rhw = 1.0f; + vertices[i].color = color; + vertices[i].u = 0.0f; + vertices[i].v = 0.0f; + } + result = + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count, + vertices, sizeof(*vertices)); + SDL_stack_free(vertices); + if (FAILED(result)) { + D3D_SetError("DrawPrimitiveUP()", result); + return -1; + } + return 0; +} + +static int +D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, + int count) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + DWORD color; + Vertex *vertices; + int i; + HRESULT result; + + if (data->beginScene) { + IDirect3DDevice9_BeginScene(data->device); + data->beginScene = SDL_FALSE; + } + + D3D_SetBlendMode(data, renderer->blendMode); + + result = + IDirect3DDevice9_SetTexture(data->device, 0, + (IDirect3DBaseTexture9 *) 0); + if (FAILED(result)) { + D3D_SetError("SetTexture()", result); + return -1; + } + + color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); + + vertices = SDL_stack_alloc(Vertex, count); + for (i = 0; i < count; ++i) { + vertices[i].x = (float) points[i].x; + vertices[i].y = (float) points[i].y; + vertices[i].z = 0.0f; + vertices[i].rhw = 1.0f; + vertices[i].color = color; + vertices[i].u = 0.0f; + vertices[i].v = 0.0f; + } + result = + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1, + vertices, sizeof(*vertices)); + + /* DirectX 9 has the same line rasterization semantics as GDI, + so we need to close the endpoint of the line */ + if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) { + vertices[0].x = (float) points[count-1].x; + vertices[0].y = (float) points[count-1].y; + result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices)); + } + + SDL_stack_free(vertices); + if (FAILED(result)) { + D3D_SetError("DrawPrimitiveUP()", result); + return -1; + } + return 0; +} + +static int +D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, + int count) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + DWORD color; + int i; + float minx, miny, maxx, maxy; + Vertex vertices[4]; + HRESULT result; + + if (data->beginScene) { + IDirect3DDevice9_BeginScene(data->device); + data->beginScene = SDL_FALSE; + } + + D3D_SetBlendMode(data, renderer->blendMode); + + result = + IDirect3DDevice9_SetTexture(data->device, 0, + (IDirect3DBaseTexture9 *) 0); + if (FAILED(result)) { + D3D_SetError("SetTexture()", result); + return -1; + } + + color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); + + for (i = 0; i < count; ++i) { + const SDL_Rect *rect = rects[i]; + + minx = (float) rect->x; + miny = (float) rect->y; + maxx = (float) rect->x + rect->w; + maxy = (float) rect->y + rect->h; + + vertices[0].x = minx; + vertices[0].y = miny; + vertices[0].z = 0.0f; + vertices[0].rhw = 1.0f; + vertices[0].color = color; + vertices[0].u = 0.0f; + vertices[0].v = 0.0f; + + vertices[1].x = maxx; + vertices[1].y = miny; + vertices[1].z = 0.0f; + vertices[1].rhw = 1.0f; + vertices[1].color = color; + vertices[1].u = 0.0f; + vertices[1].v = 0.0f; + + vertices[2].x = maxx; + vertices[2].y = maxy; + vertices[2].z = 0.0f; + vertices[2].rhw = 1.0f; + vertices[2].color = color; + vertices[2].u = 0.0f; + vertices[2].v = 0.0f; + + vertices[3].x = minx; + vertices[3].y = maxy; + vertices[3].z = 0.0f; + vertices[3].rhw = 1.0f; + vertices[3].color = color; + vertices[3].u = 0.0f; + vertices[3].v = 0.0f; + + result = + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, + 2, vertices, sizeof(*vertices)); + if (FAILED(result)) { + D3D_SetError("DrawPrimitiveUP()", result); + return -1; + } + } + return 0; +} + +static int +D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; + LPDIRECT3DPIXELSHADER9 shader = NULL; + float minx, miny, maxx, maxy; + float minu, maxu, minv, maxv; + DWORD color; + Vertex vertices[4]; + HRESULT result; + + if (data->beginScene) { + IDirect3DDevice9_BeginScene(data->device); + data->beginScene = SDL_FALSE; + } + + minx = (float) dstrect->x - 0.5f; + miny = (float) dstrect->y - 0.5f; + maxx = (float) dstrect->x + dstrect->w - 0.5f; + maxy = (float) dstrect->y + dstrect->h - 0.5f; + + minu = (float) srcrect->x / texture->w; + maxu = (float) (srcrect->x + srcrect->w) / texture->w; + minv = (float) srcrect->y / texture->h; + maxv = (float) (srcrect->y + srcrect->h) / texture->h; + + color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b); + + vertices[0].x = minx; + vertices[0].y = miny; + vertices[0].z = 0.0f; + vertices[0].rhw = 1.0f; + vertices[0].color = color; + vertices[0].u = minu; + vertices[0].v = minv; + + vertices[1].x = maxx; + vertices[1].y = miny; + vertices[1].z = 0.0f; + vertices[1].rhw = 1.0f; + vertices[1].color = color; + vertices[1].u = maxu; + vertices[1].v = minv; + + vertices[2].x = maxx; + vertices[2].y = maxy; + vertices[2].z = 0.0f; + vertices[2].rhw = 1.0f; + vertices[2].color = color; + vertices[2].u = maxu; + vertices[2].v = maxv; + + vertices[3].x = minx; + vertices[3].y = maxy; + vertices[3].z = 0.0f; + vertices[3].rhw = 1.0f; + vertices[3].color = color; + vertices[3].u = minu; + vertices[3].v = maxv; + + D3D_SetBlendMode(data, texture->blendMode); + + IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER, + D3DTEXF_LINEAR); + IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER, + D3DTEXF_LINEAR); + + result = + IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *) + texturedata->texture); + if (FAILED(result)) { + D3D_SetError("SetTexture()", result); + return -1; + } + if (shader) { + result = IDirect3DDevice9_SetPixelShader(data->device, shader); + if (FAILED(result)) { + D3D_SetError("SetShader()", result); + return -1; + } + } + result = + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, + vertices, sizeof(*vertices)); + if (FAILED(result)) { + D3D_SetError("DrawPrimitiveUP()", result); + return -1; + } + if (shader) { + result = IDirect3DDevice9_SetPixelShader(data->device, NULL); + if (FAILED(result)) { + D3D_SetError("SetShader()", result); + return -1; + } + } + return 0; +} + +static int +D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, void * pixels, int pitch) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + D3DSURFACE_DESC desc; + LPDIRECT3DSURFACE9 backBuffer; + LPDIRECT3DSURFACE9 surface; + RECT d3drect; + D3DLOCKED_RECT locked; + HRESULT result; + + result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer); + if (FAILED(result)) { + D3D_SetError("GetBackBuffer()", result); + return -1; + } + + result = IDirect3DSurface9_GetDesc(backBuffer, &desc); + if (FAILED(result)) { + D3D_SetError("GetDesc()", result); + IDirect3DSurface9_Release(backBuffer); + return -1; + } + + result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL); + if (FAILED(result)) { + D3D_SetError("CreateOffscreenPlainSurface()", result); + IDirect3DSurface9_Release(backBuffer); + return -1; + } + + result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface); + if (FAILED(result)) { + D3D_SetError("GetRenderTargetData()", result); + IDirect3DSurface9_Release(surface); + IDirect3DSurface9_Release(backBuffer); + return -1; + } + + d3drect.left = rect->x; + d3drect.right = rect->x + rect->w; + d3drect.top = rect->y; + d3drect.bottom = rect->y + rect->h; + + result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY); + if (FAILED(result)) { + D3D_SetError("LockRect()", result); + IDirect3DSurface9_Release(surface); + IDirect3DSurface9_Release(backBuffer); + return -1; + } + + SDL_ConvertPixels(rect->w, rect->h, + D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch, + format, pixels, pitch); + + IDirect3DSurface9_UnlockRect(surface); + + IDirect3DSurface9_Release(surface); + IDirect3DSurface9_Release(backBuffer); + + return 0; +} + +static void +D3D_RenderPresent(SDL_Renderer * renderer) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + HRESULT result; + + if (!data->beginScene) { + IDirect3DDevice9_EndScene(data->device); + data->beginScene = SDL_TRUE; + } + + result = IDirect3DDevice9_TestCooperativeLevel(data->device); + if (result == D3DERR_DEVICELOST) { + /* We'll reset later */ + return; + } + if (result == D3DERR_DEVICENOTRESET) { + D3D_Reset(renderer); + } + result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL); + if (FAILED(result)) { + D3D_SetError("Present()", result); + } +} + +static void +D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; + + if (!data) { + return; + } + if (data->texture) { + IDirect3DTexture9_Release(data->texture); + } + SDL_free(data); + texture->driverdata = NULL; +} + +static void +D3D_DestroyRenderer(SDL_Renderer * renderer) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + + if (data) { + if (data->device) { + IDirect3DDevice9_Release(data->device); + } + if (data->d3d) { + IDirect3D9_Release(data->d3d); + SDL_UnloadObject(data->d3dDLL); + } + SDL_free(data); + } + SDL_free(renderer); +} + +#endif /* SDL_VIDEO_RENDER_D3D */ + +/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/opengl/SDL_render_gl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/render/opengl/SDL_render_gl.c Sat Feb 05 12:01:11 2011 -0800 @@ -0,0 +1,826 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_RENDER_OGL + +#include "SDL_opengl.h" +#include "../SDL_sysrender.h" + +#ifdef __MACOSX__ +#include +#endif + + +/* OpenGL renderer implementation */ + +/* Details on optimizing the texture path on Mac OS X: + http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html +*/ + +/* Used to re-create the window with OpenGL capability */ +extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); + +static const float inv255f = 1.0f / 255.0f; + +static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags); +static void GL_WindowEvent(SDL_Renderer * renderer, + const SDL_WindowEvent *event); +static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, + int pitch); +static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch); +static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int GL_RenderClear(SDL_Renderer * renderer); +static int GL_RenderDrawPoints(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int GL_RenderDrawLines(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int GL_RenderFillRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, int count); +static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect); +static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 pixel_format, void * pixels, int pitch); +static void GL_RenderPresent(SDL_Renderer * renderer); +static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static void GL_DestroyRenderer(SDL_Renderer * renderer); + + +SDL_RenderDriver GL_RenderDriver = { + GL_CreateRenderer, + { + "opengl", + (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), + 1, + {SDL_PIXELFORMAT_ARGB8888}, + 0, + 0} +}; + +typedef struct +{ + SDL_GLContext context; + SDL_bool updateSize; + SDL_bool GL_ARB_texture_rectangle_supported; + int blendMode; + + /* OpenGL functions */ +#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; +#include "../../video/SDL_glfuncs.h" +#undef SDL_PROC + + void (*glTextureRangeAPPLE) (GLenum target, GLsizei length, + const GLvoid * pointer); +} GL_RenderData; + +typedef struct +{ + GLuint texture; + GLenum type; + GLfloat texw; + GLfloat texh; + GLenum format; + GLenum formattype; + void *pixels; + int pitch; +} GL_TextureData; + + +static void +GL_SetError(const char *prefix, GLenum result) +{ + const char *error; + + switch (result) { + case GL_NO_ERROR: + error = "GL_NO_ERROR"; + break; + case GL_INVALID_ENUM: + error = "GL_INVALID_ENUM"; + break; + case GL_INVALID_VALUE: + error = "GL_INVALID_VALUE"; + break; + case GL_INVALID_OPERATION: + error = "GL_INVALID_OPERATION"; + break; + case GL_STACK_OVERFLOW: + error = "GL_STACK_OVERFLOW"; + break; + case GL_STACK_UNDERFLOW: + error = "GL_STACK_UNDERFLOW"; + break; + case GL_OUT_OF_MEMORY: + error = "GL_OUT_OF_MEMORY"; + break; + case GL_TABLE_TOO_LARGE: + error = "GL_TABLE_TOO_LARGE"; + break; + default: + error = "UNKNOWN"; + break; + } + SDL_SetError("%s: %s", prefix, error); +} + +static int +GL_LoadFunctions(GL_RenderData * data) +{ +#ifdef __SDL_NOGETPROCADDR__ +#define SDL_PROC(ret,func,params) data->func=func; +#else +#define SDL_PROC(ret,func,params) \ + do { \ + data->func = SDL_GL_GetProcAddress(#func); \ + if ( ! data->func ) { \ + SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \ + return -1; \ + } \ + } while ( 0 ); +#endif /* __SDL_NOGETPROCADDR__ */ + +#include "../../video/SDL_glfuncs.h" +#undef SDL_PROC + return 0; +} + +SDL_Renderer * +GL_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + SDL_Renderer *renderer; + GL_RenderData *data; + GLint value; + Uint32 window_flags; + + window_flags = SDL_GetWindowFlags(window); + if (!(window_flags & SDL_WINDOW_OPENGL)) { + if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) { + return NULL; + } + } + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + + data = (GL_RenderData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + GL_DestroyRenderer(renderer); + SDL_OutOfMemory(); + return NULL; + } + + renderer->WindowEvent = GL_WindowEvent; + renderer->CreateTexture = GL_CreateTexture; + renderer->UpdateTexture = GL_UpdateTexture; + renderer->LockTexture = GL_LockTexture; + renderer->UnlockTexture = GL_UnlockTexture; + renderer->RenderClear = GL_RenderClear; + renderer->RenderDrawPoints = GL_RenderDrawPoints; + renderer->RenderDrawLines = GL_RenderDrawLines; + renderer->RenderFillRects = GL_RenderFillRects; + renderer->RenderCopy = GL_RenderCopy; + renderer->RenderReadPixels = GL_RenderReadPixels; + renderer->RenderPresent = GL_RenderPresent; + renderer->DestroyTexture = GL_DestroyTexture; + renderer->DestroyRenderer = GL_DestroyRenderer; + renderer->info = GL_RenderDriver.info; + renderer->driverdata = data; + + renderer->info.flags = SDL_RENDERER_ACCELERATED; + + if (GL_LoadFunctions(data) < 0) { + GL_DestroyRenderer(renderer); + return NULL; + } + + data->context = SDL_GL_CreateContext(window); + if (!data->context) { + GL_DestroyRenderer(renderer); + return NULL; + } + if (SDL_GL_MakeCurrent(window, data->context) < 0) { + GL_DestroyRenderer(renderer); + return NULL; + } +#ifdef __MACOSX__ + /* Enable multi-threaded rendering */ + /* Disabled until Ryan finishes his VBO/PBO code... + CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine); + */ +#endif + + if (flags & SDL_RENDERER_PRESENTVSYNC) { + SDL_GL_SetSwapInterval(1); + } else { + SDL_GL_SetSwapInterval(0); + } + if (SDL_GL_GetSwapInterval() > 0) { + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } + + data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); + renderer->info.max_texture_width = value; + data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); + renderer->info.max_texture_height = value; + + if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") + || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) { + data->GL_ARB_texture_rectangle_supported = SDL_TRUE; + } + if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) { + data->glTextureRangeAPPLE = + (void (*)(GLenum, GLsizei, const GLvoid *)) + SDL_GL_GetProcAddress("glTextureRangeAPPLE"); + } + + /* Set up parameters for rendering */ + data->blendMode = -1; + data->glDisable(GL_DEPTH_TEST); + data->glDisable(GL_CULL_FACE); + /* This ended up causing video discrepancies between OpenGL and Direct3D */ + /*data->glEnable(GL_LINE_SMOOTH);*/ + if (data->GL_ARB_texture_rectangle_supported) { + data->glEnable(GL_TEXTURE_RECTANGLE_ARB); + } else { + data->glEnable(GL_TEXTURE_2D); + } + data->updateSize = SDL_TRUE; + + return renderer; +} + +static SDL_GLContext SDL_CurrentContext = NULL; + +static int +GL_ActivateRenderer(SDL_Renderer * renderer) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + + if (SDL_CurrentContext != data->context) { + if (SDL_GL_MakeCurrent(window, data->context) < 0) { + return -1; + } + SDL_CurrentContext = data->context; + } + if (data->updateSize) { + int w, h; + + SDL_GetWindowSize(window, &w, &h); + data->glMatrixMode(GL_PROJECTION); + data->glLoadIdentity(); + data->glMatrixMode(GL_MODELVIEW); + data->glLoadIdentity(); + data->glViewport(0, 0, w, h); + data->glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 1.0); + data->updateSize = SDL_FALSE; + } + return 0; +} + +static void +GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + + if (event->event == SDL_WINDOWEVENT_RESIZED) { + /* Rebind the context to the window area and update matrices */ + SDL_CurrentContext = NULL; + data->updateSize = SDL_TRUE; + } +} + +static __inline__ int +power_of_2(int input) +{ + int value = 1; + + while (value < input) { + value <<= 1; + } + return value; +} + +static __inline__ SDL_bool +convert_format(GL_RenderData *renderdata, Uint32 pixel_format, + GLint* internalFormat, GLenum* format, GLenum* type) +{ + switch (pixel_format) { + case SDL_PIXELFORMAT_RGB888: + case SDL_PIXELFORMAT_ARGB8888: + *internalFormat = GL_RGBA8; + *format = GL_BGRA; + *type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + default: + return SDL_FALSE; + } + return SDL_TRUE; +} + +static int +GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; + GL_TextureData *data; + GLint internalFormat; + GLenum format, type; + int texture_w, texture_h; + GLenum result; + + GL_ActivateRenderer(renderer); + + if (!convert_format(renderdata, texture->format, &internalFormat, + &format, &type)) { + SDL_SetError("Texture format %s not supported by OpenGL", + SDL_GetPixelFormatName(texture->format)); + return -1; + } + + data = (GL_TextureData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + SDL_OutOfMemory(); + return -1; + } + + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); + data->pixels = SDL_malloc(texture->h * data->pitch); + if (!data->pixels) { + SDL_OutOfMemory(); + SDL_free(data); + return -1; + } + } + + texture->driverdata = data; + + renderdata->glGetError(); + renderdata->glGenTextures(1, &data->texture); + if (renderdata->GL_ARB_texture_rectangle_supported) { + data->type = GL_TEXTURE_RECTANGLE_ARB; + texture_w = texture->w; + texture_h = texture->h; + data->texw = (GLfloat) texture_w; + data->texh = (GLfloat) texture_h; + } else { + data->type = GL_TEXTURE_2D; + texture_w = power_of_2(texture->w); + texture_h = power_of_2(texture->h); + data->texw = (GLfloat) (texture->w) / texture_w; + data->texh = (GLfloat) texture->h / texture_h; + } + + data->format = format; + data->formattype = type; + renderdata->glEnable(data->type); + renderdata->glBindTexture(data->type, data->texture); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); +#ifdef __MACOSX__ +#ifndef GL_TEXTURE_STORAGE_HINT_APPLE +#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC +#endif +#ifndef STORAGE_CACHED_APPLE +#define STORAGE_CACHED_APPLE 0x85BE +#endif +#ifndef STORAGE_SHARED_APPLE +#define STORAGE_SHARED_APPLE 0x85BF +#endif + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE, + GL_STORAGE_SHARED_APPLE); + } else { + renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE, + GL_STORAGE_CACHED_APPLE); + } + if (texture->access == SDL_TEXTUREACCESS_STREAMING + && texture->format == SDL_PIXELFORMAT_ARGB8888) { + renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, + texture_h, 0, format, type, data->pixels); + } + else +#endif + { + renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, + texture_h, 0, format, type, NULL); + } + renderdata->glDisable(data->type); + result = renderdata->glGetError(); + if (result != GL_NO_ERROR) { + GL_SetError("glTexImage2D()", result); + return -1; + } + return 0; +} + +static void +SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture, + int pitch) +{ + renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, + (pitch / SDL_BYTESPERPIXEL(texture->format))); +} + +static int +GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, int pitch) +{ + GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; + GL_TextureData *data = (GL_TextureData *) texture->driverdata; + GLenum result; + + GL_ActivateRenderer(renderer); + + renderdata->glGetError(); + SetupTextureUpdate(renderdata, texture, pitch); + renderdata->glEnable(data->type); + renderdata->glBindTexture(data->type, data->texture); + renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, + rect->h, data->format, data->formattype, + pixels); + renderdata->glDisable(data->type); + result = renderdata->glGetError(); + if (result != GL_NO_ERROR) { + GL_SetError("glTexSubImage2D()", result); + return -1; + } + return 0; +} + +static int +GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch) +{ + GL_TextureData *data = (GL_TextureData *) texture->driverdata; + + *pixels = + (void *) ((Uint8 *) data->pixels + rect->y * data->pitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + *pitch = data->pitch; + return 0; +} + +static void +GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; + GL_TextureData *data = (GL_TextureData *) texture->driverdata; + + GL_ActivateRenderer(renderer); + + SetupTextureUpdate(renderdata, texture, data->pitch); + renderdata->glEnable(data->type); + renderdata->glBindTexture(data->type, data->texture); + renderdata->glTexSubImage2D(data->type, 0, 0, 0, texture->w, texture->h, + data->format, data->formattype, data->pixels); + renderdata->glDisable(data->type); +} + +static void +GL_SetBlendMode(GL_RenderData * data, int blendMode) +{ + if (blendMode != data->blendMode) { + switch (blendMode) { + case SDL_BLENDMODE_NONE: + data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + data->glDisable(GL_BLEND); + break; + case SDL_BLENDMODE_BLEND: + data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + data->glEnable(GL_BLEND); + data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case SDL_BLENDMODE_ADD: + data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + data->glEnable(GL_BLEND); + data->glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + case SDL_BLENDMODE_MOD: + data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + data->glEnable(GL_BLEND); + data->glBlendFunc(GL_ZERO, GL_SRC_COLOR); + break; + } + data->blendMode = blendMode; + } +} + +static int +GL_RenderClear(SDL_Renderer * renderer) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + + GL_ActivateRenderer(renderer); + + data->glClearColor((GLfloat) renderer->r * inv255f, + (GLfloat) renderer->g * inv255f, + (GLfloat) renderer->b * inv255f, + (GLfloat) renderer->a * inv255f); + + data->glClear(GL_COLOR_BUFFER_BIT); + + return 0; +} + +static int +GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, + int count) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + int i; + + GL_ActivateRenderer(renderer); + + GL_SetBlendMode(data, renderer->blendMode); + + data->glColor4f((GLfloat) renderer->r * inv255f, + (GLfloat) renderer->g * inv255f, + (GLfloat) renderer->b * inv255f, + (GLfloat) renderer->a * inv255f); + + data->glBegin(GL_POINTS); + for (i = 0; i < count; ++i) { + data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); + } + data->glEnd(); + + return 0; +} + +static int +GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, + int count) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + int i; + + GL_ActivateRenderer(renderer); + + GL_SetBlendMode(data, renderer->blendMode); + + data->glColor4f((GLfloat) renderer->r * inv255f, + (GLfloat) renderer->g * inv255f, + (GLfloat) renderer->b * inv255f, + (GLfloat) renderer->a * inv255f); + + if (count > 2 && + points[0].x == points[count-1].x && points[0].y == points[count-1].y) { + data->glBegin(GL_LINE_LOOP); + /* GL_LINE_LOOP takes care of the final segment */ + --count; + for (i = 0; i < count; ++i) { + data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); + } + data->glEnd(); + } else { +#if defined(__APPLE__) || defined(__WIN32__) +#else + int x1, y1, x2, y2; +#endif + + data->glBegin(GL_LINE_STRIP); + for (i = 0; i < count; ++i) { + data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); + } + data->glEnd(); + + /* The line is half open, so we need one more point to complete it. + * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html + * If we have to, we can use vertical line and horizontal line textures + * for vertical and horizontal lines, and then create custom textures + * for diagonal lines and software render those. It's terrible, but at + * least it would be pixel perfect. + */ + data->glBegin(GL_POINTS); +#if defined(__APPLE__) || defined(__WIN32__) + /* Mac OS X and Windows seem to always leave the second point open */ + data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y); +#else + /* Linux seems to leave the right-most or bottom-most point open */ + x1 = points[0].x; + y1 = points[0].y; + x2 = points[count-1].x; + y2 = points[count-1].y; + + if (x1 > x2) { + data->glVertex2f(0.5f + x1, 0.5f + y1); + } else if (x2 > x1) { + data->glVertex2f(0.5f + x2, 0.5f + y2); + } else if (y1 > y2) { + data->glVertex2f(0.5f + x1, 0.5f + y1); + } else if (y2 > y1) { + data->glVertex2f(0.5f + x2, 0.5f + y2); + } +#endif + data->glEnd(); + } + + return 0; +} + +static int +GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + int i; + + GL_ActivateRenderer(renderer); + + GL_SetBlendMode(data, renderer->blendMode); + + data->glColor4f((GLfloat) renderer->r * inv255f, + (GLfloat) renderer->g * inv255f, + (GLfloat) renderer->b * inv255f, + (GLfloat) renderer->a * inv255f); + + for (i = 0; i < count; ++i) { + const SDL_Rect *rect = rects[i]; + + data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h); + } + + return 0; +} + +static int +GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata; + int minx, miny, maxx, maxy; + GLfloat minu, maxu, minv, maxv; + + GL_ActivateRenderer(renderer); + + minx = dstrect->x; + miny = dstrect->y; + maxx = dstrect->x + dstrect->w; + maxy = dstrect->y + dstrect->h; + + minu = (GLfloat) srcrect->x / texture->w; + minu *= texturedata->texw; + maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; + maxu *= texturedata->texw; + minv = (GLfloat) srcrect->y / texture->h; + minv *= texturedata->texh; + maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; + maxv *= texturedata->texh; + + data->glEnable(texturedata->type); + data->glBindTexture(texturedata->type, texturedata->texture); + + if (texture->modMode) { + data->glColor4f((GLfloat) texture->r * inv255f, + (GLfloat) texture->g * inv255f, + (GLfloat) texture->b * inv255f, + (GLfloat) texture->a * inv255f); + } else { + data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + + GL_SetBlendMode(data, texture->blendMode); + + data->glBegin(GL_TRIANGLE_STRIP); + data->glTexCoord2f(minu, minv); + data->glVertex2f((GLfloat) minx, (GLfloat) miny); + data->glTexCoord2f(maxu, minv); + data->glVertex2f((GLfloat) maxx, (GLfloat) miny); + data->glTexCoord2f(minu, maxv); + data->glVertex2f((GLfloat) minx, (GLfloat) maxy); + data->glTexCoord2f(maxu, maxv); + data->glVertex2f((GLfloat) maxx, (GLfloat) maxy); + data->glEnd(); + + data->glDisable(texturedata->type); + + return 0; +} + +static int +GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 pixel_format, void * pixels, int pitch) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + GLint internalFormat; + GLenum format, type; + Uint8 *src, *dst, *tmp; + int w, h, length, rows; + + GL_ActivateRenderer(renderer); + + if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) { + /* FIXME: Do a temp copy to a format that is supported */ + SDL_SetError("Unsupported pixel format"); + return -1; + } + + SDL_GetWindowSize(window, &w, &h); + + data->glPixelStorei(GL_PACK_ALIGNMENT, 1); + data->glPixelStorei(GL_PACK_ROW_LENGTH, + (pitch / SDL_BYTESPERPIXEL(pixel_format))); + + data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h, + format, type, pixels); + + /* Flip the rows to be top-down */ + length = rect->w * SDL_BYTESPERPIXEL(pixel_format); + src = (Uint8*)pixels + (rect->h-1)*pitch; + dst = (Uint8*)pixels; + tmp = SDL_stack_alloc(Uint8, length); + rows = rect->h / 2; + while (rows--) { + SDL_memcpy(tmp, dst, length); + SDL_memcpy(dst, src, length); + SDL_memcpy(src, tmp, length); + dst += pitch; + src -= pitch; + } + SDL_stack_free(tmp); + + return 0; +} + +static void +GL_RenderPresent(SDL_Renderer * renderer) +{ + GL_ActivateRenderer(renderer); + + SDL_GL_SwapWindow(renderer->window); +} + +static void +GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; + GL_TextureData *data = (GL_TextureData *) texture->driverdata; + + GL_ActivateRenderer(renderer); + + if (!data) { + return; + } + if (data->texture) { + renderdata->glDeleteTextures(1, &data->texture); + } + if (data->pixels) { + SDL_free(data->pixels); + } + SDL_free(data); + texture->driverdata = NULL; +} + +static void +GL_DestroyRenderer(SDL_Renderer * renderer) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + + if (data) { + if (data->context) { + /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */ + SDL_GL_DeleteContext(data->context); + } + SDL_free(data); + } + SDL_free(renderer); +} + +#endif /* SDL_VIDEO_RENDER_OGL */ + +/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/opengl/SDL_renderer_gl.c --- a/src/render/opengl/SDL_renderer_gl.c Sat Feb 05 11:54:46 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,826 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2010 Sam Lantinga - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ -#include "SDL_config.h" - -#if SDL_VIDEO_RENDER_OGL - -#include "SDL_opengl.h" -#include "../SDL_sysrender.h" - -#ifdef __MACOSX__ -#include -#endif - - -/* OpenGL renderer implementation */ - -/* Details on optimizing the texture path on Mac OS X: - http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html -*/ - -/* Used to re-create the window with OpenGL capability */ -extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); - -static const float inv255f = 1.0f / 255.0f; - -static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags); -static void GL_WindowEvent(SDL_Renderer * renderer, - const SDL_WindowEvent *event); -static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, const void *pixels, - int pitch); -static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, void **pixels, int *pitch); -static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static int GL_RenderClear(SDL_Renderer * renderer); -static int GL_RenderDrawPoints(SDL_Renderer * renderer, - const SDL_Point * points, int count); -static int GL_RenderDrawLines(SDL_Renderer * renderer, - const SDL_Point * points, int count); -static int GL_RenderFillRects(SDL_Renderer * renderer, - const SDL_Rect ** rects, int count); -static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * srcrect, const SDL_Rect * dstrect); -static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - Uint32 pixel_format, void * pixels, int pitch); -static void GL_RenderPresent(SDL_Renderer * renderer); -static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static void GL_DestroyRenderer(SDL_Renderer * renderer); - - -SDL_RenderDriver GL_RenderDriver = { - GL_CreateRenderer, - { - "opengl", - (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), - 1, - {SDL_PIXELFORMAT_ARGB8888}, - 0, - 0} -}; - -typedef struct -{ - SDL_GLContext context; - SDL_bool updateSize; - SDL_bool GL_ARB_texture_rectangle_supported; - int blendMode; - - /* OpenGL functions */ -#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; -#include "../../video/SDL_glfuncs.h" -#undef SDL_PROC - - void (*glTextureRangeAPPLE) (GLenum target, GLsizei length, - const GLvoid * pointer); -} GL_RenderData; - -typedef struct -{ - GLuint texture; - GLenum type; - GLfloat texw; - GLfloat texh; - GLenum format; - GLenum formattype; - void *pixels; - int pitch; -} GL_TextureData; - - -static void -GL_SetError(const char *prefix, GLenum result) -{ - const char *error; - - switch (result) { - case GL_NO_ERROR: - error = "GL_NO_ERROR"; - break; - case GL_INVALID_ENUM: - error = "GL_INVALID_ENUM"; - break; - case GL_INVALID_VALUE: - error = "GL_INVALID_VALUE"; - break; - case GL_INVALID_OPERATION: - error = "GL_INVALID_OPERATION"; - break; - case GL_STACK_OVERFLOW: - error = "GL_STACK_OVERFLOW"; - break; - case GL_STACK_UNDERFLOW: - error = "GL_STACK_UNDERFLOW"; - break; - case GL_OUT_OF_MEMORY: - error = "GL_OUT_OF_MEMORY"; - break; - case GL_TABLE_TOO_LARGE: - error = "GL_TABLE_TOO_LARGE"; - break; - default: - error = "UNKNOWN"; - break; - } - SDL_SetError("%s: %s", prefix, error); -} - -static int -GL_LoadFunctions(GL_RenderData * data) -{ -#ifdef __SDL_NOGETPROCADDR__ -#define SDL_PROC(ret,func,params) data->func=func; -#else -#define SDL_PROC(ret,func,params) \ - do { \ - data->func = SDL_GL_GetProcAddress(#func); \ - if ( ! data->func ) { \ - SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \ - return -1; \ - } \ - } while ( 0 ); -#endif /* __SDL_NOGETPROCADDR__ */ - -#include "../../video/SDL_glfuncs.h" -#undef SDL_PROC - return 0; -} - -SDL_Renderer * -GL_CreateRenderer(SDL_Window * window, Uint32 flags) -{ - SDL_Renderer *renderer; - GL_RenderData *data; - GLint value; - Uint32 window_flags; - - window_flags = SDL_GetWindowFlags(window); - if (!(window_flags & SDL_WINDOW_OPENGL)) { - if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) { - return NULL; - } - } - - renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); - if (!renderer) { - SDL_OutOfMemory(); - return NULL; - } - - data = (GL_RenderData *) SDL_calloc(1, sizeof(*data)); - if (!data) { - GL_DestroyRenderer(renderer); - SDL_OutOfMemory(); - return NULL; - } - - renderer->WindowEvent = GL_WindowEvent; - renderer->CreateTexture = GL_CreateTexture; - renderer->UpdateTexture = GL_UpdateTexture; - renderer->LockTexture = GL_LockTexture; - renderer->UnlockTexture = GL_UnlockTexture; - renderer->RenderClear = GL_RenderClear; - renderer->RenderDrawPoints = GL_RenderDrawPoints; - renderer->RenderDrawLines = GL_RenderDrawLines; - renderer->RenderFillRects = GL_RenderFillRects; - renderer->RenderCopy = GL_RenderCopy; - renderer->RenderReadPixels = GL_RenderReadPixels; - renderer->RenderPresent = GL_RenderPresent; - renderer->DestroyTexture = GL_DestroyTexture; - renderer->DestroyRenderer = GL_DestroyRenderer; - renderer->info = GL_RenderDriver.info; - renderer->driverdata = data; - - renderer->info.flags = SDL_RENDERER_ACCELERATED; - - if (GL_LoadFunctions(data) < 0) { - GL_DestroyRenderer(renderer); - return NULL; - } - - data->context = SDL_GL_CreateContext(window); - if (!data->context) { - GL_DestroyRenderer(renderer); - return NULL; - } - if (SDL_GL_MakeCurrent(window, data->context) < 0) { - GL_DestroyRenderer(renderer); - return NULL; - } -#ifdef __MACOSX__ - /* Enable multi-threaded rendering */ - /* Disabled until Ryan finishes his VBO/PBO code... - CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine); - */ -#endif - - if (flags & SDL_RENDERER_PRESENTVSYNC) { - SDL_GL_SetSwapInterval(1); - } else { - SDL_GL_SetSwapInterval(0); - } - if (SDL_GL_GetSwapInterval() > 0) { - renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; - } - - data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); - renderer->info.max_texture_width = value; - data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); - renderer->info.max_texture_height = value; - - if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") - || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) { - data->GL_ARB_texture_rectangle_supported = SDL_TRUE; - } - if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) { - data->glTextureRangeAPPLE = - (void (*)(GLenum, GLsizei, const GLvoid *)) - SDL_GL_GetProcAddress("glTextureRangeAPPLE"); - } - - /* Set up parameters for rendering */ - data->blendMode = -1; - data->glDisable(GL_DEPTH_TEST); - data->glDisable(GL_CULL_FACE); - /* This ended up causing video discrepancies between OpenGL and Direct3D */ - /*data->glEnable(GL_LINE_SMOOTH);*/ - if (data->GL_ARB_texture_rectangle_supported) { - data->glEnable(GL_TEXTURE_RECTANGLE_ARB); - } else { - data->glEnable(GL_TEXTURE_2D); - } - data->updateSize = SDL_TRUE; - - return renderer; -} - -static SDL_GLContext SDL_CurrentContext = NULL; - -static int -GL_ActivateRenderer(SDL_Renderer * renderer) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - SDL_Window *window = renderer->window; - - if (SDL_CurrentContext != data->context) { - if (SDL_GL_MakeCurrent(window, data->context) < 0) { - return -1; - } - SDL_CurrentContext = data->context; - } - if (data->updateSize) { - int w, h; - - SDL_GetWindowSize(window, &w, &h); - data->glMatrixMode(GL_PROJECTION); - data->glLoadIdentity(); - data->glMatrixMode(GL_MODELVIEW); - data->glLoadIdentity(); - data->glViewport(0, 0, w, h); - data->glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 1.0); - data->updateSize = SDL_FALSE; - } - return 0; -} - -static void -GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - - if (event->event == SDL_WINDOWEVENT_RESIZED) { - /* Rebind the context to the window area and update matrices */ - SDL_CurrentContext = NULL; - data->updateSize = SDL_TRUE; - } -} - -static __inline__ int -power_of_2(int input) -{ - int value = 1; - - while (value < input) { - value <<= 1; - } - return value; -} - -static __inline__ SDL_bool -convert_format(GL_RenderData *renderdata, Uint32 pixel_format, - GLint* internalFormat, GLenum* format, GLenum* type) -{ - switch (pixel_format) { - case SDL_PIXELFORMAT_RGB888: - case SDL_PIXELFORMAT_ARGB8888: - *internalFormat = GL_RGBA8; - *format = GL_BGRA; - *type = GL_UNSIGNED_INT_8_8_8_8_REV; - break; - default: - return SDL_FALSE; - } - return SDL_TRUE; -} - -static int -GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; - GL_TextureData *data; - GLint internalFormat; - GLenum format, type; - int texture_w, texture_h; - GLenum result; - - GL_ActivateRenderer(renderer); - - if (!convert_format(renderdata, texture->format, &internalFormat, - &format, &type)) { - SDL_SetError("Texture format %s not supported by OpenGL", - SDL_GetPixelFormatName(texture->format)); - return -1; - } - - data = (GL_TextureData *) SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_OutOfMemory(); - return -1; - } - - if (texture->access == SDL_TEXTUREACCESS_STREAMING) { - data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); - data->pixels = SDL_malloc(texture->h * data->pitch); - if (!data->pixels) { - SDL_OutOfMemory(); - SDL_free(data); - return -1; - } - } - - texture->driverdata = data; - - renderdata->glGetError(); - renderdata->glGenTextures(1, &data->texture); - if (renderdata->GL_ARB_texture_rectangle_supported) { - data->type = GL_TEXTURE_RECTANGLE_ARB; - texture_w = texture->w; - texture_h = texture->h; - data->texw = (GLfloat) texture_w; - data->texh = (GLfloat) texture_h; - } else { - data->type = GL_TEXTURE_2D; - texture_w = power_of_2(texture->w); - texture_h = power_of_2(texture->h); - data->texw = (GLfloat) (texture->w) / texture_w; - data->texh = (GLfloat) texture->h / texture_h; - } - - data->format = format; - data->formattype = type; - renderdata->glEnable(data->type); - renderdata->glBindTexture(data->type, data->texture); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); -#ifdef __MACOSX__ -#ifndef GL_TEXTURE_STORAGE_HINT_APPLE -#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC -#endif -#ifndef STORAGE_CACHED_APPLE -#define STORAGE_CACHED_APPLE 0x85BE -#endif -#ifndef STORAGE_SHARED_APPLE -#define STORAGE_SHARED_APPLE 0x85BF -#endif - if (texture->access == SDL_TEXTUREACCESS_STREAMING) { - renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE, - GL_STORAGE_SHARED_APPLE); - } else { - renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE, - GL_STORAGE_CACHED_APPLE); - } - if (texture->access == SDL_TEXTUREACCESS_STREAMING - && texture->format == SDL_PIXELFORMAT_ARGB8888) { - renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); - renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, - texture_h, 0, format, type, data->pixels); - } - else -#endif - { - renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, - texture_h, 0, format, type, NULL); - } - renderdata->glDisable(data->type); - result = renderdata->glGetError(); - if (result != GL_NO_ERROR) { - GL_SetError("glTexImage2D()", result); - return -1; - } - return 0; -} - -static void -SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture, - int pitch) -{ - renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, - (pitch / SDL_BYTESPERPIXEL(texture->format))); -} - -static int -GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, const void *pixels, int pitch) -{ - GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; - GL_TextureData *data = (GL_TextureData *) texture->driverdata; - GLenum result; - - GL_ActivateRenderer(renderer); - - renderdata->glGetError(); - SetupTextureUpdate(renderdata, texture, pitch); - renderdata->glEnable(data->type); - renderdata->glBindTexture(data->type, data->texture); - renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, - rect->h, data->format, data->formattype, - pixels); - renderdata->glDisable(data->type); - result = renderdata->glGetError(); - if (result != GL_NO_ERROR) { - GL_SetError("glTexSubImage2D()", result); - return -1; - } - return 0; -} - -static int -GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, void **pixels, int *pitch) -{ - GL_TextureData *data = (GL_TextureData *) texture->driverdata; - - *pixels = - (void *) ((Uint8 *) data->pixels + rect->y * data->pitch + - rect->x * SDL_BYTESPERPIXEL(texture->format)); - *pitch = data->pitch; - return 0; -} - -static void -GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; - GL_TextureData *data = (GL_TextureData *) texture->driverdata; - - GL_ActivateRenderer(renderer); - - SetupTextureUpdate(renderdata, texture, data->pitch); - renderdata->glEnable(data->type); - renderdata->glBindTexture(data->type, data->texture); - renderdata->glTexSubImage2D(data->type, 0, 0, 0, texture->w, texture->h, - data->format, data->formattype, data->pixels); - renderdata->glDisable(data->type); -} - -static void -GL_SetBlendMode(GL_RenderData * data, int blendMode) -{ - if (blendMode != data->blendMode) { - switch (blendMode) { - case SDL_BLENDMODE_NONE: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - data->glDisable(GL_BLEND); - break; - case SDL_BLENDMODE_BLEND: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - data->glEnable(GL_BLEND); - data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case SDL_BLENDMODE_ADD: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - data->glEnable(GL_BLEND); - data->glBlendFunc(GL_SRC_ALPHA, GL_ONE); - break; - case SDL_BLENDMODE_MOD: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - data->glEnable(GL_BLEND); - data->glBlendFunc(GL_ZERO, GL_SRC_COLOR); - break; - } - data->blendMode = blendMode; - } -} - -static int -GL_RenderClear(SDL_Renderer * renderer) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - - GL_ActivateRenderer(renderer); - - data->glClearColor((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); - - data->glClear(GL_COLOR_BUFFER_BIT); - - return 0; -} - -static int -GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, - int count) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - int i; - - GL_ActivateRenderer(renderer); - - GL_SetBlendMode(data, renderer->blendMode); - - data->glColor4f((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); - - data->glBegin(GL_POINTS); - for (i = 0; i < count; ++i) { - data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); - } - data->glEnd(); - - return 0; -} - -static int -GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, - int count) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - int i; - - GL_ActivateRenderer(renderer); - - GL_SetBlendMode(data, renderer->blendMode); - - data->glColor4f((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); - - if (count > 2 && - points[0].x == points[count-1].x && points[0].y == points[count-1].y) { - data->glBegin(GL_LINE_LOOP); - /* GL_LINE_LOOP takes care of the final segment */ - --count; - for (i = 0; i < count; ++i) { - data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); - } - data->glEnd(); - } else { -#if defined(__APPLE__) || defined(__WIN32__) -#else - int x1, y1, x2, y2; -#endif - - data->glBegin(GL_LINE_STRIP); - for (i = 0; i < count; ++i) { - data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); - } - data->glEnd(); - - /* The line is half open, so we need one more point to complete it. - * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html - * If we have to, we can use vertical line and horizontal line textures - * for vertical and horizontal lines, and then create custom textures - * for diagonal lines and software render those. It's terrible, but at - * least it would be pixel perfect. - */ - data->glBegin(GL_POINTS); -#if defined(__APPLE__) || defined(__WIN32__) - /* Mac OS X and Windows seem to always leave the second point open */ - data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y); -#else - /* Linux seems to leave the right-most or bottom-most point open */ - x1 = points[0].x; - y1 = points[0].y; - x2 = points[count-1].x; - y2 = points[count-1].y; - - if (x1 > x2) { - data->glVertex2f(0.5f + x1, 0.5f + y1); - } else if (x2 > x1) { - data->glVertex2f(0.5f + x2, 0.5f + y2); - } else if (y1 > y2) { - data->glVertex2f(0.5f + x1, 0.5f + y1); - } else if (y2 > y1) { - data->glVertex2f(0.5f + x2, 0.5f + y2); - } -#endif - data->glEnd(); - } - - return 0; -} - -static int -GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - int i; - - GL_ActivateRenderer(renderer); - - GL_SetBlendMode(data, renderer->blendMode); - - data->glColor4f((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); - - for (i = 0; i < count; ++i) { - const SDL_Rect *rect = rects[i]; - - data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h); - } - - return 0; -} - -static int -GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * srcrect, const SDL_Rect * dstrect) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata; - int minx, miny, maxx, maxy; - GLfloat minu, maxu, minv, maxv; - - GL_ActivateRenderer(renderer); - - minx = dstrect->x; - miny = dstrect->y; - maxx = dstrect->x + dstrect->w; - maxy = dstrect->y + dstrect->h; - - minu = (GLfloat) srcrect->x / texture->w; - minu *= texturedata->texw; - maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; - maxu *= texturedata->texw; - minv = (GLfloat) srcrect->y / texture->h; - minv *= texturedata->texh; - maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; - maxv *= texturedata->texh; - - data->glEnable(texturedata->type); - data->glBindTexture(texturedata->type, texturedata->texture); - - if (texture->modMode) { - data->glColor4f((GLfloat) texture->r * inv255f, - (GLfloat) texture->g * inv255f, - (GLfloat) texture->b * inv255f, - (GLfloat) texture->a * inv255f); - } else { - data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } - - GL_SetBlendMode(data, texture->blendMode); - - data->glBegin(GL_TRIANGLE_STRIP); - data->glTexCoord2f(minu, minv); - data->glVertex2f((GLfloat) minx, (GLfloat) miny); - data->glTexCoord2f(maxu, minv); - data->glVertex2f((GLfloat) maxx, (GLfloat) miny); - data->glTexCoord2f(minu, maxv); - data->glVertex2f((GLfloat) minx, (GLfloat) maxy); - data->glTexCoord2f(maxu, maxv); - data->glVertex2f((GLfloat) maxx, (GLfloat) maxy); - data->glEnd(); - - data->glDisable(texturedata->type); - - return 0; -} - -static int -GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - Uint32 pixel_format, void * pixels, int pitch) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - SDL_Window *window = renderer->window; - GLint internalFormat; - GLenum format, type; - Uint8 *src, *dst, *tmp; - int w, h, length, rows; - - GL_ActivateRenderer(renderer); - - if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) { - /* FIXME: Do a temp copy to a format that is supported */ - SDL_SetError("Unsupported pixel format"); - return -1; - } - - SDL_GetWindowSize(window, &w, &h); - - data->glPixelStorei(GL_PACK_ALIGNMENT, 1); - data->glPixelStorei(GL_PACK_ROW_LENGTH, - (pitch / SDL_BYTESPERPIXEL(pixel_format))); - - data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h, - format, type, pixels); - - /* Flip the rows to be top-down */ - length = rect->w * SDL_BYTESPERPIXEL(pixel_format); - src = (Uint8*)pixels + (rect->h-1)*pitch; - dst = (Uint8*)pixels; - tmp = SDL_stack_alloc(Uint8, length); - rows = rect->h / 2; - while (rows--) { - SDL_memcpy(tmp, dst, length); - SDL_memcpy(dst, src, length); - SDL_memcpy(src, tmp, length); - dst += pitch; - src -= pitch; - } - SDL_stack_free(tmp); - - return 0; -} - -static void -GL_RenderPresent(SDL_Renderer * renderer) -{ - GL_ActivateRenderer(renderer); - - SDL_GL_SwapWindow(renderer->window); -} - -static void -GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; - GL_TextureData *data = (GL_TextureData *) texture->driverdata; - - GL_ActivateRenderer(renderer); - - if (!data) { - return; - } - if (data->texture) { - renderdata->glDeleteTextures(1, &data->texture); - } - if (data->pixels) { - SDL_free(data->pixels); - } - SDL_free(data); - texture->driverdata = NULL; -} - -static void -GL_DestroyRenderer(SDL_Renderer * renderer) -{ - GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - - if (data) { - if (data->context) { - /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */ - SDL_GL_DeleteContext(data->context); - } - SDL_free(data); - } - SDL_free(renderer); -} - -#endif /* SDL_VIDEO_RENDER_OGL */ - -/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/opengles/SDL_render_gles.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/render/opengles/SDL_render_gles.c Sat Feb 05 12:01:11 2011 -0800 @@ -0,0 +1,748 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_RENDER_OGL_ES + +#include "SDL_opengles.h" +#include "../SDL_sysrender.h" + +#if defined(SDL_VIDEO_DRIVER_PANDORA) + +/* Empty function stub to get OpenGL ES 1.x support without */ +/* OpenGL ES extension GL_OES_draw_texture supported */ +GL_API void GL_APIENTRY +glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height) +{ + return; +} + +#endif /* PANDORA */ + +/* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */ + +/* Used to re-create the window with OpenGL capability */ +extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); + +static const float inv255f = 1.0f / 255.0f; + +static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags); +static void GLES_WindowEvent(SDL_Renderer * renderer, + const SDL_WindowEvent *event); +static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, + int pitch); +static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch); +static void GLES_UnlockTexture(SDL_Renderer * renderer, + SDL_Texture * texture); +static int GLES_RenderDrawPoints(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int GLES_RenderDrawLines(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int GLES_RenderFillRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, int count); +static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, + const SDL_Rect * dstrect); +static void GLES_RenderPresent(SDL_Renderer * renderer); +static void GLES_DestroyTexture(SDL_Renderer * renderer, + SDL_Texture * texture); +static void GLES_DestroyRenderer(SDL_Renderer * renderer); + + +SDL_RenderDriver GL_ES_RenderDriver = { + GLES_CreateRenderer, + { + "opengl_es", + (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), + 1, + {SDL_PIXELFORMAT_ABGR8888}, + 0, + 0} +}; + +typedef struct +{ + SDL_GLContext context; + SDL_bool updateSize; + int blendMode; + +#ifndef APIENTRY +#define APIENTRY +#endif + + SDL_bool useDrawTexture; + SDL_bool GL_OES_draw_texture_supported; + + /* OpenGL ES functions */ +#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; +#include "../../video/SDL_glesfuncs.h" +#undef SDL_PROC + +} GLES_RenderData; + +typedef struct +{ + GLuint texture; + GLenum type; + GLfloat texw; + GLfloat texh; + GLenum format; + GLenum formattype; + void *pixels; + int pitch; +} GLES_TextureData; + +static void +GLES_SetError(const char *prefix, GLenum result) +{ + const char *error; + + switch (result) { + case GL_NO_ERROR: + error = "GL_NO_ERROR"; + break; + case GL_INVALID_ENUM: + error = "GL_INVALID_ENUM"; + break; + case GL_INVALID_VALUE: + error = "GL_INVALID_VALUE"; + break; + case GL_INVALID_OPERATION: + error = "GL_INVALID_OPERATION"; + break; + case GL_STACK_OVERFLOW: + error = "GL_STACK_OVERFLOW"; + break; + case GL_STACK_UNDERFLOW: + error = "GL_STACK_UNDERFLOW"; + break; + case GL_OUT_OF_MEMORY: + error = "GL_OUT_OF_MEMORY"; + break; + default: + error = "UNKNOWN"; + break; + } + SDL_SetError("%s: %s", prefix, error); +} + +static int +GLES_LoadFunctions(GLES_RenderData * data) +{ + +#define SDL_PROC(ret,func,params) \ + data->func = func; +#include "../../video/SDL_glesfuncs.h" +#undef SDL_PROC + + return 0; +} + +SDL_Renderer * +GLES_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + + SDL_Renderer *renderer; + GLES_RenderData *data; + GLint value; + Uint32 window_flags; + + window_flags = SDL_GetWindowFlags(window); + if (!(window_flags & SDL_WINDOW_OPENGL)) { + if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) { + return NULL; + } + } + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + + data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + GLES_DestroyRenderer(renderer); + SDL_OutOfMemory(); + return NULL; + } + + renderer->WindowEvent = GLES_WindowEvent; + renderer->CreateTexture = GLES_CreateTexture; + renderer->UpdateTexture = GLES_UpdateTexture; + renderer->LockTexture = GLES_LockTexture; + renderer->UnlockTexture = GLES_UnlockTexture; + renderer->RenderDrawPoints = GLES_RenderDrawPoints; + renderer->RenderDrawLines = GLES_RenderDrawLines; + renderer->RenderFillRects = GLES_RenderFillRects; + renderer->RenderCopy = GLES_RenderCopy; + renderer->RenderPresent = GLES_RenderPresent; + renderer->DestroyTexture = GLES_DestroyTexture; + renderer->DestroyRenderer = GLES_DestroyRenderer; + renderer->info = GL_ES_RenderDriver.info; + renderer->driverdata = data; + + renderer->info.flags = SDL_RENDERER_ACCELERATED; + + if (GLES_LoadFunctions(data) < 0) { + GLES_DestroyRenderer(renderer); + return NULL; + } + + data->context = SDL_GL_CreateContext(window); + if (!data->context) { + GLES_DestroyRenderer(renderer); + return NULL; + } + if (SDL_GL_MakeCurrent(window, data->context) < 0) { + GLES_DestroyRenderer(renderer); + return NULL; + } + + if (flags & SDL_RENDERER_PRESENTVSYNC) { + SDL_GL_SetSwapInterval(1); + } else { + SDL_GL_SetSwapInterval(0); + } + if (SDL_GL_GetSwapInterval() > 0) { + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } + +#if SDL_VIDEO_DRIVER_PANDORA + data->GL_OES_draw_texture_supported = SDL_FALSE; + data->useDrawTexture = SDL_FALSE; +#else + if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) { + data->GL_OES_draw_texture_supported = SDL_TRUE; + data->useDrawTexture = SDL_TRUE; + } else { + data->GL_OES_draw_texture_supported = SDL_FALSE; + data->useDrawTexture = SDL_FALSE; + } +#endif + + data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); + renderer->info.max_texture_width = value; + data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); + renderer->info.max_texture_height = value; + + /* Set up parameters for rendering */ + data->blendMode = -1; + data->glDisable(GL_DEPTH_TEST); + data->glDisable(GL_CULL_FACE); + data->updateSize = SDL_TRUE; + + data->glEnableClientState(GL_VERTEX_ARRAY); + data->glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + return renderer; +} + +static SDL_GLContext SDL_CurrentContext = NULL; + +static int +GLES_ActivateRenderer(SDL_Renderer * renderer) +{ + + GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + + if (SDL_CurrentContext != data->context) { + if (SDL_GL_MakeCurrent(window, data->context) < 0) { + return -1; + } + SDL_CurrentContext = data->context; + } + if (data->updateSize) { + int w, h; + + SDL_GetWindowSize(window, &w, &h); + data->glMatrixMode(GL_PROJECTION); + data->glLoadIdentity(); + data->glMatrixMode(GL_MODELVIEW); + data->glLoadIdentity(); + data->glViewport(0, 0, w, h); + data->glOrthof(0.0, (GLfloat) w, (GLfloat) h, 0.0, 0.0, 1.0); + data->updateSize = SDL_FALSE; + } + return 0; +} + +static void +GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) +{ + GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; + + if (event->event == SDL_WINDOWEVENT_RESIZED) { + /* Rebind the context to the window area and update matrices */ + SDL_CurrentContext = NULL; + data->updateSize = SDL_TRUE; + } +} + +static __inline__ int +power_of_2(int input) +{ + int value = 1; + + while (value < input) { + value <<= 1; + } + return value; +} + +static int +GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; + GLES_TextureData *data; + GLint internalFormat; + GLenum format, type; + int texture_w, texture_h; + GLenum result; + + GLES_ActivateRenderer(renderer); + + switch (texture->format) { + case SDL_PIXELFORMAT_ABGR8888: + internalFormat = GL_RGBA; + format = GL_RGBA; + type = GL_UNSIGNED_BYTE; + break; + default: + SDL_SetError("Texture format %s not supported by OpenGL ES", + SDL_GetPixelFormatName(texture->format)); + return -1; + } + + data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + SDL_OutOfMemory(); + return -1; + } + + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); + data->pixels = SDL_malloc(texture->h * data->pitch); + if (!data->pixels) { + SDL_OutOfMemory(); + SDL_free(data); + return -1; + } + } + + texture->driverdata = data; + + renderdata->glGetError(); + renderdata->glEnable(GL_TEXTURE_2D); + renderdata->glGenTextures(1, &data->texture); + + data->type = GL_TEXTURE_2D; + /* no NPOV textures allowed in OpenGL ES (yet) */ + texture_w = power_of_2(texture->w); + texture_h = power_of_2(texture->h); + data->texw = (GLfloat) texture->w / texture_w; + data->texh = (GLfloat) texture->h / texture_h; + + data->format = format; + data->formattype = type; + renderdata->glBindTexture(data->type, data->texture); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, + texture_h, 0, format, type, NULL); + renderdata->glDisable(GL_TEXTURE_2D); + + result = renderdata->glGetError(); + if (result != GL_NO_ERROR) { + GLES_SetError("glTexImage2D()", result); + return -1; + } + return 0; +} + +static void +SetupTextureUpdate(GLES_RenderData * renderdata, SDL_Texture * texture, + int pitch) +{ + renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +} + +static int +GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, int pitch) +{ + GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; + GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; + GLenum result; + int bpp = SDL_BYTESPERPIXEL(texture->format); + void * temp_buffer; + void * temp_ptr; + int i; + + GLES_ActivateRenderer(renderer); + + renderdata->glGetError(); + SetupTextureUpdate(renderdata, texture, pitch); + renderdata->glEnable(data->type); + renderdata->glBindTexture(data->type, data->texture); + + if( rect->w * bpp == pitch ) { + temp_buffer = (void *)pixels; /* No need to reformat */ + } else { + /* Reformatting of mem area required */ + temp_buffer = SDL_malloc(rect->w * rect->h * bpp); + temp_ptr = temp_buffer; + for (i = 0; i < rect->h; i++) { + SDL_memcpy(temp_ptr, pixels, rect->w * bpp); + temp_ptr += rect->w * bpp; + pixels += pitch; + } + } + + renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, + rect->h, data->format, data->formattype, + temp_buffer); + + if( temp_buffer != pixels ) { + SDL_free(temp_buffer); + } + + renderdata->glDisable(data->type); + result = renderdata->glGetError(); + if (result != GL_NO_ERROR) { + GLES_SetError("glTexSubImage2D()", result); + return -1; + } + return 0; +} + +static int +GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch) +{ + GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; + + *pixels = + (void *) ((Uint8 *) data->pixels + rect->y * data->pitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + *pitch = data->pitch; + return 0; +} + +static void +GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; + GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; + + GLES_ActivateRenderer(renderer); + + SetupTextureUpdate(renderdata, texture, data->pitch); + renderdata->glEnable(data->type); + renderdata->glBindTexture(data->type, data->texture); + renderdata->glTexSubImage2D(data->type, 0, 0, 0, texture->w, + texture->h, data->format, data->formattype, + data->pixels); + renderdata->glDisable(data->type); +} + +static void +GLES_SetBlendMode(GLES_RenderData * data, int blendMode) +{ + if (blendMode != data->blendMode) { + switch (blendMode) { + case SDL_BLENDMODE_NONE: + data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + data->glDisable(GL_BLEND); + break; + case SDL_BLENDMODE_BLEND: + data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + data->glEnable(GL_BLEND); + data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case SDL_BLENDMODE_ADD: + data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + data->glEnable(GL_BLEND); + data->glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + case SDL_BLENDMODE_MOD: + data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + data->glEnable(GL_BLEND); + data->glBlendFunc(GL_ZERO, GL_SRC_COLOR); + break; + } + data->blendMode = blendMode; + } +} + +static int +GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, + int count) +{ + GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; + int i; + GLshort *vertices; + + GLES_ActivateRenderer(renderer); + + GLES_SetBlendMode(data, renderer->blendMode); + + data->glColor4f((GLfloat) renderer->r * inv255f, + (GLfloat) renderer->g * inv255f, + (GLfloat) renderer->b * inv255f, + (GLfloat) renderer->a * inv255f); + + vertices = SDL_stack_alloc(GLshort, count*2); + for (i = 0; i < count; ++i) { + vertices[2*i+0] = (GLshort)points[i].x; + vertices[2*i+1] = (GLshort)points[i].y; + } + data->glVertexPointer(2, GL_SHORT, 0, vertices); + data->glDrawArrays(GL_POINTS, 0, count); + SDL_stack_free(vertices); + + return 0; +} + +static int +GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, + int count) +{ + GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; + int i; + GLshort *vertices; + + GLES_ActivateRenderer(renderer); + + GLES_SetBlendMode(data, renderer->blendMode); + + data->glColor4f((GLfloat) renderer->r * inv255f, + (GLfloat) renderer->g * inv255f, + (GLfloat) renderer->b * inv255f, + (GLfloat) renderer->a * inv255f); + + vertices = SDL_stack_alloc(GLshort, count*2); + for (i = 0; i < count; ++i) { + vertices[2*i+0] = (GLshort)points[i].x; + vertices[2*i+1] = (GLshort)points[i].y; + } + data->glVertexPointer(2, GL_SHORT, 0, vertices); + if (count > 2 && + points[0].x == points[count-1].x && points[0].y == points[count-1].y) { + /* GL_LINE_LOOP takes care of the final segment */ + --count; + data->glDrawArrays(GL_LINE_LOOP, 0, count); + } else { + data->glDrawArrays(GL_LINE_STRIP, 0, count); + } + SDL_stack_free(vertices); + + return 0; +} + +static int +GLES_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, + int count) +{ + GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; + int i; + + GLES_ActivateRenderer(renderer); + + GLES_SetBlendMode(data, renderer->blendMode); + + data->glColor4f((GLfloat) renderer->r * inv255f, + (GLfloat) renderer->g * inv255f, + (GLfloat) renderer->b * inv255f, + (GLfloat) renderer->a * inv255f); + + for (i = 0; i < count; ++i) { + const SDL_Rect *rect = rects[i]; + GLshort minx = rect->x; + GLshort maxx = rect->x + rect->w; + GLshort miny = rect->y; + GLshort maxy = rect->y + rect->h; + GLshort vertices[8]; + vertices[0] = minx; + vertices[1] = miny; + vertices[2] = maxx; + vertices[3] = miny; + vertices[4] = minx; + vertices[5] = maxy; + vertices[6] = maxx; + vertices[7] = maxy; + + data->glVertexPointer(2, GL_SHORT, 0, vertices); + data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + + return 0; +} + +static int +GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect) +{ + + GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; + GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata; + int minx, miny, maxx, maxy; + GLfloat minu, maxu, minv, maxv; + int i; + void *temp_buffer; /* used for reformatting dirty rect pixels */ + void *temp_ptr; + + GLES_ActivateRenderer(renderer); + + data->glEnable(GL_TEXTURE_2D); + + data->glBindTexture(texturedata->type, texturedata->texture); + + if (texture->modMode) { + data->glColor4f((GLfloat) texture->r * inv255f, + (GLfloat) texture->g * inv255f, + (GLfloat) texture->b * inv255f, + (GLfloat) texture->a * inv255f); + } else { + data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + + GLES_SetBlendMode(data, texture->blendMode); + + if (data->GL_OES_draw_texture_supported && data->useDrawTexture) { + /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */ + GLint cropRect[4]; + int w, h; + SDL_Window *window = renderer->window; + + SDL_GetWindowSize(window, &w, &h); + cropRect[0] = srcrect->x; + cropRect[1] = srcrect->y + srcrect->h; + cropRect[2] = srcrect->w; + cropRect[3] = -srcrect->h; + data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, + cropRect); + data->glDrawTexiOES(dstrect->x, h - dstrect->y - dstrect->h, 0, + dstrect->w, dstrect->h); + } else { + + minx = dstrect->x; + miny = dstrect->y; + maxx = dstrect->x + dstrect->w; + maxy = dstrect->y + dstrect->h; + + minu = (GLfloat) srcrect->x / texture->w; + minu *= texturedata->texw; + maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; + maxu *= texturedata->texw; + minv = (GLfloat) srcrect->y / texture->h; + minv *= texturedata->texh; + maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; + maxv *= texturedata->texh; + + GLshort vertices[8]; + GLfloat texCoords[8]; + + vertices[0] = minx; + vertices[1] = miny; + vertices[2] = maxx; + vertices[3] = miny; + vertices[4] = minx; + vertices[5] = maxy; + vertices[6] = maxx; + vertices[7] = maxy; + + texCoords[0] = minu; + texCoords[1] = minv; + texCoords[2] = maxu; + texCoords[3] = minv; + texCoords[4] = minu; + texCoords[5] = maxv; + texCoords[6] = maxu; + texCoords[7] = maxv; + + data->glVertexPointer(2, GL_SHORT, 0, vertices); + data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + + data->glDisable(GL_TEXTURE_2D); + + return 0; +} + +static void +GLES_RenderPresent(SDL_Renderer * renderer) +{ + GLES_ActivateRenderer(renderer); + + SDL_GL_SwapWindow(renderer->window); +} + +static void +GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; + + GLES_ActivateRenderer(renderer); + + if (!data) { + return; + } + if (data->texture) { + glDeleteTextures(1, &data->texture); + } + if (data->pixels) { + SDL_free(data->pixels); + } + SDL_free(data); + texture->driverdata = NULL; +} + +static void +GLES_DestroyRenderer(SDL_Renderer * renderer) +{ + GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; + + if (data) { + if (data->context) { + SDL_GL_DeleteContext(data->context); + } + SDL_free(data); + } + SDL_free(renderer); +} + +#endif /* SDL_VIDEO_RENDER_OGL_ES */ + +/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/opengles/SDL_renderer_gles.c --- a/src/render/opengles/SDL_renderer_gles.c Sat Feb 05 11:54:46 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,748 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2010 Sam Lantinga - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ -#include "SDL_config.h" - -#if SDL_VIDEO_RENDER_OGL_ES - -#include "SDL_opengles.h" -#include "../SDL_sysrender.h" - -#if defined(SDL_VIDEO_DRIVER_PANDORA) - -/* Empty function stub to get OpenGL ES 1.x support without */ -/* OpenGL ES extension GL_OES_draw_texture supported */ -GL_API void GL_APIENTRY -glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height) -{ - return; -} - -#endif /* PANDORA */ - -/* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */ - -/* Used to re-create the window with OpenGL capability */ -extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); - -static const float inv255f = 1.0f / 255.0f; - -static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags); -static void GLES_WindowEvent(SDL_Renderer * renderer, - const SDL_WindowEvent *event); -static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, const void *pixels, - int pitch); -static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, void **pixels, int *pitch); -static void GLES_UnlockTexture(SDL_Renderer * renderer, - SDL_Texture * texture); -static int GLES_RenderDrawPoints(SDL_Renderer * renderer, - const SDL_Point * points, int count); -static int GLES_RenderDrawLines(SDL_Renderer * renderer, - const SDL_Point * points, int count); -static int GLES_RenderFillRects(SDL_Renderer * renderer, - const SDL_Rect ** rects, int count); -static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * srcrect, - const SDL_Rect * dstrect); -static void GLES_RenderPresent(SDL_Renderer * renderer); -static void GLES_DestroyTexture(SDL_Renderer * renderer, - SDL_Texture * texture); -static void GLES_DestroyRenderer(SDL_Renderer * renderer); - - -SDL_RenderDriver GL_ES_RenderDriver = { - GLES_CreateRenderer, - { - "opengl_es", - (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), - 1, - {SDL_PIXELFORMAT_ABGR8888}, - 0, - 0} -}; - -typedef struct -{ - SDL_GLContext context; - SDL_bool updateSize; - int blendMode; - -#ifndef APIENTRY -#define APIENTRY -#endif - - SDL_bool useDrawTexture; - SDL_bool GL_OES_draw_texture_supported; - - /* OpenGL ES functions */ -#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; -#include "../../video/SDL_glesfuncs.h" -#undef SDL_PROC - -} GLES_RenderData; - -typedef struct -{ - GLuint texture; - GLenum type; - GLfloat texw; - GLfloat texh; - GLenum format; - GLenum formattype; - void *pixels; - int pitch; -} GLES_TextureData; - -static void -GLES_SetError(const char *prefix, GLenum result) -{ - const char *error; - - switch (result) { - case GL_NO_ERROR: - error = "GL_NO_ERROR"; - break; - case GL_INVALID_ENUM: - error = "GL_INVALID_ENUM"; - break; - case GL_INVALID_VALUE: - error = "GL_INVALID_VALUE"; - break; - case GL_INVALID_OPERATION: - error = "GL_INVALID_OPERATION"; - break; - case GL_STACK_OVERFLOW: - error = "GL_STACK_OVERFLOW"; - break; - case GL_STACK_UNDERFLOW: - error = "GL_STACK_UNDERFLOW"; - break; - case GL_OUT_OF_MEMORY: - error = "GL_OUT_OF_MEMORY"; - break; - default: - error = "UNKNOWN"; - break; - } - SDL_SetError("%s: %s", prefix, error); -} - -static int -GLES_LoadFunctions(GLES_RenderData * data) -{ - -#define SDL_PROC(ret,func,params) \ - data->func = func; -#include "../../video/SDL_glesfuncs.h" -#undef SDL_PROC - - return 0; -} - -SDL_Renderer * -GLES_CreateRenderer(SDL_Window * window, Uint32 flags) -{ - - SDL_Renderer *renderer; - GLES_RenderData *data; - GLint value; - Uint32 window_flags; - - window_flags = SDL_GetWindowFlags(window); - if (!(window_flags & SDL_WINDOW_OPENGL)) { - if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) { - return NULL; - } - } - - renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); - if (!renderer) { - SDL_OutOfMemory(); - return NULL; - } - - data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data)); - if (!data) { - GLES_DestroyRenderer(renderer); - SDL_OutOfMemory(); - return NULL; - } - - renderer->WindowEvent = GLES_WindowEvent; - renderer->CreateTexture = GLES_CreateTexture; - renderer->UpdateTexture = GLES_UpdateTexture; - renderer->LockTexture = GLES_LockTexture; - renderer->UnlockTexture = GLES_UnlockTexture; - renderer->RenderDrawPoints = GLES_RenderDrawPoints; - renderer->RenderDrawLines = GLES_RenderDrawLines; - renderer->RenderFillRects = GLES_RenderFillRects; - renderer->RenderCopy = GLES_RenderCopy; - renderer->RenderPresent = GLES_RenderPresent; - renderer->DestroyTexture = GLES_DestroyTexture; - renderer->DestroyRenderer = GLES_DestroyRenderer; - renderer->info = GL_ES_RenderDriver.info; - renderer->driverdata = data; - - renderer->info.flags = SDL_RENDERER_ACCELERATED; - - if (GLES_LoadFunctions(data) < 0) { - GLES_DestroyRenderer(renderer); - return NULL; - } - - data->context = SDL_GL_CreateContext(window); - if (!data->context) { - GLES_DestroyRenderer(renderer); - return NULL; - } - if (SDL_GL_MakeCurrent(window, data->context) < 0) { - GLES_DestroyRenderer(renderer); - return NULL; - } - - if (flags & SDL_RENDERER_PRESENTVSYNC) { - SDL_GL_SetSwapInterval(1); - } else { - SDL_GL_SetSwapInterval(0); - } - if (SDL_GL_GetSwapInterval() > 0) { - renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; - } - -#if SDL_VIDEO_DRIVER_PANDORA - data->GL_OES_draw_texture_supported = SDL_FALSE; - data->useDrawTexture = SDL_FALSE; -#else - if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) { - data->GL_OES_draw_texture_supported = SDL_TRUE; - data->useDrawTexture = SDL_TRUE; - } else { - data->GL_OES_draw_texture_supported = SDL_FALSE; - data->useDrawTexture = SDL_FALSE; - } -#endif - - data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); - renderer->info.max_texture_width = value; - data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); - renderer->info.max_texture_height = value; - - /* Set up parameters for rendering */ - data->blendMode = -1; - data->glDisable(GL_DEPTH_TEST); - data->glDisable(GL_CULL_FACE); - data->updateSize = SDL_TRUE; - - data->glEnableClientState(GL_VERTEX_ARRAY); - data->glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - return renderer; -} - -static SDL_GLContext SDL_CurrentContext = NULL; - -static int -GLES_ActivateRenderer(SDL_Renderer * renderer) -{ - - GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - SDL_Window *window = renderer->window; - - if (SDL_CurrentContext != data->context) { - if (SDL_GL_MakeCurrent(window, data->context) < 0) { - return -1; - } - SDL_CurrentContext = data->context; - } - if (data->updateSize) { - int w, h; - - SDL_GetWindowSize(window, &w, &h); - data->glMatrixMode(GL_PROJECTION); - data->glLoadIdentity(); - data->glMatrixMode(GL_MODELVIEW); - data->glLoadIdentity(); - data->glViewport(0, 0, w, h); - data->glOrthof(0.0, (GLfloat) w, (GLfloat) h, 0.0, 0.0, 1.0); - data->updateSize = SDL_FALSE; - } - return 0; -} - -static void -GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) -{ - GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - - if (event->event == SDL_WINDOWEVENT_RESIZED) { - /* Rebind the context to the window area and update matrices */ - SDL_CurrentContext = NULL; - data->updateSize = SDL_TRUE; - } -} - -static __inline__ int -power_of_2(int input) -{ - int value = 1; - - while (value < input) { - value <<= 1; - } - return value; -} - -static int -GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; - GLES_TextureData *data; - GLint internalFormat; - GLenum format, type; - int texture_w, texture_h; - GLenum result; - - GLES_ActivateRenderer(renderer); - - switch (texture->format) { - case SDL_PIXELFORMAT_ABGR8888: - internalFormat = GL_RGBA; - format = GL_RGBA; - type = GL_UNSIGNED_BYTE; - break; - default: - SDL_SetError("Texture format %s not supported by OpenGL ES", - SDL_GetPixelFormatName(texture->format)); - return -1; - } - - data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_OutOfMemory(); - return -1; - } - - if (texture->access == SDL_TEXTUREACCESS_STREAMING) { - data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); - data->pixels = SDL_malloc(texture->h * data->pitch); - if (!data->pixels) { - SDL_OutOfMemory(); - SDL_free(data); - return -1; - } - } - - texture->driverdata = data; - - renderdata->glGetError(); - renderdata->glEnable(GL_TEXTURE_2D); - renderdata->glGenTextures(1, &data->texture); - - data->type = GL_TEXTURE_2D; - /* no NPOV textures allowed in OpenGL ES (yet) */ - texture_w = power_of_2(texture->w); - texture_h = power_of_2(texture->h); - data->texw = (GLfloat) texture->w / texture_w; - data->texh = (GLfloat) texture->h / texture_h; - - data->format = format; - data->formattype = type; - renderdata->glBindTexture(data->type, data->texture); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, - texture_h, 0, format, type, NULL); - renderdata->glDisable(GL_TEXTURE_2D); - - result = renderdata->glGetError(); - if (result != GL_NO_ERROR) { - GLES_SetError("glTexImage2D()", result); - return -1; - } - return 0; -} - -static void -SetupTextureUpdate(GLES_RenderData * renderdata, SDL_Texture * texture, - int pitch) -{ - renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -} - -static int -GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, const void *pixels, int pitch) -{ - GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; - GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; - GLenum result; - int bpp = SDL_BYTESPERPIXEL(texture->format); - void * temp_buffer; - void * temp_ptr; - int i; - - GLES_ActivateRenderer(renderer); - - renderdata->glGetError(); - SetupTextureUpdate(renderdata, texture, pitch); - renderdata->glEnable(data->type); - renderdata->glBindTexture(data->type, data->texture); - - if( rect->w * bpp == pitch ) { - temp_buffer = (void *)pixels; /* No need to reformat */ - } else { - /* Reformatting of mem area required */ - temp_buffer = SDL_malloc(rect->w * rect->h * bpp); - temp_ptr = temp_buffer; - for (i = 0; i < rect->h; i++) { - SDL_memcpy(temp_ptr, pixels, rect->w * bpp); - temp_ptr += rect->w * bpp; - pixels += pitch; - } - } - - renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, - rect->h, data->format, data->formattype, - temp_buffer); - - if( temp_buffer != pixels ) { - SDL_free(temp_buffer); - } - - renderdata->glDisable(data->type); - result = renderdata->glGetError(); - if (result != GL_NO_ERROR) { - GLES_SetError("glTexSubImage2D()", result); - return -1; - } - return 0; -} - -static int -GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, void **pixels, int *pitch) -{ - GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; - - *pixels = - (void *) ((Uint8 *) data->pixels + rect->y * data->pitch + - rect->x * SDL_BYTESPERPIXEL(texture->format)); - *pitch = data->pitch; - return 0; -} - -static void -GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; - GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; - - GLES_ActivateRenderer(renderer); - - SetupTextureUpdate(renderdata, texture, data->pitch); - renderdata->glEnable(data->type); - renderdata->glBindTexture(data->type, data->texture); - renderdata->glTexSubImage2D(data->type, 0, 0, 0, texture->w, - texture->h, data->format, data->formattype, - data->pixels); - renderdata->glDisable(data->type); -} - -static void -GLES_SetBlendMode(GLES_RenderData * data, int blendMode) -{ - if (blendMode != data->blendMode) { - switch (blendMode) { - case SDL_BLENDMODE_NONE: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - data->glDisable(GL_BLEND); - break; - case SDL_BLENDMODE_BLEND: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - data->glEnable(GL_BLEND); - data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case SDL_BLENDMODE_ADD: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - data->glEnable(GL_BLEND); - data->glBlendFunc(GL_SRC_ALPHA, GL_ONE); - break; - case SDL_BLENDMODE_MOD: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - data->glEnable(GL_BLEND); - data->glBlendFunc(GL_ZERO, GL_SRC_COLOR); - break; - } - data->blendMode = blendMode; - } -} - -static int -GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, - int count) -{ - GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - int i; - GLshort *vertices; - - GLES_ActivateRenderer(renderer); - - GLES_SetBlendMode(data, renderer->blendMode); - - data->glColor4f((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); - - vertices = SDL_stack_alloc(GLshort, count*2); - for (i = 0; i < count; ++i) { - vertices[2*i+0] = (GLshort)points[i].x; - vertices[2*i+1] = (GLshort)points[i].y; - } - data->glVertexPointer(2, GL_SHORT, 0, vertices); - data->glDrawArrays(GL_POINTS, 0, count); - SDL_stack_free(vertices); - - return 0; -} - -static int -GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, - int count) -{ - GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - int i; - GLshort *vertices; - - GLES_ActivateRenderer(renderer); - - GLES_SetBlendMode(data, renderer->blendMode); - - data->glColor4f((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); - - vertices = SDL_stack_alloc(GLshort, count*2); - for (i = 0; i < count; ++i) { - vertices[2*i+0] = (GLshort)points[i].x; - vertices[2*i+1] = (GLshort)points[i].y; - } - data->glVertexPointer(2, GL_SHORT, 0, vertices); - if (count > 2 && - points[0].x == points[count-1].x && points[0].y == points[count-1].y) { - /* GL_LINE_LOOP takes care of the final segment */ - --count; - data->glDrawArrays(GL_LINE_LOOP, 0, count); - } else { - data->glDrawArrays(GL_LINE_STRIP, 0, count); - } - SDL_stack_free(vertices); - - return 0; -} - -static int -GLES_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, - int count) -{ - GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - int i; - - GLES_ActivateRenderer(renderer); - - GLES_SetBlendMode(data, renderer->blendMode); - - data->glColor4f((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); - - for (i = 0; i < count; ++i) { - const SDL_Rect *rect = rects[i]; - GLshort minx = rect->x; - GLshort maxx = rect->x + rect->w; - GLshort miny = rect->y; - GLshort maxy = rect->y + rect->h; - GLshort vertices[8]; - vertices[0] = minx; - vertices[1] = miny; - vertices[2] = maxx; - vertices[3] = miny; - vertices[4] = minx; - vertices[5] = maxy; - vertices[6] = maxx; - vertices[7] = maxy; - - data->glVertexPointer(2, GL_SHORT, 0, vertices); - data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - } - - return 0; -} - -static int -GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * srcrect, const SDL_Rect * dstrect) -{ - - GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata; - int minx, miny, maxx, maxy; - GLfloat minu, maxu, minv, maxv; - int i; - void *temp_buffer; /* used for reformatting dirty rect pixels */ - void *temp_ptr; - - GLES_ActivateRenderer(renderer); - - data->glEnable(GL_TEXTURE_2D); - - data->glBindTexture(texturedata->type, texturedata->texture); - - if (texture->modMode) { - data->glColor4f((GLfloat) texture->r * inv255f, - (GLfloat) texture->g * inv255f, - (GLfloat) texture->b * inv255f, - (GLfloat) texture->a * inv255f); - } else { - data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } - - GLES_SetBlendMode(data, texture->blendMode); - - if (data->GL_OES_draw_texture_supported && data->useDrawTexture) { - /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */ - GLint cropRect[4]; - int w, h; - SDL_Window *window = renderer->window; - - SDL_GetWindowSize(window, &w, &h); - cropRect[0] = srcrect->x; - cropRect[1] = srcrect->y + srcrect->h; - cropRect[2] = srcrect->w; - cropRect[3] = -srcrect->h; - data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, - cropRect); - data->glDrawTexiOES(dstrect->x, h - dstrect->y - dstrect->h, 0, - dstrect->w, dstrect->h); - } else { - - minx = dstrect->x; - miny = dstrect->y; - maxx = dstrect->x + dstrect->w; - maxy = dstrect->y + dstrect->h; - - minu = (GLfloat) srcrect->x / texture->w; - minu *= texturedata->texw; - maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; - maxu *= texturedata->texw; - minv = (GLfloat) srcrect->y / texture->h; - minv *= texturedata->texh; - maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; - maxv *= texturedata->texh; - - GLshort vertices[8]; - GLfloat texCoords[8]; - - vertices[0] = minx; - vertices[1] = miny; - vertices[2] = maxx; - vertices[3] = miny; - vertices[4] = minx; - vertices[5] = maxy; - vertices[6] = maxx; - vertices[7] = maxy; - - texCoords[0] = minu; - texCoords[1] = minv; - texCoords[2] = maxu; - texCoords[3] = minv; - texCoords[4] = minu; - texCoords[5] = maxv; - texCoords[6] = maxu; - texCoords[7] = maxv; - - data->glVertexPointer(2, GL_SHORT, 0, vertices); - data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - } - - data->glDisable(GL_TEXTURE_2D); - - return 0; -} - -static void -GLES_RenderPresent(SDL_Renderer * renderer) -{ - GLES_ActivateRenderer(renderer); - - SDL_GL_SwapWindow(renderer->window); -} - -static void -GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; - - GLES_ActivateRenderer(renderer); - - if (!data) { - return; - } - if (data->texture) { - glDeleteTextures(1, &data->texture); - } - if (data->pixels) { - SDL_free(data->pixels); - } - SDL_free(data); - texture->driverdata = NULL; -} - -static void -GLES_DestroyRenderer(SDL_Renderer * renderer) -{ - GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - - if (data) { - if (data->context) { - SDL_GL_DeleteContext(data->context); - } - SDL_free(data); - } - SDL_free(renderer); -} - -#endif /* SDL_VIDEO_RENDER_OGL_ES */ - -/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/software/SDL_render_sw.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/render/software/SDL_render_sw.c Sat Feb 05 12:01:11 2011 -0800 @@ -0,0 +1,418 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "../SDL_sysrender.h" +#include "../../video/SDL_pixels_c.h" + +#include "SDL_draw.h" +#include "SDL_blendfillrect.h" +#include "SDL_blendline.h" +#include "SDL_blendpoint.h" +#include "SDL_drawline.h" +#include "SDL_drawpoint.h" + + +/* SDL surface based renderer implementation */ + +static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags); +static void SW_WindowEvent(SDL_Renderer * renderer, + const SDL_WindowEvent *event); +static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int SW_SetTextureColorMod(SDL_Renderer * renderer, + SDL_Texture * texture); +static int SW_SetTextureAlphaMod(SDL_Renderer * renderer, + SDL_Texture * texture); +static int SW_SetTextureBlendMode(SDL_Renderer * renderer, + SDL_Texture * texture); +static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, + int pitch); +static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch); +static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int SW_RenderDrawPoints(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int SW_RenderDrawLines(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int SW_RenderFillRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, int count); +static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect); +static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, void * pixels, int pitch); +static void SW_RenderPresent(SDL_Renderer * renderer); +static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static void SW_DestroyRenderer(SDL_Renderer * renderer); + + +SDL_RenderDriver SW_RenderDriver = { + SW_CreateRenderer, + { + "software", + 0, + 8, + { + SDL_PIXELFORMAT_RGB555, + SDL_PIXELFORMAT_RGB565, + SDL_PIXELFORMAT_RGB888, + SDL_PIXELFORMAT_BGR888, + SDL_PIXELFORMAT_ARGB8888, + SDL_PIXELFORMAT_RGBA8888, + SDL_PIXELFORMAT_ABGR8888, + SDL_PIXELFORMAT_BGRA8888 + }, + 0, + 0} +}; + +typedef struct +{ + SDL_bool updateSize; + SDL_Surface *surface; +} SW_RenderData; + + +SDL_Renderer * +SW_CreateRendererForSurface(SDL_Surface * surface) +{ + SDL_Renderer *renderer; + SW_RenderData *data; + + if (!surface) { + SDL_SetError("Can't create renderer for NULL surface"); + return NULL; + } + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + + data = (SW_RenderData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + SW_DestroyRenderer(renderer); + SDL_OutOfMemory(); + return NULL; + } + data->surface = surface; + + renderer->WindowEvent = SW_WindowEvent; + renderer->CreateTexture = SW_CreateTexture; + renderer->SetTextureColorMod = SW_SetTextureColorMod; + renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod; + renderer->SetTextureBlendMode = SW_SetTextureBlendMode; + renderer->UpdateTexture = SW_UpdateTexture; + renderer->LockTexture = SW_LockTexture; + renderer->UnlockTexture = SW_UnlockTexture; + renderer->DestroyTexture = SW_DestroyTexture; + renderer->RenderDrawPoints = SW_RenderDrawPoints; + renderer->RenderDrawLines = SW_RenderDrawLines; + renderer->RenderFillRects = SW_RenderFillRects; + renderer->RenderCopy = SW_RenderCopy; + renderer->RenderReadPixels = SW_RenderReadPixels; + renderer->RenderPresent = SW_RenderPresent; + renderer->DestroyRenderer = SW_DestroyRenderer; + renderer->info = SW_RenderDriver.info; + renderer->driverdata = data; + + return renderer; +} + +SDL_Renderer * +SW_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + SDL_Surface *surface; + + surface = SDL_GetWindowSurface(window); + if (!surface) { + return NULL; + } + return SW_CreateRendererForSurface(surface); +} + +static SDL_Surface * +SW_ActivateRenderer(SDL_Renderer * renderer) +{ + SW_RenderData *data = (SW_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + + if (data->updateSize) { + data->surface = SDL_GetWindowSurface(window); + data->updateSize = SDL_FALSE; + } + return data->surface; +} + +static void +SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) +{ + SW_RenderData *data = (SW_RenderData *) renderer->driverdata; + + if (event->event == SDL_WINDOWEVENT_RESIZED) { + data->updateSize = SDL_TRUE; + } +} + +static int +SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (!SDL_PixelFormatEnumToMasks + (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + SDL_SetError("Unknown texture format"); + return -1; + } + + texture->driverdata = + SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask, + Bmask, Amask); + SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g, + texture->b); + SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a); + SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode); + + if (texture->access == SDL_TEXTUREACCESS_STATIC) { + SDL_SetSurfaceRLE(texture->driverdata, 1); + } + + if (!texture->driverdata) { + return -1; + } + return 0; +} + +static int +SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + return SDL_SetSurfaceColorMod(surface, texture->r, texture->g, + texture->b); +} + +static int +SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + return SDL_SetSurfaceAlphaMod(surface, texture->a); +} + +static int +SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + return SDL_SetSurfaceBlendMode(surface, texture->blendMode); +} + +static int +SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, int pitch) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + Uint8 *src, *dst; + int row; + size_t length; + + src = (Uint8 *) pixels; + dst = (Uint8 *) surface->pixels + + rect->y * surface->pitch + + rect->x * surface->format->BytesPerPixel; + length = rect->w * surface->format->BytesPerPixel; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += surface->pitch; + } + return 0; +} + +static int +SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + + *pixels = + (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch + + rect->x * surface->format->BytesPerPixel); + *pitch = surface->pitch; + return 0; +} + +static void +SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ +} + +static int +SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, + int count) +{ + SDL_Surface *surface = SW_ActivateRenderer(renderer); + + if (!surface) { + return -1; + } + + /* Draw the points! */ + if (renderer->blendMode == SDL_BLENDMODE_NONE) { + Uint32 color = SDL_MapRGBA(surface->format, + renderer->r, renderer->g, renderer->b, + renderer->a); + + return SDL_DrawPoints(surface, points, count, color); + } else { + return SDL_BlendPoints(surface, points, count, + renderer->blendMode, + renderer->r, renderer->g, renderer->b, + renderer->a); + } +} + +static int +SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, + int count) +{ + SDL_Surface *surface = SW_ActivateRenderer(renderer); + + if (!surface) { + return -1; + } + + /* Draw the lines! */ + if (renderer->blendMode == SDL_BLENDMODE_NONE) { + Uint32 color = SDL_MapRGBA(surface->format, + renderer->r, renderer->g, renderer->b, + renderer->a); + + return SDL_DrawLines(surface, points, count, color); + } else { + return SDL_BlendLines(surface, points, count, + renderer->blendMode, + renderer->r, renderer->g, renderer->b, + renderer->a); + } +} + +static int +SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, + int count) +{ + SDL_Surface *surface = SW_ActivateRenderer(renderer); + + if (!surface) { + return -1; + } + + if (renderer->blendMode == SDL_BLENDMODE_NONE) { + Uint32 color = SDL_MapRGBA(surface->format, + renderer->r, renderer->g, renderer->b, + renderer->a); + return SDL_FillRects(surface, rects, count, color); + } else { + return SDL_BlendFillRects(surface, rects, count, + renderer->blendMode, + renderer->r, renderer->g, renderer->b, + renderer->a); + } +} + +static int +SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect) +{ + SDL_Surface *surface = SW_ActivateRenderer(renderer); + SDL_Surface *src = (SDL_Surface *) texture->driverdata; + SDL_Rect final_rect = *dstrect; + + if (!surface) { + return -1; + } + return SDL_BlitSurface(src, srcrect, surface, &final_rect); +} + +static int +SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, void * pixels, int pitch) +{ + SDL_Surface *surface = SW_ActivateRenderer(renderer); + Uint32 src_format; + void *src_pixels; + + if (!surface) { + return -1; + } + + if (rect->x < 0 || rect->x+rect->w > surface->w || + rect->y < 0 || rect->y+rect->h > surface->h) { + SDL_SetError("Tried to read outside of surface bounds"); + return -1; + } + + src_format = SDL_MasksToPixelFormatEnum( + surface->format->BitsPerPixel, + surface->format->Rmask, surface->format->Gmask, + surface->format->Bmask, surface->format->Amask); + + src_pixels = (void*)((Uint8 *) surface->pixels + + rect->y * surface->pitch + + rect->x * surface->format->BytesPerPixel); + + return SDL_ConvertPixels(rect->w, rect->h, + src_format, src_pixels, surface->pitch, + format, pixels, pitch); +} + +static void +SW_RenderPresent(SDL_Renderer * renderer) +{ + SW_RenderData *data = (SW_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + + if (window) { + SDL_UpdateWindowSurface(window); + } +} + +static void +SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + + SDL_FreeSurface(surface); +} + +static void +SW_DestroyRenderer(SDL_Renderer * renderer) +{ + SW_RenderData *data = (SW_RenderData *) renderer->driverdata; + + if (data) { + SDL_free(data); + } + SDL_free(renderer); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/software/SDL_render_sw_c.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/render/software/SDL_render_sw_c.h Sat Feb 05 12:01:11 2011 -0800 @@ -0,0 +1,25 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +extern SDL_Renderer * SW_CreateRendererForSurface(SDL_Surface * surface); + +/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/software/SDL_renderer_sw.c --- a/src/render/software/SDL_renderer_sw.c Sat Feb 05 11:54:46 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,418 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2010 Sam Lantinga - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ -#include "SDL_config.h" - -#include "../SDL_sysrender.h" -#include "../../video/SDL_pixels_c.h" - -#include "SDL_draw.h" -#include "SDL_blendfillrect.h" -#include "SDL_blendline.h" -#include "SDL_blendpoint.h" -#include "SDL_drawline.h" -#include "SDL_drawpoint.h" - - -/* SDL surface based renderer implementation */ - -static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags); -static void SW_WindowEvent(SDL_Renderer * renderer, - const SDL_WindowEvent *event); -static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static int SW_SetTextureColorMod(SDL_Renderer * renderer, - SDL_Texture * texture); -static int SW_SetTextureAlphaMod(SDL_Renderer * renderer, - SDL_Texture * texture); -static int SW_SetTextureBlendMode(SDL_Renderer * renderer, - SDL_Texture * texture); -static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, const void *pixels, - int pitch); -static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, void **pixels, int *pitch); -static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static int SW_RenderDrawPoints(SDL_Renderer * renderer, - const SDL_Point * points, int count); -static int SW_RenderDrawLines(SDL_Renderer * renderer, - const SDL_Point * points, int count); -static int SW_RenderFillRects(SDL_Renderer * renderer, - const SDL_Rect ** rects, int count); -static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * srcrect, const SDL_Rect * dstrect); -static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - Uint32 format, void * pixels, int pitch); -static void SW_RenderPresent(SDL_Renderer * renderer); -static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); -static void SW_DestroyRenderer(SDL_Renderer * renderer); - - -SDL_RenderDriver SW_RenderDriver = { - SW_CreateRenderer, - { - "software", - 0, - 8, - { - SDL_PIXELFORMAT_RGB555, - SDL_PIXELFORMAT_RGB565, - SDL_PIXELFORMAT_RGB888, - SDL_PIXELFORMAT_BGR888, - SDL_PIXELFORMAT_ARGB8888, - SDL_PIXELFORMAT_RGBA8888, - SDL_PIXELFORMAT_ABGR8888, - SDL_PIXELFORMAT_BGRA8888 - }, - 0, - 0} -}; - -typedef struct -{ - SDL_bool updateSize; - SDL_Surface *surface; -} SW_RenderData; - - -SDL_Renderer * -SW_CreateRendererForSurface(SDL_Surface * surface) -{ - SDL_Renderer *renderer; - SW_RenderData *data; - - if (!surface) { - SDL_SetError("Can't create renderer for NULL surface"); - return NULL; - } - - renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); - if (!renderer) { - SDL_OutOfMemory(); - return NULL; - } - - data = (SW_RenderData *) SDL_calloc(1, sizeof(*data)); - if (!data) { - SW_DestroyRenderer(renderer); - SDL_OutOfMemory(); - return NULL; - } - data->surface = surface; - - renderer->WindowEvent = SW_WindowEvent; - renderer->CreateTexture = SW_CreateTexture; - renderer->SetTextureColorMod = SW_SetTextureColorMod; - renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod; - renderer->SetTextureBlendMode = SW_SetTextureBlendMode; - renderer->UpdateTexture = SW_UpdateTexture; - renderer->LockTexture = SW_LockTexture; - renderer->UnlockTexture = SW_UnlockTexture; - renderer->DestroyTexture = SW_DestroyTexture; - renderer->RenderDrawPoints = SW_RenderDrawPoints; - renderer->RenderDrawLines = SW_RenderDrawLines; - renderer->RenderFillRects = SW_RenderFillRects; - renderer->RenderCopy = SW_RenderCopy; - renderer->RenderReadPixels = SW_RenderReadPixels; - renderer->RenderPresent = SW_RenderPresent; - renderer->DestroyRenderer = SW_DestroyRenderer; - renderer->info = SW_RenderDriver.info; - renderer->driverdata = data; - - return renderer; -} - -SDL_Renderer * -SW_CreateRenderer(SDL_Window * window, Uint32 flags) -{ - SDL_Surface *surface; - - surface = SDL_GetWindowSurface(window); - if (!surface) { - return NULL; - } - return SW_CreateRendererForSurface(surface); -} - -static SDL_Surface * -SW_ActivateRenderer(SDL_Renderer * renderer) -{ - SW_RenderData *data = (SW_RenderData *) renderer->driverdata; - SDL_Window *window = renderer->window; - - if (data->updateSize) { - data->surface = SDL_GetWindowSurface(window); - data->updateSize = SDL_FALSE; - } - return data->surface; -} - -static void -SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) -{ - SW_RenderData *data = (SW_RenderData *) renderer->driverdata; - - if (event->event == SDL_WINDOWEVENT_RESIZED) { - data->updateSize = SDL_TRUE; - } -} - -static int -SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - int bpp; - Uint32 Rmask, Gmask, Bmask, Amask; - - if (!SDL_PixelFormatEnumToMasks - (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { - SDL_SetError("Unknown texture format"); - return -1; - } - - texture->driverdata = - SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask, - Bmask, Amask); - SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g, - texture->b); - SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a); - SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode); - - if (texture->access == SDL_TEXTUREACCESS_STATIC) { - SDL_SetSurfaceRLE(texture->driverdata, 1); - } - - if (!texture->driverdata) { - return -1; - } - return 0; -} - -static int -SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) -{ - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - return SDL_SetSurfaceColorMod(surface, texture->r, texture->g, - texture->b); -} - -static int -SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) -{ - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - return SDL_SetSurfaceAlphaMod(surface, texture->a); -} - -static int -SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) -{ - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - return SDL_SetSurfaceBlendMode(surface, texture->blendMode); -} - -static int -SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, const void *pixels, int pitch) -{ - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - Uint8 *src, *dst; - int row; - size_t length; - - src = (Uint8 *) pixels; - dst = (Uint8 *) surface->pixels + - rect->y * surface->pitch + - rect->x * surface->format->BytesPerPixel; - length = rect->w * surface->format->BytesPerPixel; - for (row = 0; row < rect->h; ++row) { - SDL_memcpy(dst, src, length); - src += pitch; - dst += surface->pitch; - } - return 0; -} - -static int -SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * rect, void **pixels, int *pitch) -{ - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - - *pixels = - (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch + - rect->x * surface->format->BytesPerPixel); - *pitch = surface->pitch; - return 0; -} - -static void -SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ -} - -static int -SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, - int count) -{ - SDL_Surface *surface = SW_ActivateRenderer(renderer); - - if (!surface) { - return -1; - } - - /* Draw the points! */ - if (renderer->blendMode == SDL_BLENDMODE_NONE) { - Uint32 color = SDL_MapRGBA(surface->format, - renderer->r, renderer->g, renderer->b, - renderer->a); - - return SDL_DrawPoints(surface, points, count, color); - } else { - return SDL_BlendPoints(surface, points, count, - renderer->blendMode, - renderer->r, renderer->g, renderer->b, - renderer->a); - } -} - -static int -SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, - int count) -{ - SDL_Surface *surface = SW_ActivateRenderer(renderer); - - if (!surface) { - return -1; - } - - /* Draw the lines! */ - if (renderer->blendMode == SDL_BLENDMODE_NONE) { - Uint32 color = SDL_MapRGBA(surface->format, - renderer->r, renderer->g, renderer->b, - renderer->a); - - return SDL_DrawLines(surface, points, count, color); - } else { - return SDL_BlendLines(surface, points, count, - renderer->blendMode, - renderer->r, renderer->g, renderer->b, - renderer->a); - } -} - -static int -SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, - int count) -{ - SDL_Surface *surface = SW_ActivateRenderer(renderer); - - if (!surface) { - return -1; - } - - if (renderer->blendMode == SDL_BLENDMODE_NONE) { - Uint32 color = SDL_MapRGBA(surface->format, - renderer->r, renderer->g, renderer->b, - renderer->a); - return SDL_FillRects(surface, rects, count, color); - } else { - return SDL_BlendFillRects(surface, rects, count, - renderer->blendMode, - renderer->r, renderer->g, renderer->b, - renderer->a); - } -} - -static int -SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, - const SDL_Rect * srcrect, const SDL_Rect * dstrect) -{ - SDL_Surface *surface = SW_ActivateRenderer(renderer); - SDL_Surface *src = (SDL_Surface *) texture->driverdata; - SDL_Rect final_rect = *dstrect; - - if (!surface) { - return -1; - } - return SDL_BlitSurface(src, srcrect, surface, &final_rect); -} - -static int -SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, - Uint32 format, void * pixels, int pitch) -{ - SDL_Surface *surface = SW_ActivateRenderer(renderer); - Uint32 src_format; - void *src_pixels; - - if (!surface) { - return -1; - } - - if (rect->x < 0 || rect->x+rect->w > surface->w || - rect->y < 0 || rect->y+rect->h > surface->h) { - SDL_SetError("Tried to read outside of surface bounds"); - return -1; - } - - src_format = SDL_MasksToPixelFormatEnum( - surface->format->BitsPerPixel, - surface->format->Rmask, surface->format->Gmask, - surface->format->Bmask, surface->format->Amask); - - src_pixels = (void*)((Uint8 *) surface->pixels + - rect->y * surface->pitch + - rect->x * surface->format->BytesPerPixel); - - return SDL_ConvertPixels(rect->w, rect->h, - src_format, src_pixels, surface->pitch, - format, pixels, pitch); -} - -static void -SW_RenderPresent(SDL_Renderer * renderer) -{ - SW_RenderData *data = (SW_RenderData *) renderer->driverdata; - SDL_Window *window = renderer->window; - - if (window) { - SDL_UpdateWindowSurface(window); - } -} - -static void -SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - - SDL_FreeSurface(surface); -} - -static void -SW_DestroyRenderer(SDL_Renderer * renderer) -{ - SW_RenderData *data = (SW_RenderData *) renderer->driverdata; - - if (data) { - SDL_free(data); - } - SDL_free(renderer); -} - -/* vi: set ts=4 sw=4 expandtab: */ diff -r 69f47f2c1856 -r bb45ecd958d8 src/render/software/SDL_renderer_sw_c.h --- a/src/render/software/SDL_renderer_sw_c.h Sat Feb 05 11:54:46 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2010 Sam Lantinga - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ - -extern SDL_Renderer * SW_CreateRendererForSurface(SDL_Surface * surface); - -/* vi: set ts=4 sw=4 expandtab: */