# HG changeset patch # User Holmes Futrell # Date 1215735736 0 # Node ID 69dd5af09ff18d5e79df4bf3b86f827a15c6244e # Parent 80ceefc00adaf1c22336decf4301e893a7174871 diff -r 80ceefc00ada -r 69dd5af09ff1 src/video/SDL_renderer_gl.c --- a/src/video/SDL_renderer_gl.c Fri Jul 11 00:21:45 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,960 +0,0 @@ -/* - 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" - -#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 -*/ - -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_QueryTexturePixels(SDL_Renderer * renderer, - SDL_Texture * texture, void **pixels, - int *pitch); -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_ARB_texture_rectangle_supported; - SDL_bool GL_EXT_paletted_texture_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; - 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; - 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->QueryTexturePixels = GL_QueryTexturePixels; - 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; - } -#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; - } - - 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; - } - 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->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: -#ifdef __MACOSX__ - internalFormat = GL_RGBA; - format = GL_BGRA; - type = GL_UNSIGNED_INT_8_8_8_8_REV; -#else - internalFormat = GL_RGBA8; - format = GL_BGRA; - type = GL_UNSIGNED_BYTE; -#endif - 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)); - } - - 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->glBindTexture(data->type, data->texture); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, - GL_NEAREST); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, - GL_NEAREST); - 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) { - /* - if (renderdata->glTextureRangeAPPLE) { - renderdata->glTextureRangeAPPLE(data->type, - texture->h * data->pitch, - data->pixels); - } - */ - 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); - } - result = renderdata->glGetError(); - if (result != GL_NO_ERROR) { - GL_SetError("glTexImage2D()", result); - return -1; - } - return 0; -} - -static int -GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, - void **pixels, int *pitch) -{ - GL_TextureData *data = (GL_TextureData *) texture->driverdata; - - *pixels = data->pixels; - *pitch = data->pitch; - 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 (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.list) { - 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); *//* 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 80ceefc00ada -r 69dd5af09ff1 src/video/glrenderer/SDL_renderer_gl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/glrenderer/SDL_renderer_gl.c Fri Jul 11 00:22:16 2008 +0000 @@ -0,0 +1,960 @@ +/* + 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" + +#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 +*/ + +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_QueryTexturePixels(SDL_Renderer * renderer, + SDL_Texture * texture, void **pixels, + int *pitch); +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_ARB_texture_rectangle_supported; + SDL_bool GL_EXT_paletted_texture_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; + 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; + 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->QueryTexturePixels = GL_QueryTexturePixels; + 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; + } +#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; + } + + 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; + } + 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->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: +#ifdef __MACOSX__ + internalFormat = GL_RGBA; + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; +#else + internalFormat = GL_RGBA8; + format = GL_BGRA; + type = GL_UNSIGNED_BYTE; +#endif + 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)); + } + + 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->glBindTexture(data->type, data->texture); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, + GL_NEAREST); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, + GL_NEAREST); + 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) { + /* + if (renderdata->glTextureRangeAPPLE) { + renderdata->glTextureRangeAPPLE(data->type, + texture->h * data->pitch, + data->pixels); + } + */ + 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); + } + result = renderdata->glGetError(); + if (result != GL_NO_ERROR) { + GL_SetError("glTexImage2D()", result); + return -1; + } + return 0; +} + +static int +GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, + void **pixels, int *pitch) +{ + GL_TextureData *data = (GL_TextureData *) texture->driverdata; + + *pixels = data->pixels; + *pitch = data->pitch; + 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 (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.list) { + 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); *//* 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: */