src/render/opengl/SDL_render_gl.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 08 Feb 2011 22:40:19 -0800
changeset 5233 ce4f91138031
parent 5230 8efa43b915be
child 5262 b530ef003506
permissions -rw-r--r--
Added a hint to control whether the OpenGL driver uses shaders.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
    25 
    26 #include "SDL_hints.h"
    27 #include "SDL_log.h"
    28 #include "SDL_opengl.h"
    29 #include "../SDL_sysrender.h"
    30 #include "SDL_shaders_gl.h"
    31 
    32 #ifdef __MACOSX__
    33 #include <OpenGL/OpenGL.h>
    34 #endif
    35 
    36 
    37 /* OpenGL renderer implementation */
    38 
    39 /* Details on optimizing the texture path on Mac OS X:
    40    http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
    41 */
    42 
    43 /* Used to re-create the window with OpenGL capability */
    44 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    45 
    46 static const float inv255f = 1.0f / 255.0f;
    47 
    48 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    49 static void GL_WindowEvent(SDL_Renderer * renderer,
    50                            const SDL_WindowEvent *event);
    51 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    52 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    53                             const SDL_Rect * rect, const void *pixels,
    54                             int pitch);
    55 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    56                           const SDL_Rect * rect, void **pixels, int *pitch);
    57 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    58 static void GL_SetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect);
    59 static int GL_RenderClear(SDL_Renderer * renderer);
    60 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
    61                                const SDL_Point * points, int count);
    62 static int GL_RenderDrawLines(SDL_Renderer * renderer,
    63                               const SDL_Point * points, int count);
    64 static int GL_RenderFillRects(SDL_Renderer * renderer,
    65                               const SDL_Rect ** rects, int count);
    66 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    67                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    68 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    69                                Uint32 pixel_format, void * pixels, int pitch);
    70 static void GL_RenderPresent(SDL_Renderer * renderer);
    71 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    72 static void GL_DestroyRenderer(SDL_Renderer * renderer);
    73 
    74 
    75 SDL_RenderDriver GL_RenderDriver = {
    76     GL_CreateRenderer,
    77     {
    78      "opengl",
    79      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
    80      1,
    81      {SDL_PIXELFORMAT_ARGB8888},
    82      0,
    83      0}
    84 };
    85 
    86 typedef struct
    87 {
    88     SDL_GLContext context;
    89     SDL_bool updateSize;
    90     SDL_bool GL_ARB_texture_rectangle_supported;
    91     int blendMode;
    92 
    93     /* OpenGL functions */
    94 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
    95 #include "SDL_glfuncs.h"
    96 #undef SDL_PROC
    97 
    98     void (*glTextureRangeAPPLE) (GLenum target, GLsizei length,
    99                                  const GLvoid * pointer);
   100 
   101     /* Multitexture support */
   102     SDL_bool GL_ARB_multitexture_supported;
   103     PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
   104     int num_texture_units;
   105 
   106     /* Shader support */
   107     GL_ShaderContext *shaders;
   108 
   109 } GL_RenderData;
   110 
   111 typedef struct
   112 {
   113     GLuint texture;
   114     GLenum type;
   115     GLfloat texw;
   116     GLfloat texh;
   117     GLenum format;
   118     GLenum formattype;
   119     void *pixels;
   120     int pitch;
   121     SDL_Rect locked_rect;
   122 } GL_TextureData;
   123 
   124 
   125 static void
   126 GL_SetError(const char *prefix, GLenum result)
   127 {
   128     const char *error;
   129 
   130     switch (result) {
   131     case GL_NO_ERROR:
   132         error = "GL_NO_ERROR";
   133         break;
   134     case GL_INVALID_ENUM:
   135         error = "GL_INVALID_ENUM";
   136         break;
   137     case GL_INVALID_VALUE:
   138         error = "GL_INVALID_VALUE";
   139         break;
   140     case GL_INVALID_OPERATION:
   141         error = "GL_INVALID_OPERATION";
   142         break;
   143     case GL_STACK_OVERFLOW:
   144         error = "GL_STACK_OVERFLOW";
   145         break;
   146     case GL_STACK_UNDERFLOW:
   147         error = "GL_STACK_UNDERFLOW";
   148         break;
   149     case GL_OUT_OF_MEMORY:
   150         error = "GL_OUT_OF_MEMORY";
   151         break;
   152     case GL_TABLE_TOO_LARGE:
   153         error = "GL_TABLE_TOO_LARGE";
   154         break;
   155     default:
   156         error = "UNKNOWN";
   157         break;
   158     }
   159     SDL_SetError("%s: %s", prefix, error);
   160 }
   161 
   162 static int
   163 GL_LoadFunctions(GL_RenderData * data)
   164 {
   165 #ifdef __SDL_NOGETPROCADDR__
   166 #define SDL_PROC(ret,func,params) data->func=func;
   167 #else
   168 #define SDL_PROC(ret,func,params) \
   169     do { \
   170         data->func = SDL_GL_GetProcAddress(#func); \
   171         if ( ! data->func ) { \
   172             SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
   173             return -1; \
   174         } \
   175     } while ( 0 );
   176 #endif /* __SDL_NOGETPROCADDR__ */
   177 
   178 #include "SDL_glfuncs.h"
   179 #undef SDL_PROC
   180     return 0;
   181 }
   182 
   183 SDL_Renderer *
   184 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
   185 {
   186     SDL_Renderer *renderer;
   187     GL_RenderData *data;
   188     const char *hint;
   189     GLint value;
   190     Uint32 window_flags;
   191 
   192     window_flags = SDL_GetWindowFlags(window);
   193     if (!(window_flags & SDL_WINDOW_OPENGL)) {
   194         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
   195             return NULL;
   196         }
   197     }
   198 
   199     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   200     if (!renderer) {
   201         SDL_OutOfMemory();
   202         return NULL;
   203     }
   204 
   205     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   206     if (!data) {
   207         GL_DestroyRenderer(renderer);
   208         SDL_OutOfMemory();
   209         return NULL;
   210     }
   211 
   212     renderer->WindowEvent = GL_WindowEvent;
   213     renderer->CreateTexture = GL_CreateTexture;
   214     renderer->UpdateTexture = GL_UpdateTexture;
   215     renderer->LockTexture = GL_LockTexture;
   216     renderer->UnlockTexture = GL_UnlockTexture;
   217     renderer->SetClipRect = GL_SetClipRect;
   218     renderer->RenderClear = GL_RenderClear;
   219     renderer->RenderDrawPoints = GL_RenderDrawPoints;
   220     renderer->RenderDrawLines = GL_RenderDrawLines;
   221     renderer->RenderFillRects = GL_RenderFillRects;
   222     renderer->RenderCopy = GL_RenderCopy;
   223     renderer->RenderReadPixels = GL_RenderReadPixels;
   224     renderer->RenderPresent = GL_RenderPresent;
   225     renderer->DestroyTexture = GL_DestroyTexture;
   226     renderer->DestroyRenderer = GL_DestroyRenderer;
   227     renderer->info = GL_RenderDriver.info;
   228     renderer->driverdata = data;
   229 
   230     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   231 
   232     data->context = SDL_GL_CreateContext(window);
   233     if (!data->context) {
   234         GL_DestroyRenderer(renderer);
   235         return NULL;
   236     }
   237     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   238         GL_DestroyRenderer(renderer);
   239         return NULL;
   240     }
   241 
   242     if (GL_LoadFunctions(data) < 0) {
   243         GL_DestroyRenderer(renderer);
   244         return NULL;
   245     }
   246 
   247 #ifdef __MACOSX__
   248     /* Enable multi-threaded rendering */
   249     /* Disabled until Ryan finishes his VBO/PBO code...
   250        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
   251      */
   252 #endif
   253 
   254     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   255         SDL_GL_SetSwapInterval(1);
   256     } else {
   257         SDL_GL_SetSwapInterval(0);
   258     }
   259     if (SDL_GL_GetSwapInterval() > 0) {
   260         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   261     }
   262 
   263     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   264     renderer->info.max_texture_width = value;
   265     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   266     renderer->info.max_texture_height = value;
   267 
   268     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
   269         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   270         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   271     }
   272     if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) {
   273         data->glTextureRangeAPPLE =
   274             (void (*)(GLenum, GLsizei, const GLvoid *))
   275             SDL_GL_GetProcAddress("glTextureRangeAPPLE");
   276     }
   277 
   278     /* Check for multitexture support */
   279     if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
   280         data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
   281         if (data->glActiveTextureARB) {
   282             data->GL_ARB_multitexture_supported = SDL_TRUE;
   283             data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
   284         }
   285     }
   286 
   287     /* Check for shader support */
   288     hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);
   289     if (!hint || *hint != '0') {
   290         data->shaders = GL_CreateShaderContext();
   291     }
   292     SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
   293                 data->shaders ? "ENABLED" : "DISABLED");
   294 
   295 #if 0
   296     /* We support YV12 textures using 3 textures and a shader */
   297     if (data->shaders && data->num_texture_units >= 3) {
   298         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   299     }
   300 #endif
   301 
   302     /* Set up parameters for rendering */
   303     data->blendMode = -1;
   304     data->glDisable(GL_DEPTH_TEST);
   305     data->glDisable(GL_CULL_FACE);
   306     /* This ended up causing video discrepancies between OpenGL and Direct3D */
   307     /*data->glEnable(GL_LINE_SMOOTH);*/
   308     data->updateSize = SDL_TRUE;
   309 
   310     return renderer;
   311 }
   312 
   313 static SDL_GLContext SDL_CurrentContext = NULL;
   314 
   315 static int
   316 GL_ActivateRenderer(SDL_Renderer * renderer)
   317 {
   318     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   319     SDL_Window *window = renderer->window;
   320 
   321     if (SDL_CurrentContext != data->context) {
   322         if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   323             return -1;
   324         }
   325         SDL_CurrentContext = data->context;
   326     }
   327     if (data->updateSize) {
   328         int w, h;
   329 
   330         SDL_GetWindowSize(window, &w, &h);
   331         data->glMatrixMode(GL_PROJECTION);
   332         data->glLoadIdentity();
   333         data->glMatrixMode(GL_MODELVIEW);
   334         data->glLoadIdentity();
   335         data->glViewport(0, 0, w, h);
   336         data->glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 1.0);
   337         data->updateSize = SDL_FALSE;
   338     }
   339     return 0;
   340 }
   341 
   342 static void
   343 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   344 {
   345     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   346 
   347     if (event->event == SDL_WINDOWEVENT_RESIZED) {
   348         /* Rebind the context to the window area and update matrices */
   349         SDL_CurrentContext = NULL;
   350         data->updateSize = SDL_TRUE;
   351     }
   352 }
   353 
   354 static __inline__ int
   355 power_of_2(int input)
   356 {
   357     int value = 1;
   358 
   359     while (value < input) {
   360         value <<= 1;
   361     }
   362     return value;
   363 }
   364 
   365 static __inline__ SDL_bool
   366 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
   367                GLint* internalFormat, GLenum* format, GLenum* type)
   368 {
   369     switch (pixel_format) {
   370     case SDL_PIXELFORMAT_ARGB8888:
   371         *internalFormat = GL_RGBA8;
   372         *format = GL_BGRA;
   373         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
   374         break;
   375     default:
   376         return SDL_FALSE;
   377     }
   378     return SDL_TRUE;
   379 }
   380 
   381 static int
   382 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   383 {
   384     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   385     GL_TextureData *data;
   386     GLint internalFormat;
   387     GLenum format, type;
   388     int texture_w, texture_h;
   389     GLenum result;
   390 
   391     GL_ActivateRenderer(renderer);
   392 
   393     if (!convert_format(renderdata, texture->format, &internalFormat,
   394                         &format, &type)) {
   395         SDL_SetError("Texture format %s not supported by OpenGL",
   396                      SDL_GetPixelFormatName(texture->format));
   397         return -1;
   398     }
   399 
   400     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   401     if (!data) {
   402         SDL_OutOfMemory();
   403         return -1;
   404     }
   405 
   406     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   407         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   408         data->pixels = SDL_malloc(texture->h * data->pitch);
   409         if (!data->pixels) {
   410             SDL_OutOfMemory();
   411             SDL_free(data);
   412             return -1;
   413         }
   414     }
   415 
   416     texture->driverdata = data;
   417 
   418     renderdata->glGetError();
   419     renderdata->glGenTextures(1, &data->texture);
   420     if (renderdata->GL_ARB_texture_rectangle_supported) {
   421         data->type = GL_TEXTURE_RECTANGLE_ARB;
   422         texture_w = texture->w;
   423         texture_h = texture->h;
   424         data->texw = (GLfloat) texture_w;
   425         data->texh = (GLfloat) texture_h;
   426     } else {
   427         data->type = GL_TEXTURE_2D;
   428         texture_w = power_of_2(texture->w);
   429         texture_h = power_of_2(texture->h);
   430         data->texw = (GLfloat) (texture->w) / texture_w;
   431         data->texh = (GLfloat) texture->h / texture_h;
   432     }
   433 
   434     data->format = format;
   435     data->formattype = type;
   436     renderdata->glEnable(data->type);
   437     renderdata->glBindTexture(data->type, data->texture);
   438     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   439                                 GL_LINEAR);
   440     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   441                                 GL_LINEAR);
   442     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   443                                 GL_CLAMP_TO_EDGE);
   444     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   445                                 GL_CLAMP_TO_EDGE);
   446 #ifdef __MACOSX__
   447 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   448 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   449 #endif
   450 #ifndef STORAGE_CACHED_APPLE
   451 #define STORAGE_CACHED_APPLE                0x85BE
   452 #endif
   453 #ifndef STORAGE_SHARED_APPLE
   454 #define STORAGE_SHARED_APPLE                0x85BF
   455 #endif
   456     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   457         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   458                                     GL_STORAGE_SHARED_APPLE);
   459     } else {
   460         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   461                                     GL_STORAGE_CACHED_APPLE);
   462     }
   463     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   464         && texture->format == SDL_PIXELFORMAT_ARGB8888) {
   465         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   466         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   467                                  texture_h, 0, format, type, data->pixels);
   468     }
   469     else
   470 #endif
   471     {
   472         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   473                                  texture_h, 0, format, type, NULL);
   474     }
   475     renderdata->glDisable(data->type);
   476     result = renderdata->glGetError();
   477     if (result != GL_NO_ERROR) {
   478         GL_SetError("glTexImage2D()", result);
   479         return -1;
   480     }
   481     return 0;
   482 }
   483 
   484 static int
   485 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   486                  const SDL_Rect * rect, const void *pixels, int pitch)
   487 {
   488     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   489     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   490     GLenum result;
   491 
   492     GL_ActivateRenderer(renderer);
   493 
   494     renderdata->glGetError();
   495     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   496     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   497                               (pitch / SDL_BYTESPERPIXEL(texture->format)));
   498     renderdata->glEnable(data->type);
   499     renderdata->glBindTexture(data->type, data->texture);
   500     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   501                                 rect->h, data->format, data->formattype,
   502                                 pixels);
   503     renderdata->glDisable(data->type);
   504     result = renderdata->glGetError();
   505     if (result != GL_NO_ERROR) {
   506         GL_SetError("glTexSubImage2D()", result);
   507         return -1;
   508     }
   509     return 0;
   510 }
   511 
   512 static int
   513 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   514                const SDL_Rect * rect, void **pixels, int *pitch)
   515 {
   516     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   517 
   518     data->locked_rect = *rect;
   519     *pixels = 
   520         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   521                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   522     *pitch = data->pitch;
   523     return 0;
   524 }
   525 
   526 static void
   527 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   528 {
   529     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   530     const SDL_Rect *rect;
   531     void *pixels;
   532 
   533     rect = &data->locked_rect;
   534     pixels = 
   535         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   536                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   537     GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
   538 }
   539 
   540 static void
   541 GL_SetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
   542 {
   543     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   544 
   545     GL_ActivateRenderer(renderer);
   546 
   547     if (rect) {
   548         int w, h;
   549 
   550         SDL_GetWindowSize(renderer->window, &w, &h);
   551         data->glScissor(rect->x, (h-(rect->y+rect->h)), rect->w, rect->h);
   552         data->glEnable(GL_SCISSOR_TEST);
   553     } else {
   554         data->glDisable(GL_SCISSOR_TEST);
   555     }
   556 }
   557 
   558 static void
   559 GL_SetBlendMode(GL_RenderData * data, int blendMode)
   560 {
   561     if (blendMode != data->blendMode) {
   562         switch (blendMode) {
   563         case SDL_BLENDMODE_NONE:
   564             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   565             data->glDisable(GL_BLEND);
   566             break;
   567         case SDL_BLENDMODE_BLEND:
   568             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   569             data->glEnable(GL_BLEND);
   570             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   571             break;
   572         case SDL_BLENDMODE_ADD:
   573             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   574             data->glEnable(GL_BLEND);
   575             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   576             break;
   577         case SDL_BLENDMODE_MOD:
   578             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   579             data->glEnable(GL_BLEND);
   580             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   581             break;
   582         }
   583         data->blendMode = blendMode;
   584     }
   585 }
   586 
   587 static int
   588 GL_RenderClear(SDL_Renderer * renderer)
   589 {
   590     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   591 
   592     GL_ActivateRenderer(renderer);
   593 
   594     data->glClearColor((GLfloat) renderer->r * inv255f,
   595                        (GLfloat) renderer->g * inv255f,
   596                        (GLfloat) renderer->b * inv255f,
   597                        (GLfloat) renderer->a * inv255f);
   598 
   599     data->glClear(GL_COLOR_BUFFER_BIT);
   600 
   601     return 0;
   602 }
   603 
   604 static int
   605 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   606                     int count)
   607 {
   608     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   609     int i;
   610 
   611     GL_ActivateRenderer(renderer);
   612 
   613     GL_SetBlendMode(data, renderer->blendMode);
   614     GL_SelectShader(data->shaders, SHADER_SOLID);
   615 
   616     data->glColor4f((GLfloat) renderer->r * inv255f,
   617                     (GLfloat) renderer->g * inv255f,
   618                     (GLfloat) renderer->b * inv255f,
   619                     (GLfloat) renderer->a * inv255f);
   620 
   621     data->glBegin(GL_POINTS);
   622     for (i = 0; i < count; ++i) {
   623         data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   624     }
   625     data->glEnd();
   626 
   627     return 0;
   628 }
   629 
   630 static int
   631 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   632                    int count)
   633 {
   634     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   635     int i;
   636 
   637     GL_ActivateRenderer(renderer);
   638 
   639     GL_SetBlendMode(data, renderer->blendMode);
   640     GL_SelectShader(data->shaders, SHADER_SOLID);
   641 
   642     data->glColor4f((GLfloat) renderer->r * inv255f,
   643                     (GLfloat) renderer->g * inv255f,
   644                     (GLfloat) renderer->b * inv255f,
   645                     (GLfloat) renderer->a * inv255f);
   646 
   647     if (count > 2 && 
   648         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
   649         data->glBegin(GL_LINE_LOOP);
   650         /* GL_LINE_LOOP takes care of the final segment */
   651         --count;
   652         for (i = 0; i < count; ++i) {
   653             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   654         }
   655         data->glEnd();
   656     } else {
   657 #if defined(__APPLE__) || defined(__WIN32__)
   658 #else
   659         int x1, y1, x2, y2;
   660 #endif
   661 
   662         data->glBegin(GL_LINE_STRIP);
   663         for (i = 0; i < count; ++i) {
   664             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   665         }
   666         data->glEnd();
   667 
   668         /* The line is half open, so we need one more point to complete it.
   669          * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
   670          * If we have to, we can use vertical line and horizontal line textures
   671          * for vertical and horizontal lines, and then create custom textures
   672          * for diagonal lines and software render those.  It's terrible, but at
   673          * least it would be pixel perfect.
   674          */
   675         data->glBegin(GL_POINTS);
   676 #if defined(__APPLE__) || defined(__WIN32__)
   677         /* Mac OS X and Windows seem to always leave the second point open */
   678         data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
   679 #else
   680         /* Linux seems to leave the right-most or bottom-most point open */
   681         x1 = points[0].x;
   682         y1 = points[0].y;
   683         x2 = points[count-1].x;
   684         y2 = points[count-1].y;
   685 
   686         if (x1 > x2) {
   687             data->glVertex2f(0.5f + x1, 0.5f + y1);
   688         } else if (x2 > x1) {
   689             data->glVertex2f(0.5f + x2, 0.5f + y2);
   690         } else if (y1 > y2) {
   691             data->glVertex2f(0.5f + x1, 0.5f + y1);
   692         } else if (y2 > y1) {
   693             data->glVertex2f(0.5f + x2, 0.5f + y2);
   694         }
   695 #endif
   696         data->glEnd();
   697     }
   698 
   699     return 0;
   700 }
   701 
   702 static int
   703 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
   704 {
   705     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   706     int i;
   707 
   708     GL_ActivateRenderer(renderer);
   709 
   710     GL_SetBlendMode(data, renderer->blendMode);
   711     GL_SelectShader(data->shaders, SHADER_SOLID);
   712 
   713     data->glColor4f((GLfloat) renderer->r * inv255f,
   714                     (GLfloat) renderer->g * inv255f,
   715                     (GLfloat) renderer->b * inv255f,
   716                     (GLfloat) renderer->a * inv255f);
   717 
   718     for (i = 0; i < count; ++i) {
   719         const SDL_Rect *rect = rects[i];
   720 
   721         data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
   722     }
   723 
   724     return 0;
   725 }
   726 
   727 static int
   728 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   729               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   730 {
   731     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   732     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   733     int minx, miny, maxx, maxy;
   734     GLfloat minu, maxu, minv, maxv;
   735 
   736     GL_ActivateRenderer(renderer);
   737 
   738     minx = dstrect->x;
   739     miny = dstrect->y;
   740     maxx = dstrect->x + dstrect->w;
   741     maxy = dstrect->y + dstrect->h;
   742 
   743     minu = (GLfloat) srcrect->x / texture->w;
   744     minu *= texturedata->texw;
   745     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   746     maxu *= texturedata->texw;
   747     minv = (GLfloat) srcrect->y / texture->h;
   748     minv *= texturedata->texh;
   749     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   750     maxv *= texturedata->texh;
   751 
   752     data->glEnable(texturedata->type);
   753     data->glBindTexture(texturedata->type, texturedata->texture);
   754 
   755     if (texture->modMode) {
   756         data->glColor4f((GLfloat) texture->r * inv255f,
   757                         (GLfloat) texture->g * inv255f,
   758                         (GLfloat) texture->b * inv255f,
   759                         (GLfloat) texture->a * inv255f);
   760     } else {
   761         data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
   762     }
   763 
   764     GL_SetBlendMode(data, texture->blendMode);
   765     GL_SelectShader(data->shaders, SHADER_RGB);
   766 
   767     data->glBegin(GL_TRIANGLE_STRIP);
   768     data->glTexCoord2f(minu, minv);
   769     data->glVertex2f((GLfloat) minx, (GLfloat) miny);
   770     data->glTexCoord2f(maxu, minv);
   771     data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
   772     data->glTexCoord2f(minu, maxv);
   773     data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
   774     data->glTexCoord2f(maxu, maxv);
   775     data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
   776     data->glEnd();
   777 
   778     data->glDisable(texturedata->type);
   779 
   780     return 0;
   781 }
   782 
   783 static int
   784 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   785                     Uint32 pixel_format, void * pixels, int pitch)
   786 {
   787     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   788     SDL_Window *window = renderer->window;
   789     GLint internalFormat;
   790     GLenum format, type;
   791     Uint8 *src, *dst, *tmp;
   792     int w, h, length, rows;
   793 
   794     GL_ActivateRenderer(renderer);
   795 
   796     if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
   797         /* FIXME: Do a temp copy to a format that is supported */
   798         SDL_SetError("Unsupported pixel format");
   799         return -1;
   800     }
   801 
   802     SDL_GetWindowSize(window, &w, &h);
   803 
   804     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
   805     data->glPixelStorei(GL_PACK_ROW_LENGTH,
   806                         (pitch / SDL_BYTESPERPIXEL(pixel_format)));
   807 
   808     data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
   809                        format, type, pixels);
   810 
   811     /* Flip the rows to be top-down */
   812     length = rect->w * SDL_BYTESPERPIXEL(pixel_format);
   813     src = (Uint8*)pixels + (rect->h-1)*pitch;
   814     dst = (Uint8*)pixels;
   815     tmp = SDL_stack_alloc(Uint8, length);
   816     rows = rect->h / 2;
   817     while (rows--) {
   818         SDL_memcpy(tmp, dst, length);
   819         SDL_memcpy(dst, src, length);
   820         SDL_memcpy(src, tmp, length);
   821         dst += pitch;
   822         src -= pitch;
   823     }
   824     SDL_stack_free(tmp);
   825 
   826     return 0;
   827 }
   828 
   829 static void
   830 GL_RenderPresent(SDL_Renderer * renderer)
   831 {
   832     GL_ActivateRenderer(renderer);
   833 
   834     SDL_GL_SwapWindow(renderer->window);
   835 }
   836 
   837 static void
   838 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   839 {
   840     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   841     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   842 
   843     GL_ActivateRenderer(renderer);
   844 
   845     if (!data) {
   846         return;
   847     }
   848     if (data->texture) {
   849         renderdata->glDeleteTextures(1, &data->texture);
   850     }
   851     if (data->pixels) {
   852         SDL_free(data->pixels);
   853     }
   854     SDL_free(data);
   855     texture->driverdata = NULL;
   856 }
   857 
   858 static void
   859 GL_DestroyRenderer(SDL_Renderer * renderer)
   860 {
   861     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   862 
   863     if (data) {
   864         if (data->context) {
   865             /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
   866             SDL_GL_DeleteContext(data->context);
   867         }
   868         SDL_free(data);
   869     }
   870     SDL_free(renderer);
   871 }
   872 
   873 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
   874 
   875 /* vi: set ts=4 sw=4 expandtab: */