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