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