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