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