| /* |
| SDL - Simple DirectMedia Layer |
| Copyright (C) 1997-2006 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_video.h" |
| #include "SDL_opengl.h" |
| #include "SDL_sysvideo.h" |
| #include "SDL_pixels_c.h" |
| #include "SDL_rect_c.h" |
| #include "SDL_yuv_sw_c.h" |
| |
| /* OpenGL renderer implementation */ |
| |
| static const float inv255f = 1.0f / 255.0f; |
| |
| static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags); |
| static int GL_ActivateRenderer(SDL_Renderer * renderer); |
| static int GL_DisplayModeChanged(SDL_Renderer * renderer); |
| static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); |
| static int GL_SetTexturePalette(SDL_Renderer * renderer, |
| SDL_Texture * texture, |
| const SDL_Color * colors, int firstcolor, |
| int ncolors); |
| static int GL_GetTexturePalette(SDL_Renderer * renderer, |
| SDL_Texture * texture, SDL_Color * colors, |
| int firstcolor, int ncolors); |
| static int GL_SetTextureColorMod(SDL_Renderer * renderer, |
| SDL_Texture * texture); |
| static int GL_SetTextureAlphaMod(SDL_Renderer * renderer, |
| SDL_Texture * texture); |
| static int GL_SetTextureBlendMode(SDL_Renderer * renderer, |
| SDL_Texture * texture); |
| static int GL_SetTextureScaleMode(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, int markDirty, void **pixels, |
| int *pitch); |
| static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); |
| static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
| int numrects, const SDL_Rect * rects); |
| static int GL_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, |
| Uint8 a, const SDL_Rect * rect); |
| static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, |
| const SDL_Rect * srcrect, const SDL_Rect * dstrect); |
| 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_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD | |
| SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), |
| (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR | |
| SDL_TEXTUREMODULATE_ALPHA), |
| (SDL_TEXTUREBLENDMODE_NONE | SDL_TEXTUREBLENDMODE_MASK | |
| SDL_TEXTUREBLENDMODE_BLEND | SDL_TEXTUREBLENDMODE_ADD | |
| SDL_TEXTUREBLENDMODE_MOD), |
| (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST | |
| SDL_TEXTURESCALEMODE_SLOW), |
| 16, |
| { |
| SDL_PIXELFORMAT_INDEX1LSB, |
| SDL_PIXELFORMAT_INDEX1MSB, |
| SDL_PIXELFORMAT_INDEX8, |
| SDL_PIXELFORMAT_RGB332, |
| SDL_PIXELFORMAT_RGB444, |
| SDL_PIXELFORMAT_RGB555, |
| SDL_PIXELFORMAT_ARGB4444, |
| SDL_PIXELFORMAT_ARGB1555, |
| SDL_PIXELFORMAT_RGB565, |
| SDL_PIXELFORMAT_RGB24, |
| SDL_PIXELFORMAT_BGR24, |
| SDL_PIXELFORMAT_RGB888, |
| SDL_PIXELFORMAT_BGR888, |
| SDL_PIXELFORMAT_ARGB8888, |
| SDL_PIXELFORMAT_ABGR8888, |
| SDL_PIXELFORMAT_ARGB2101010}, |
| 0, |
| 0} |
| }; |
| |
| typedef struct |
| { |
| SDL_GLContext context; |
| SDL_bool updateSize; |
| SDL_bool GL_EXT_paletted_texture_supported; |
| SDL_bool GL_ARB_texture_rectangle_supported; |
| int blendMode; |
| int scaleMode; |
| |
| /* OpenGL functions */ |
| #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; |
| #include "SDL_glfuncs.h" |
| #undef SDL_PROC |
| |
| PFNGLCOLORTABLEEXTPROC glColorTableEXT; |
| } GL_RenderData; |
| |
| typedef struct |
| { |
| GLuint texture; |
| GLenum type; |
| GLfloat texw; |
| GLfloat texh; |
| GLenum format; |
| GLenum formattype; |
| Uint8 *palette; |
| void *pixels; |
| int pitch; |
| SDL_DirtyRectList dirty; |
| } 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) |
| { |
| #if defined(__QNXNTO__) && (_NTO_VERSION < 630) |
| #define __SDL_NOGETPROCADDR__ |
| #elif defined(__MINT__) |
| #define __SDL_NOGETPROCADDR__ |
| #endif |
| #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 "SDL_glfuncs.h" |
| #undef SDL_PROC |
| return 0; |
| } |
| |
| void |
| GL_AddRenderDriver(_THIS) |
| { |
| if (_this->GL_CreateContext) { |
| SDL_AddRenderDriver(0, &GL_RenderDriver); |
| } |
| } |
| |
| SDL_Renderer * |
| GL_CreateRenderer(SDL_Window * window, Uint32 flags) |
| { |
| SDL_Renderer *renderer; |
| GL_RenderData *data; |
| GLint value; |
| int doublebuffer; |
| |
| /* Render directly to the window, unless we're compositing */ |
| #ifndef __MACOSX__ |
| if (flags & SDL_RENDERER_SINGLEBUFFER) { |
| SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0); |
| } |
| #endif |
| 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->ActivateRenderer = GL_ActivateRenderer; |
| renderer->DisplayModeChanged = GL_DisplayModeChanged; |
| renderer->CreateTexture = GL_CreateTexture; |
| renderer->SetTexturePalette = GL_SetTexturePalette; |
| renderer->GetTexturePalette = GL_GetTexturePalette; |
| renderer->SetTextureColorMod = GL_SetTextureColorMod; |
| renderer->SetTextureAlphaMod = GL_SetTextureAlphaMod; |
| renderer->SetTextureBlendMode = GL_SetTextureBlendMode; |
| renderer->SetTextureScaleMode = GL_SetTextureScaleMode; |
| renderer->UpdateTexture = GL_UpdateTexture; |
| renderer->LockTexture = GL_LockTexture; |
| renderer->UnlockTexture = GL_UnlockTexture; |
| renderer->DirtyTexture = GL_DirtyTexture; |
| renderer->RenderFill = GL_RenderFill; |
| renderer->RenderCopy = GL_RenderCopy; |
| renderer->RenderPresent = GL_RenderPresent; |
| renderer->DestroyTexture = GL_DestroyTexture; |
| renderer->DestroyRenderer = GL_DestroyRenderer; |
| renderer->info = GL_RenderDriver.info; |
| renderer->window = window->id; |
| renderer->driverdata = data; |
| |
| renderer->info.flags = |
| (SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED); |
| |
| if (GL_LoadFunctions(data) < 0) { |
| GL_DestroyRenderer(renderer); |
| return NULL; |
| } |
| |
| data->context = SDL_GL_CreateContext(window->id); |
| if (!data->context) { |
| GL_DestroyRenderer(renderer); |
| return NULL; |
| } |
| if (SDL_GL_MakeCurrent(window->id, data->context) < 0) { |
| GL_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_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doublebuffer) == 0) { |
| if (!doublebuffer) { |
| renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER; |
| } |
| } |
| |
| 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_EXT_paletted_texture")) { |
| data->GL_EXT_paletted_texture_supported = SDL_TRUE; |
| data->glColorTableEXT = |
| (PFNGLCOLORTABLEEXTPROC) SDL_GL_GetProcAddress("glColorTableEXT"); |
| } else { |
| /* Don't advertise support for 8-bit indexed texture format */ |
| Uint32 i, j; |
| SDL_RendererInfo *info = &renderer->info; |
| for (i = 0, j = 0; i < info->num_texture_formats; ++i) { |
| if (info->texture_formats[i] != SDL_PIXELFORMAT_INDEX8) { |
| info->texture_formats[j++] = info->texture_formats[i]; |
| } |
| } |
| --info->num_texture_formats; |
| } |
| |
| /* Set up parameters for rendering */ |
| data->blendMode = -1; |
| data->scaleMode = -1; |
| data->glDisable(GL_DEPTH_TEST); |
| data->glDisable(GL_CULL_FACE); |
| 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 int |
| GL_ActivateRenderer(SDL_Renderer * renderer) |
| { |
| GL_RenderData *data = (GL_RenderData *) renderer->driverdata; |
| SDL_Window *window = SDL_GetWindowFromID(renderer->window); |
| |
| if (SDL_GL_MakeCurrent(window->id, data->context) < 0) { |
| return -1; |
| } |
| if (data->updateSize) { |
| data->glMatrixMode(GL_PROJECTION); |
| data->glLoadIdentity(); |
| data->glMatrixMode(GL_MODELVIEW); |
| data->glLoadIdentity(); |
| data->glViewport(0, 0, window->w, window->h); |
| data->glOrtho(0.0, (GLdouble) window->w, (GLdouble) window->h, 0.0, |
| 0.0, 1.0); |
| data->updateSize = SDL_FALSE; |
| } |
| return 0; |
| } |
| |
| static int |
| GL_DisplayModeChanged(SDL_Renderer * renderer) |
| { |
| GL_RenderData *data = (GL_RenderData *) renderer->driverdata; |
| |
| data->updateSize = SDL_TRUE; |
| return 0; |
| } |
| |
| static __inline__ int |
| power_of_2(int input) |
| { |
| int value = 1; |
| |
| while (value < input) { |
| value <<= 1; |
| } |
| return value; |
| } |
| |
| static int |
| GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) |
| { |
| GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; |
| SDL_Window *window = SDL_GetWindowFromID(renderer->window); |
| GL_TextureData *data; |
| GLint internalFormat; |
| GLenum format, type; |
| int texture_w, texture_h; |
| GLenum result; |
| |
| switch (texture->format) { |
| case SDL_PIXELFORMAT_INDEX1LSB: |
| case SDL_PIXELFORMAT_INDEX1MSB: |
| internalFormat = GL_RGB; |
| format = GL_COLOR_INDEX; |
| type = GL_BITMAP; |
| break; |
| case SDL_PIXELFORMAT_INDEX8: |
| if (!renderdata->GL_EXT_paletted_texture_supported) { |
| SDL_SetError("Unsupported texture format"); |
| return -1; |
| } |
| internalFormat = GL_COLOR_INDEX8_EXT; |
| format = GL_COLOR_INDEX; |
| type = GL_UNSIGNED_BYTE; |
| break; |
| case SDL_PIXELFORMAT_RGB332: |
| internalFormat = GL_R3_G3_B2; |
| format = GL_RGB; |
| type = GL_UNSIGNED_BYTE_3_3_2; |
| break; |
| case SDL_PIXELFORMAT_RGB444: |
| internalFormat = GL_RGB4; |
| format = GL_RGB; |
| type = GL_UNSIGNED_SHORT_4_4_4_4; |
| break; |
| case SDL_PIXELFORMAT_RGB555: |
| internalFormat = GL_RGB5; |
| format = GL_RGB; |
| type = GL_UNSIGNED_SHORT_5_5_5_1; |
| break; |
| case SDL_PIXELFORMAT_ARGB4444: |
| internalFormat = GL_RGBA4; |
| format = GL_BGRA; |
| type = GL_UNSIGNED_SHORT_4_4_4_4_REV; |
| break; |
| case SDL_PIXELFORMAT_ARGB1555: |
| internalFormat = GL_RGB5_A1; |
| format = GL_BGRA; |
| type = GL_UNSIGNED_SHORT_1_5_5_5_REV; |
| break; |
| case SDL_PIXELFORMAT_RGB565: |
| internalFormat = GL_RGB8; |
| format = GL_RGB; |
| type = GL_UNSIGNED_SHORT_5_6_5; |
| break; |
| case SDL_PIXELFORMAT_RGB24: |
| internalFormat = GL_RGB8; |
| format = GL_RGB; |
| type = GL_UNSIGNED_BYTE; |
| break; |
| case SDL_PIXELFORMAT_RGB888: |
| internalFormat = GL_RGB8; |
| format = GL_BGRA; |
| type = GL_UNSIGNED_BYTE; |
| break; |
| case SDL_PIXELFORMAT_BGR24: |
| internalFormat = GL_RGB8; |
| format = GL_BGR; |
| type = GL_UNSIGNED_BYTE; |
| break; |
| case SDL_PIXELFORMAT_BGR888: |
| internalFormat = GL_RGB8; |
| format = GL_RGBA; |
| type = GL_UNSIGNED_BYTE; |
| break; |
| case SDL_PIXELFORMAT_ARGB8888: |
| internalFormat = GL_RGBA8; |
| format = GL_BGRA; |
| type = GL_UNSIGNED_BYTE; |
| break; |
| case SDL_PIXELFORMAT_ABGR8888: |
| internalFormat = GL_RGBA8; |
| format = GL_RGBA; |
| type = GL_UNSIGNED_BYTE; |
| break; |
| case SDL_PIXELFORMAT_ARGB2101010: |
| internalFormat = GL_RGB10_A2; |
| format = GL_BGRA; |
| type = GL_UNSIGNED_INT_2_10_10_10_REV; |
| break; |
| default: |
| SDL_SetError("Unsupported texture format"); |
| return -1; |
| } |
| |
| data = (GL_TextureData *) SDL_calloc(1, sizeof(*data)); |
| if (!data) { |
| SDL_OutOfMemory(); |
| return -1; |
| } |
| |
| if (texture->format == SDL_PIXELFORMAT_INDEX8) { |
| data->palette = (Uint8 *) SDL_malloc(3 * 256 * sizeof(Uint8)); |
| if (!data->palette) { |
| SDL_OutOfMemory(); |
| SDL_free(data); |
| return -1; |
| } |
| SDL_memset(data->palette, 0xFF, 3 * 256 * sizeof(Uint8)); |
| } |
| |
| 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->glBindTexture(data->type, data->texture); |
| renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, |
| texture_h, 0, format, type, NULL); |
| result = renderdata->glGetError(); |
| if (result != GL_NO_ERROR) { |
| GL_SetError("glTexImage2D()", result); |
| return -1; |
| } |
| return 0; |
| } |
| |
| static int |
| GL_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, |
| const SDL_Color * colors, int firstcolor, int ncolors) |
| { |
| GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; |
| GL_TextureData *data = (GL_TextureData *) texture->driverdata; |
| Uint8 *palette; |
| |
| if (!data->palette) { |
| SDL_SetError("Texture doesn't have a palette"); |
| return -1; |
| } |
| palette = data->palette + firstcolor * 3; |
| while (ncolors--) { |
| *palette++ = colors->r; |
| *palette++ = colors->g; |
| *palette++ = colors->b; |
| ++colors; |
| } |
| renderdata->glBindTexture(data->type, data->texture); |
| renderdata->glColorTableEXT(data->type, GL_RGB8, 256, GL_RGB, |
| GL_UNSIGNED_BYTE, data->palette); |
| return 0; |
| } |
| |
| static int |
| GL_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, |
| SDL_Color * colors, int firstcolor, int ncolors) |
| { |
| GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; |
| GL_TextureData *data = (GL_TextureData *) texture->driverdata; |
| Uint8 *palette; |
| |
| if (!data->palette) { |
| SDL_SetError("Texture doesn't have a palette"); |
| return -1; |
| } |
| palette = data->palette + firstcolor * 3; |
| while (ncolors--) { |
| colors->r = *palette++; |
| colors->g = *palette++; |
| colors->b = *palette++; |
| colors->unused = SDL_ALPHA_OPAQUE; |
| ++colors; |
| } |
| return 0; |
| } |
| |
| static void |
| SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture, |
| int pitch) |
| { |
| if (texture->format == SDL_PIXELFORMAT_INDEX1LSB) { |
| renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 1); |
| } else if (texture->format == SDL_PIXELFORMAT_INDEX1MSB) { |
| renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 0); |
| } |
| renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, |
| pitch / SDL_BYTESPERPIXEL(texture->format)); |
| } |
| |
| static int |
| GL_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) |
| { |
| return 0; |
| } |
| |
| static int |
| GL_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) |
| { |
| return 0; |
| } |
| |
| static int |
| GL_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) |
| { |
| switch (texture->blendMode) { |
| case SDL_TEXTUREBLENDMODE_NONE: |
| case SDL_TEXTUREBLENDMODE_MASK: |
| case SDL_TEXTUREBLENDMODE_BLEND: |
| case SDL_TEXTUREBLENDMODE_ADD: |
| case SDL_TEXTUREBLENDMODE_MOD: |
| return 0; |
| default: |
| SDL_Unsupported(); |
| texture->blendMode = SDL_TEXTUREBLENDMODE_NONE; |
| return -1; |
| } |
| } |
| |
| static int |
| GL_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) |
| { |
| switch (texture->scaleMode) { |
| case SDL_TEXTURESCALEMODE_NONE: |
| case SDL_TEXTURESCALEMODE_FAST: |
| case SDL_TEXTURESCALEMODE_SLOW: |
| return 0; |
| case SDL_TEXTURESCALEMODE_BEST: |
| SDL_Unsupported(); |
| texture->scaleMode = SDL_TEXTURESCALEMODE_SLOW; |
| return -1; |
| default: |
| SDL_Unsupported(); |
| texture->scaleMode = SDL_TEXTURESCALEMODE_NONE; |
| return -1; |
| } |
| } |
| |
| 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; |
| |
| renderdata->glGetError(); |
| SetupTextureUpdate(renderdata, texture, pitch); |
| renderdata->glBindTexture(data->type, data->texture); |
| renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, |
| rect->h, data->format, data->formattype, |
| pixels); |
| 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, int markDirty, void **pixels, |
| int *pitch) |
| { |
| GL_TextureData *data = (GL_TextureData *) texture->driverdata; |
| |
| if (!data->pixels) { |
| data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); |
| data->pixels = SDL_malloc(texture->h * data->pitch); |
| if (!data->pixels) { |
| SDL_OutOfMemory(); |
| return -1; |
| } |
| } |
| |
| if (markDirty) { |
| SDL_AddDirtyRect(&data->dirty, rect); |
| } |
| |
| *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) |
| { |
| } |
| |
| static void |
| GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects, |
| const SDL_Rect * rects) |
| { |
| GL_TextureData *data = (GL_TextureData *) texture->driverdata; |
| int i; |
| |
| for (i = 0; i < numrects; ++i) { |
| SDL_AddDirtyRect(&data->dirty, &rects[i]); |
| } |
| } |
| |
| static int |
| GL_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a, |
| const SDL_Rect * rect) |
| { |
| GL_RenderData *data = (GL_RenderData *) renderer->driverdata; |
| SDL_Window *window = SDL_GetWindowFromID(renderer->window); |
| |
| data->glClearColor((GLclampf) r * inv255f, (GLclampf) g * inv255f, |
| (GLclampf) b * inv255f, (GLclampf) a * inv255f); |
| data->glViewport(rect->x, window->h - rect->y, rect->w, rect->h); |
| data->glClear(GL_COLOR_BUFFER_BIT); |
| data->glViewport(0, 0, window->w, window->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; |
| |
| if (texturedata->dirty.count > 0) { |
| SDL_DirtyRect *dirty; |
| void *pixels; |
| int bpp = SDL_BYTESPERPIXEL(texture->format); |
| int pitch = texturedata->pitch; |
| |
| SetupTextureUpdate(data, texture, pitch); |
| data->glBindTexture(texturedata->type, texturedata->texture); |
| for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) { |
| SDL_Rect *rect = &dirty->rect; |
| pixels = |
| (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch + |
| rect->x * bpp); |
| data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y, |
| rect->w, rect->h, texturedata->format, |
| texturedata->formattype, pixels); |
| } |
| SDL_ClearDirtyRects(&texturedata->dirty); |
| } |
| |
| 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->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); |
| } |
| |
| if (texture->blendMode != data->blendMode) { |
| switch (texture->blendMode) { |
| case SDL_TEXTUREBLENDMODE_NONE: |
| data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); |
| data->glDisable(GL_BLEND); |
| break; |
| case SDL_TEXTUREBLENDMODE_MASK: |
| case SDL_TEXTUREBLENDMODE_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_TEXTUREBLENDMODE_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_TEXTUREBLENDMODE_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 = texture->blendMode; |
| } |
| |
| if (texture->scaleMode != data->scaleMode) { |
| switch (texture->scaleMode) { |
| case SDL_TEXTURESCALEMODE_NONE: |
| case SDL_TEXTURESCALEMODE_FAST: |
| data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER, |
| GL_NEAREST); |
| data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER, |
| GL_NEAREST); |
| break; |
| case SDL_TEXTURESCALEMODE_SLOW: |
| case SDL_TEXTURESCALEMODE_BEST: |
| data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER, |
| GL_LINEAR); |
| data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER, |
| GL_LINEAR); |
| break; |
| } |
| data->scaleMode = texture->scaleMode; |
| } |
| |
| data->glBegin(GL_TRIANGLE_STRIP); |
| data->glTexCoord2f(minu, minv); |
| data->glVertex2i(minx, miny); |
| data->glTexCoord2f(maxu, minv); |
| data->glVertex2i(maxx, miny); |
| data->glTexCoord2f(minu, maxv); |
| data->glVertex2i(minx, maxy); |
| data->glTexCoord2f(maxu, maxv); |
| data->glVertex2i(maxx, maxy); |
| data->glEnd(); |
| |
| return 0; |
| } |
| |
| static void |
| GL_RenderPresent(SDL_Renderer * 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; |
| |
| if (!data) { |
| return; |
| } |
| if (data->texture) { |
| renderdata->glDeleteTextures(1, &data->texture); |
| } |
| if (data->palette) { |
| SDL_free(data->palette); |
| } |
| if (data->pixels) { |
| SDL_free(data->pixels); |
| } |
| SDL_FreeDirtyRects(&data->dirty); |
| 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); |
| SDL_GL_DeleteContext(data->context); |
| } |
| SDL_free(data); |
| } |
| SDL_free(renderer); |
| } |
| |
| #endif /* SDL_VIDEO_RENDER_OGL */ |
| |
| /* vi: set ts=4 sw=4 expandtab: */ |