src/video/SDL_renderer_gl.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 07 Dec 2008 22:37:40 +0000
changeset 2853 6258fa7cd300
parent 2848 8a3aa505ecba
child 2858 a38fcb093081
permissions -rw-r--r--
Fixed picking blit function when RLE fails
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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_video.h"
    27 #include "SDL_opengl.h"
    28 #include "SDL_sysvideo.h"
    29 #include "SDL_pixels_c.h"
    30 #include "SDL_rect_c.h"
    31 #include "SDL_yuv_sw_c.h"
    32 
    33 #ifdef __MACOSX__
    34 #include <OpenGL/OpenGL.h>
    35 #endif
    36 
    37 
    38 /* OpenGL renderer implementation */
    39 
    40 /* Details on optimizing the texture path on Mac OS X:
    41    http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html
    42 */
    43 
    44 /* !!! FIXME: this should go in a higher level than the GL renderer. */
    45 static __inline__ int
    46 bytes_per_pixel(const Uint32 format)
    47 {
    48     if (!SDL_ISPIXELFORMAT_FOURCC(format)) {
    49         return SDL_BYTESPERPIXEL(format);
    50     }
    51 
    52     /* FOURCC format */
    53     switch (format) {
    54         case SDL_PIXELFORMAT_YV12:
    55         case SDL_PIXELFORMAT_IYUV:
    56         case SDL_PIXELFORMAT_YUY2:
    57         case SDL_PIXELFORMAT_UYVY:
    58         case SDL_PIXELFORMAT_YVYU:
    59             return 2;
    60         default:
    61             return 1;  /* shouldn't ever hit this. */
    62     }
    63 }
    64 
    65 
    66 static const float inv255f = 1.0f / 255.0f;
    67 
    68 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    69 static int GL_ActivateRenderer(SDL_Renderer * renderer);
    70 static int GL_DisplayModeChanged(SDL_Renderer * renderer);
    71 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    72 static int GL_QueryTexturePixels(SDL_Renderer * renderer,
    73                                  SDL_Texture * texture, void **pixels,
    74                                  int *pitch);
    75 static int GL_SetTexturePalette(SDL_Renderer * renderer,
    76                                 SDL_Texture * texture,
    77                                 const SDL_Color * colors, int firstcolor,
    78                                 int ncolors);
    79 static int GL_GetTexturePalette(SDL_Renderer * renderer,
    80                                 SDL_Texture * texture, SDL_Color * colors,
    81                                 int firstcolor, int ncolors);
    82 static int GL_SetTextureColorMod(SDL_Renderer * renderer,
    83                                  SDL_Texture * texture);
    84 static int GL_SetTextureAlphaMod(SDL_Renderer * renderer,
    85                                  SDL_Texture * texture);
    86 static int GL_SetTextureBlendMode(SDL_Renderer * renderer,
    87                                   SDL_Texture * texture);
    88 static int GL_SetTextureScaleMode(SDL_Renderer * renderer,
    89                                   SDL_Texture * texture);
    90 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    91                             const SDL_Rect * rect, const void *pixels,
    92                             int pitch);
    93 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    94                           const SDL_Rect * rect, int markDirty, void **pixels,
    95                           int *pitch);
    96 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    97 static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    98                             int numrects, const SDL_Rect * rects);
    99 static int GL_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b,
   100                          Uint8 a, const SDL_Rect * rect);
   101 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   102                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
   103 static void GL_RenderPresent(SDL_Renderer * renderer);
   104 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   105 static void GL_DestroyRenderer(SDL_Renderer * renderer);
   106 
   107 
   108 SDL_RenderDriver GL_RenderDriver = {
   109     GL_CreateRenderer,
   110     {
   111      "opengl",
   112      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD |
   113       SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
   114      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
   115       SDL_TEXTUREMODULATE_ALPHA),
   116      (SDL_TEXTUREBLENDMODE_NONE | SDL_TEXTUREBLENDMODE_MASK |
   117       SDL_TEXTUREBLENDMODE_BLEND | SDL_TEXTUREBLENDMODE_ADD |
   118       SDL_TEXTUREBLENDMODE_MOD),
   119      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST |
   120       SDL_TEXTURESCALEMODE_SLOW),
   121      15,
   122      {
   123       SDL_PIXELFORMAT_INDEX1LSB,
   124       SDL_PIXELFORMAT_INDEX1MSB,
   125       SDL_PIXELFORMAT_INDEX8,
   126       SDL_PIXELFORMAT_RGB332,
   127       SDL_PIXELFORMAT_RGB444,
   128       SDL_PIXELFORMAT_RGB555,
   129       SDL_PIXELFORMAT_ARGB4444,
   130       SDL_PIXELFORMAT_ARGB1555,
   131       SDL_PIXELFORMAT_RGB565,
   132       SDL_PIXELFORMAT_RGB24,
   133       SDL_PIXELFORMAT_BGR24,
   134       SDL_PIXELFORMAT_RGB888,
   135       SDL_PIXELFORMAT_BGR888,
   136       SDL_PIXELFORMAT_ARGB8888,
   137       SDL_PIXELFORMAT_ABGR8888,
   138       SDL_PIXELFORMAT_ARGB2101010},
   139      0,
   140      0}
   141 };
   142 
   143 typedef struct
   144 {
   145     SDL_GLContext context;
   146     SDL_bool updateSize;
   147     SDL_bool GL_ARB_texture_rectangle_supported;
   148     SDL_bool GL_EXT_paletted_texture_supported;
   149     SDL_bool GL_APPLE_ycbcr_422_supported;
   150     SDL_bool GL_MESA_ycbcr_texture_supported;
   151     SDL_bool GL_ARB_fragment_program_supported;
   152     int blendMode;
   153     int scaleMode;
   154 
   155     /* OpenGL functions */
   156 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   157 #include "SDL_glfuncs.h"
   158 #undef SDL_PROC
   159 
   160     PFNGLCOLORTABLEEXTPROC glColorTableEXT;
   161     void (*glTextureRangeAPPLE) (GLenum target, GLsizei length,
   162                                  const GLvoid * pointer);
   163 
   164     PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
   165     PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
   166     PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
   167     PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
   168     PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
   169     PFNGLBINDPROGRAMARBPROC glBindProgramARB;
   170     PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
   171 
   172     /* (optional) fragment programs */
   173     GLuint fragment_program_UYVY;
   174 } GL_RenderData;
   175 
   176 typedef struct
   177 {
   178     GLuint texture;
   179     GLuint shader;
   180     GLenum type;
   181     GLfloat texw;
   182     GLfloat texh;
   183     GLenum format;
   184     GLenum formattype;
   185     Uint8 *palette;
   186     void *pixels;
   187     int pitch;
   188     SDL_DirtyRectList dirty;
   189 int HACK_RYAN_FIXME;
   190 } GL_TextureData;
   191 
   192 
   193 static void
   194 GL_SetError(const char *prefix, GLenum result)
   195 {
   196     const char *error;
   197 
   198     switch (result) {
   199     case GL_NO_ERROR:
   200         error = "GL_NO_ERROR";
   201         break;
   202     case GL_INVALID_ENUM:
   203         error = "GL_INVALID_ENUM";
   204         break;
   205     case GL_INVALID_VALUE:
   206         error = "GL_INVALID_VALUE";
   207         break;
   208     case GL_INVALID_OPERATION:
   209         error = "GL_INVALID_OPERATION";
   210         break;
   211     case GL_STACK_OVERFLOW:
   212         error = "GL_STACK_OVERFLOW";
   213         break;
   214     case GL_STACK_UNDERFLOW:
   215         error = "GL_STACK_UNDERFLOW";
   216         break;
   217     case GL_OUT_OF_MEMORY:
   218         error = "GL_OUT_OF_MEMORY";
   219         break;
   220     case GL_TABLE_TOO_LARGE:
   221         error = "GL_TABLE_TOO_LARGE";
   222         break;
   223     default:
   224         error = "UNKNOWN";
   225         break;
   226     }
   227     SDL_SetError("%s: %s", prefix, error);
   228 }
   229 
   230 static int
   231 GL_LoadFunctions(GL_RenderData * data)
   232 {
   233 #if defined(__QNXNTO__) && (_NTO_VERSION < 630)
   234 #define __SDL_NOGETPROCADDR__
   235 #elif defined(__MINT__)
   236 #define __SDL_NOGETPROCADDR__
   237 #endif
   238 #ifdef __SDL_NOGETPROCADDR__
   239 #define SDL_PROC(ret,func,params) data->func=func;
   240 #else
   241 #define SDL_PROC(ret,func,params) \
   242     do { \
   243         data->func = SDL_GL_GetProcAddress(#func); \
   244         if ( ! data->func ) { \
   245             SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
   246             return -1; \
   247         } \
   248     } while ( 0 );
   249 #endif /* __SDL_NOGETPROCADDR__ */
   250 
   251 #include "SDL_glfuncs.h"
   252 #undef SDL_PROC
   253     return 0;
   254 }
   255 
   256 void
   257 GL_AddRenderDriver(_THIS)
   258 {
   259     if (_this->GL_CreateContext) {
   260         SDL_AddRenderDriver(0, &GL_RenderDriver);
   261     }
   262 }
   263 
   264 SDL_Renderer *
   265 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
   266 {
   267     SDL_Renderer *renderer;
   268     GL_RenderData *data;
   269     GLint value;
   270     int doublebuffer;
   271 
   272     /* Render directly to the window, unless we're compositing */
   273 #ifndef __MACOSX__
   274     if (flags & SDL_RENDERER_SINGLEBUFFER) {
   275         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
   276     }
   277 #endif
   278     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   279         if (SDL_RecreateWindow(window, window->flags | SDL_WINDOW_OPENGL) < 0) {
   280             return NULL;
   281         }
   282     }
   283 
   284     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   285     if (!renderer) {
   286         SDL_OutOfMemory();
   287         return NULL;
   288     }
   289 
   290     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   291     if (!data) {
   292         GL_DestroyRenderer(renderer);
   293         SDL_OutOfMemory();
   294         return NULL;
   295     }
   296 
   297     renderer->ActivateRenderer = GL_ActivateRenderer;
   298     renderer->DisplayModeChanged = GL_DisplayModeChanged;
   299     renderer->CreateTexture = GL_CreateTexture;
   300     renderer->QueryTexturePixels = GL_QueryTexturePixels;
   301     renderer->SetTexturePalette = GL_SetTexturePalette;
   302     renderer->GetTexturePalette = GL_GetTexturePalette;
   303     renderer->SetTextureColorMod = GL_SetTextureColorMod;
   304     renderer->SetTextureAlphaMod = GL_SetTextureAlphaMod;
   305     renderer->SetTextureBlendMode = GL_SetTextureBlendMode;
   306     renderer->SetTextureScaleMode = GL_SetTextureScaleMode;
   307     renderer->UpdateTexture = GL_UpdateTexture;
   308     renderer->LockTexture = GL_LockTexture;
   309     renderer->UnlockTexture = GL_UnlockTexture;
   310     renderer->DirtyTexture = GL_DirtyTexture;
   311     renderer->RenderFill = GL_RenderFill;
   312     renderer->RenderCopy = GL_RenderCopy;
   313     renderer->RenderPresent = GL_RenderPresent;
   314     renderer->DestroyTexture = GL_DestroyTexture;
   315     renderer->DestroyRenderer = GL_DestroyRenderer;
   316     renderer->info = GL_RenderDriver.info;
   317     renderer->window = window->id;
   318     renderer->driverdata = data;
   319 
   320     renderer->info.flags =
   321         (SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED);
   322 
   323     if (GL_LoadFunctions(data) < 0) {
   324         GL_DestroyRenderer(renderer);
   325         return NULL;
   326     }
   327 
   328     data->context = SDL_GL_CreateContext(window->id);
   329     if (!data->context) {
   330         GL_DestroyRenderer(renderer);
   331         return NULL;
   332     }
   333     if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
   334         GL_DestroyRenderer(renderer);
   335         return NULL;
   336     }
   337 #ifdef __MACOSX__
   338     /* Enable multi-threaded rendering */
   339     /* Disabled until Ryan finishes his VBO/PBO code...
   340        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
   341      */
   342 #endif
   343 
   344     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   345         SDL_GL_SetSwapInterval(1);
   346     } else {
   347         SDL_GL_SetSwapInterval(0);
   348     }
   349     if (SDL_GL_GetSwapInterval() > 0) {
   350         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   351     }
   352 
   353     if (SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doublebuffer) == 0) {
   354         if (!doublebuffer) {
   355             renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER;
   356         }
   357     }
   358 
   359     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   360     renderer->info.max_texture_width = value;
   361     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   362     renderer->info.max_texture_height = value;
   363 
   364     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
   365         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   366         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   367     }
   368     if (SDL_GL_ExtensionSupported("GL_EXT_paletted_texture")) {
   369         data->GL_EXT_paletted_texture_supported = SDL_TRUE;
   370         data->glColorTableEXT =
   371             (PFNGLCOLORTABLEEXTPROC) SDL_GL_GetProcAddress("glColorTableEXT");
   372     } else {
   373         /* Don't advertise support for 8-bit indexed texture format */
   374         Uint32 i, j;
   375         SDL_RendererInfo *info = &renderer->info;
   376         for (i = 0, j = 0; i < info->num_texture_formats; ++i) {
   377             if (info->texture_formats[i] != SDL_PIXELFORMAT_INDEX8) {
   378                 info->texture_formats[j++] = info->texture_formats[i];
   379             }
   380         }
   381         --info->num_texture_formats;
   382     }
   383 /*
   384     if (SDL_GL_ExtensionSupported("GL_APPLE_ycbcr_422")) {
   385         data->GL_APPLE_ycbcr_422_supported = SDL_TRUE;
   386     }
   387     if (SDL_GL_ExtensionSupported("GL_MESA_ycbcr_texture")) {
   388         data->GL_MESA_ycbcr_texture_supported = SDL_TRUE;
   389     }
   390 */
   391     if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) {
   392         data->glTextureRangeAPPLE =
   393             (void (*)(GLenum, GLsizei, const GLvoid *))
   394             SDL_GL_GetProcAddress("glTextureRangeAPPLE");
   395     }
   396 
   397     /* we might use fragment programs for YUV data, etc. */
   398     if (SDL_GL_ExtensionSupported("GL_ARB_fragment_program")) {
   399         /* !!! FIXME: this doesn't check for errors. */
   400         /* !!! FIXME: this should really reuse the glfuncs.h stuff. */
   401         data->glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)
   402             SDL_GL_GetProcAddress("glGetProgramivARB");
   403         data->glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)
   404             SDL_GL_GetProcAddress("glGetProgramStringARB");
   405         data->glProgramLocalParameter4fvARB =
   406             (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)
   407             SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB");
   408         data->glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)
   409             SDL_GL_GetProcAddress("glDeleteProgramsARB");
   410         data->glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)
   411             SDL_GL_GetProcAddress("glGenProgramsARB");
   412         data->glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)
   413             SDL_GL_GetProcAddress("glBindProgramARB");
   414         data->glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)
   415             SDL_GL_GetProcAddress("glProgramStringARB");
   416         data->GL_ARB_fragment_program_supported = SDL_TRUE;
   417     }
   418 
   419     /* Set up parameters for rendering */
   420     data->blendMode = -1;
   421     data->scaleMode = -1;
   422     data->glDisable(GL_DEPTH_TEST);
   423     data->glDisable(GL_CULL_FACE);
   424     if (data->GL_ARB_texture_rectangle_supported) {
   425         data->glEnable(GL_TEXTURE_RECTANGLE_ARB);
   426     } else {
   427         data->glEnable(GL_TEXTURE_2D);
   428     }
   429     data->updateSize = SDL_TRUE;
   430 
   431     return renderer;
   432 }
   433 
   434 static int
   435 GL_ActivateRenderer(SDL_Renderer * renderer)
   436 {
   437     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   438     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   439 
   440     if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
   441         return -1;
   442     }
   443     if (data->updateSize) {
   444         data->glMatrixMode(GL_PROJECTION);
   445         data->glLoadIdentity();
   446         data->glMatrixMode(GL_MODELVIEW);
   447         data->glLoadIdentity();
   448         data->glViewport(0, 0, window->w, window->h);
   449         data->glOrtho(0.0, (GLdouble) window->w, (GLdouble) window->h, 0.0,
   450                       0.0, 1.0);
   451         data->updateSize = SDL_FALSE;
   452     }
   453     return 0;
   454 }
   455 
   456 static int
   457 GL_DisplayModeChanged(SDL_Renderer * renderer)
   458 {
   459     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   460 
   461     /* Rebind the context to the window area and update matrices */
   462     data->updateSize = SDL_TRUE;
   463     return GL_ActivateRenderer(renderer);
   464 }
   465 
   466 static __inline__ int
   467 power_of_2(int input)
   468 {
   469     int value = 1;
   470 
   471     while (value < input) {
   472         value <<= 1;
   473     }
   474     return value;
   475 }
   476 
   477 
   478 #define DEBUG_PROGRAM_COMPILE 1
   479 
   480 static GLuint
   481 compile_shader(GL_RenderData *data, GLenum shader_type, const char *_code)
   482 {
   483     const int have_texture_rects = data->GL_ARB_texture_rectangle_supported;
   484     const char *replacement = have_texture_rects ? "RECT" : "2D";
   485     const size_t replacementlen = strlen(replacement);
   486     const char *token = "%TEXTURETARGET%";
   487     const size_t tokenlen = strlen(token);
   488     char *code = NULL;
   489     char *ptr = NULL;
   490     GLuint program = 0;
   491 
   492     /*
   493      * The TEX instruction needs a different target depending on what we use.
   494      *  To handle this, we use "%TEXTURETARGET%" and replace the string before
   495      *  compiling the shader.
   496      */
   497     code = SDL_strdup(_code);
   498     if (code == NULL)
   499         return 0;
   500 
   501     for (ptr = SDL_strstr(code, token); ptr; ptr = SDL_strstr(ptr+1, token)) {
   502         memcpy(ptr, replacement, replacementlen);
   503         memmove(ptr+replacementlen, ptr+tokenlen, strlen(ptr+tokenlen)+1);
   504     }
   505 
   506 #if DEBUG_PROGRAM_COMPILE
   507     printf("compiling shader:\n%s\n\n", code);
   508 #endif
   509 
   510     data->glGetError();  /* flush any existing error state. */
   511     data->glGenProgramsARB(1, &program);
   512     data->glBindProgramARB(shader_type, program);
   513     data->glProgramStringARB(shader_type, GL_PROGRAM_FORMAT_ASCII_ARB,
   514                              SDL_strlen(code), code);
   515 
   516     SDL_free(code);
   517 
   518     if (data->glGetError() == GL_INVALID_OPERATION)
   519     {
   520 #if DEBUG_PROGRAM_COMPILE
   521         GLint pos = 0;
   522         const GLubyte *errstr;
   523         data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
   524         errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
   525         printf("program compile error at position %d: %s\n\n",
   526                   (int) pos, (const char *) errstr);
   527 #endif
   528         data->glBindProgramARB(shader_type, 0);
   529         data->glDeleteProgramsARB(1, &program);
   530         return 0;
   531     }
   532 
   533     return program;
   534 }
   535 
   536 
   537 /*
   538  * Fragment program that renders from UYVY textures.
   539  * The UYVY to RGB equasion is:
   540  *   R = 1.164(Y-16) + 1.596(Cr-128)
   541  *   G = 1.164(Y-16) - 0.813(Cr-128) - 0.391(Cb-128)
   542  *   B = 1.164(Y-16) + 2.018(Cb-128)
   543  * Byte layout is Cb, Y1, Cr, Y2, stored in the R, G, B, A channels.
   544  * 4 bytes == 2 pixels: Y1/Cb/Cr, Y2/Cb/Cr
   545  *
   546  * !!! FIXME: this ignores blendmodes, etc.
   547  * !!! FIXME: this could be more efficient...use a dot product for green, etc.
   548  */
   549 static const char *fragment_program_UYVY_source_code =
   550     "!!ARBfp1.0\n"
   551 
   552     /* outputs... */
   553     "OUTPUT outcolor = result.color;\n"
   554 
   555     /* scratch registers... */
   556     "TEMP uyvy;\n"
   557     "TEMP luminance;\n"
   558     "TEMP work;\n"
   559 
   560     /* Halve the coordinates to grab the correct 32 bits for the fragment. */
   561     "MUL work, fragment.texcoord, { 0.5, 1.0, 1.0, 1.0 };\n"
   562 
   563     /* Sample the YUV texture. Cb, Y1, Cr, Y2, are stored in x, y, z, w. */
   564     "TEX uyvy, work, texture[0], %TEXTURETARGET%;\n"
   565 
   566     /* Do subtractions (128/255, 16/255, 128/255, 16/255) */
   567     "SUB uyvy, uyvy, { 0.501960784313726, 0.06274509803922, 0.501960784313726, 0.06274509803922 };\n"
   568 
   569     /* Choose the luminance component by texcoord. */
   570     /* !!! FIXME: laziness wins out for now... just average Y1 and Y2. */
   571     "ADD luminance, uyvy.yyyy, uyvy.wwww;\n"
   572     "MUL luminance, luminance, { 0.5, 0.5, 0.5, 0.5 };\n"
   573 
   574     /* Multiply luminance by its magic value. */
   575     "MUL luminance, luminance, { 1.164, 1.164, 1.164, 1.164 };\n"
   576 
   577     /* uyvy.xyzw becomes Cr/Cr/Cb/Cb, with multiplications. */
   578     "MUL uyvy, uyvy.zzxx, { 1.596, -0.813, 2.018, -0.391 };\n"
   579 
   580     /* Add luminance to Cr and Cb, store to RGB channels. */
   581     "ADD work.rgb, luminance, uyvy;\n"
   582 
   583     /* Do final addition for Green channel.  (!!! FIXME: this should be a DPH?) */
   584     "ADD work.g, work.g, uyvy.w;\n"
   585 
   586     /* Make sure alpha channel is fully opaque.  (!!! FIXME: blend modes!) */
   587     "MOV work.a, { 1.0 };\n"
   588 
   589     /* Store out the final fragment color... */
   590     "MOV outcolor, work;\n"
   591 
   592     /* ...and we're done! */
   593     "END\n";
   594 
   595 
   596 static int
   597 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   598 {
   599     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   600     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   601     GL_TextureData *data;
   602     GLint internalFormat;
   603     GLenum format, type;
   604     int texture_w, texture_h;
   605     GLuint shader = 0;
   606     GLenum result;
   607 
   608     switch (texture->format) {
   609     case SDL_PIXELFORMAT_INDEX1LSB:
   610     case SDL_PIXELFORMAT_INDEX1MSB:
   611         internalFormat = GL_RGB;
   612         format = GL_COLOR_INDEX;
   613         type = GL_BITMAP;
   614         break;
   615     case SDL_PIXELFORMAT_INDEX8:
   616         if (!renderdata->GL_EXT_paletted_texture_supported) {
   617             SDL_SetError("Unsupported texture format");
   618             return -1;
   619         }
   620         internalFormat = GL_COLOR_INDEX8_EXT;
   621         format = GL_COLOR_INDEX;
   622         type = GL_UNSIGNED_BYTE;
   623         break;
   624     case SDL_PIXELFORMAT_RGB332:
   625         internalFormat = GL_R3_G3_B2;
   626         format = GL_RGB;
   627         type = GL_UNSIGNED_BYTE_3_3_2;
   628         break;
   629     case SDL_PIXELFORMAT_RGB444:
   630         internalFormat = GL_RGB4;
   631         format = GL_RGB;
   632         type = GL_UNSIGNED_SHORT_4_4_4_4;
   633         break;
   634     case SDL_PIXELFORMAT_RGB555:
   635         internalFormat = GL_RGB5;
   636         format = GL_RGB;
   637         type = GL_UNSIGNED_SHORT_5_5_5_1;
   638         break;
   639     case SDL_PIXELFORMAT_ARGB4444:
   640         internalFormat = GL_RGBA4;
   641         format = GL_BGRA;
   642         type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
   643         break;
   644     case SDL_PIXELFORMAT_ARGB1555:
   645         internalFormat = GL_RGB5_A1;
   646         format = GL_BGRA;
   647         type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
   648         break;
   649     case SDL_PIXELFORMAT_RGB565:
   650         internalFormat = GL_RGB8;
   651         format = GL_RGB;
   652         type = GL_UNSIGNED_SHORT_5_6_5;
   653         break;
   654     case SDL_PIXELFORMAT_RGB24:
   655         internalFormat = GL_RGB8;
   656         format = GL_RGB;
   657         type = GL_UNSIGNED_BYTE;
   658         break;
   659     case SDL_PIXELFORMAT_RGB888:
   660         internalFormat = GL_RGB8;
   661         format = GL_BGRA;
   662         type = GL_UNSIGNED_BYTE;
   663         break;
   664     case SDL_PIXELFORMAT_BGR24:
   665         internalFormat = GL_RGB8;
   666         format = GL_BGR;
   667         type = GL_UNSIGNED_BYTE;
   668         break;
   669     case SDL_PIXELFORMAT_BGR888:
   670         internalFormat = GL_RGB8;
   671         format = GL_RGBA;
   672         type = GL_UNSIGNED_BYTE;
   673         break;
   674     case SDL_PIXELFORMAT_ARGB8888:
   675 #ifdef __MACOSX__
   676         internalFormat = GL_RGBA;
   677         format = GL_BGRA;
   678         type = GL_UNSIGNED_INT_8_8_8_8_REV;
   679 #else
   680         internalFormat = GL_RGBA8;
   681         format = GL_BGRA;
   682         type = GL_UNSIGNED_BYTE;
   683 #endif
   684         break;
   685     case SDL_PIXELFORMAT_ABGR8888:
   686         internalFormat = GL_RGBA8;
   687         format = GL_RGBA;
   688         type = GL_UNSIGNED_BYTE;
   689         break;
   690     case SDL_PIXELFORMAT_ARGB2101010:
   691         internalFormat = GL_RGB10_A2;
   692         format = GL_BGRA;
   693         type = GL_UNSIGNED_INT_2_10_10_10_REV;
   694         break;
   695     case SDL_PIXELFORMAT_UYVY:
   696         if (renderdata->GL_APPLE_ycbcr_422_supported) {
   697             internalFormat = GL_RGB;
   698             format = GL_YCBCR_422_APPLE;
   699 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   700             type = GL_UNSIGNED_SHORT_8_8_APPLE;
   701 #else
   702             type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
   703 #endif
   704         } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
   705             internalFormat = GL_RGB;
   706             format = GL_YCBCR_MESA;
   707 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   708             type = GL_UNSIGNED_SHORT_8_8_MESA;
   709 #else
   710             type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
   711 #endif
   712         } else if (renderdata->GL_ARB_fragment_program_supported) {
   713             if (renderdata->fragment_program_UYVY == 0) {
   714                 renderdata->fragment_program_UYVY =
   715                     compile_shader(renderdata, GL_FRAGMENT_PROGRAM_ARB,
   716                                    fragment_program_UYVY_source_code);
   717                 if (renderdata->fragment_program_UYVY == 0) {
   718                     SDL_SetError("Fragment program compile error");
   719                     return -1;
   720                 }
   721             }
   722             shader = renderdata->fragment_program_UYVY;
   723             internalFormat = GL_RGBA;
   724             format = GL_RGBA;
   725             type = GL_UNSIGNED_BYTE;
   726         } else {
   727             SDL_SetError("Unsupported texture format");
   728             return -1;
   729         }
   730         break;
   731     case SDL_PIXELFORMAT_YUY2:
   732         if (renderdata->GL_APPLE_ycbcr_422_supported) {
   733             internalFormat = GL_RGB;
   734             format = GL_YCBCR_422_APPLE;
   735 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   736             type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
   737 #else
   738             type = GL_UNSIGNED_SHORT_8_8_APPLE;
   739 #endif
   740         } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
   741             internalFormat = GL_RGB;
   742             format = GL_YCBCR_MESA;
   743 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   744             type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
   745 #else
   746             type = GL_UNSIGNED_SHORT_8_8_MESA;
   747 #endif
   748         } else {
   749             SDL_SetError("Unsupported texture format");
   750             return -1;
   751         }
   752         break;
   753     default:
   754         SDL_SetError("Unsupported texture format");
   755         return -1;
   756     }
   757 
   758     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   759     if (!data) {
   760         SDL_OutOfMemory();
   761         return -1;
   762     }
   763 
   764     data->shader = shader;
   765 
   766     if (texture->format == SDL_PIXELFORMAT_INDEX8) {
   767         data->palette = (Uint8 *) SDL_malloc(3 * 256 * sizeof(Uint8));
   768         if (!data->palette) {
   769             SDL_OutOfMemory();
   770             SDL_free(data);
   771             return -1;
   772         }
   773         SDL_memset(data->palette, 0xFF, 3 * 256 * sizeof(Uint8));
   774     }
   775 
   776     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   777         data->pitch = texture->w * bytes_per_pixel(texture->format);
   778         data->pixels = SDL_malloc(texture->h * data->pitch);
   779         if (!data->pixels) {
   780             SDL_OutOfMemory();
   781             SDL_free(data);
   782             return -1;
   783         }
   784     }
   785 
   786     texture->driverdata = data;
   787 
   788     renderdata->glGetError();
   789     renderdata->glGenTextures(1, &data->texture);
   790     if (renderdata->GL_ARB_texture_rectangle_supported) {
   791         data->type = GL_TEXTURE_RECTANGLE_ARB;
   792         texture_w = texture->w;
   793         texture_h = texture->h;
   794         data->texw = (GLfloat) texture_w;
   795         data->texh = (GLfloat) texture_h;
   796     } else {
   797         data->type = GL_TEXTURE_2D;
   798         texture_w = power_of_2(texture->w);
   799         texture_h = power_of_2(texture->h);
   800         data->texw = (GLfloat) (texture->w) / texture_w;
   801         data->texh = (GLfloat) texture->h / texture_h;
   802     }
   803 
   804     /* YUV formats use RGBA but are really two bytes per pixel */
   805     if (internalFormat == GL_RGBA && bytes_per_pixel(texture->format) < 4) {
   806 data->HACK_RYAN_FIXME = 2;
   807     } else {
   808 data->HACK_RYAN_FIXME = 1;
   809     }
   810     texture_w /= data->HACK_RYAN_FIXME;
   811 
   812     data->format = format;
   813     data->formattype = type;
   814     renderdata->glBindTexture(data->type, data->texture);
   815     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   816                                 GL_NEAREST);
   817     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   818                                 GL_NEAREST);
   819     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   820                                 GL_CLAMP_TO_EDGE);
   821     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   822                                 GL_CLAMP_TO_EDGE);
   823 #ifdef __MACOSX__
   824 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   825 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   826 #endif
   827 #ifndef STORAGE_CACHED_APPLE
   828 #define STORAGE_CACHED_APPLE                0x85BE
   829 #endif
   830 #ifndef STORAGE_SHARED_APPLE
   831 #define STORAGE_SHARED_APPLE                0x85BF
   832 #endif
   833     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   834         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   835                                     GL_STORAGE_SHARED_APPLE);
   836     } else {
   837         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   838                                     GL_STORAGE_CACHED_APPLE);
   839     }
   840 /* This causes a crash in testoverlay for some reason.  Apple bug? */
   841 #if 0
   842     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   843         && texture->format == SDL_PIXELFORMAT_ARGB8888) {
   844         /*
   845            if (renderdata->glTextureRangeAPPLE) {
   846            renderdata->glTextureRangeAPPLE(data->type,
   847            texture->h * data->pitch,
   848            data->pixels);
   849            }
   850          */
   851         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   852         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   853                                  texture_h, 0, format, type, data->pixels);
   854     } else
   855 #endif
   856 #endif
   857     {
   858 printf("teximage2d(%d,%d)\n", (int) texture_w, (int) texture_h);
   859         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   860                                  texture_h, 0, format, type, NULL);
   861     }
   862     result = renderdata->glGetError();
   863     if (result != GL_NO_ERROR) {
   864         GL_SetError("glTexImage2D()", result);
   865         return -1;
   866     }
   867     return 0;
   868 }
   869 
   870 static int
   871 GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   872                       void **pixels, int *pitch)
   873 {
   874     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   875 
   876     *pixels = data->pixels;
   877     *pitch = data->pitch;
   878     return 0;
   879 }
   880 
   881 static int
   882 GL_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   883                      const SDL_Color * colors, int firstcolor, int ncolors)
   884 {
   885     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   886     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   887     Uint8 *palette;
   888 
   889     if (!data->palette) {
   890         SDL_SetError("Texture doesn't have a palette");
   891         return -1;
   892     }
   893     palette = data->palette + firstcolor * 3;
   894     while (ncolors--) {
   895         *palette++ = colors->r;
   896         *palette++ = colors->g;
   897         *palette++ = colors->b;
   898         ++colors;
   899     }
   900     renderdata->glBindTexture(data->type, data->texture);
   901     renderdata->glColorTableEXT(data->type, GL_RGB8, 256, GL_RGB,
   902                                 GL_UNSIGNED_BYTE, data->palette);
   903     return 0;
   904 }
   905 
   906 static int
   907 GL_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   908                      SDL_Color * colors, int firstcolor, int ncolors)
   909 {
   910     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   911     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   912     Uint8 *palette;
   913 
   914     if (!data->palette) {
   915         SDL_SetError("Texture doesn't have a palette");
   916         return -1;
   917     }
   918     palette = data->palette + firstcolor * 3;
   919     while (ncolors--) {
   920         colors->r = *palette++;
   921         colors->g = *palette++;
   922         colors->b = *palette++;
   923         colors->unused = SDL_ALPHA_OPAQUE;
   924         ++colors;
   925     }
   926     return 0;
   927 }
   928 
   929 static void
   930 SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture,
   931                    int pitch)
   932 {
   933     if (texture->format == SDL_PIXELFORMAT_INDEX1LSB) {
   934         renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
   935     } else if (texture->format == SDL_PIXELFORMAT_INDEX1MSB) {
   936         renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
   937     }
   938     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   939     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   940                               (pitch / bytes_per_pixel(texture->format)) / ((GL_TextureData *)texture->driverdata)->HACK_RYAN_FIXME);
   941 }
   942 
   943 static int
   944 GL_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   945 {
   946     return 0;
   947 }
   948 
   949 static int
   950 GL_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   951 {
   952     return 0;
   953 }
   954 
   955 static int
   956 GL_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   957 {
   958     switch (texture->blendMode) {
   959     case SDL_TEXTUREBLENDMODE_NONE:
   960     case SDL_TEXTUREBLENDMODE_MASK:
   961     case SDL_TEXTUREBLENDMODE_BLEND:
   962     case SDL_TEXTUREBLENDMODE_ADD:
   963     case SDL_TEXTUREBLENDMODE_MOD:
   964         return 0;
   965     default:
   966         SDL_Unsupported();
   967         texture->blendMode = SDL_TEXTUREBLENDMODE_NONE;
   968         return -1;
   969     }
   970 }
   971 
   972 static int
   973 GL_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   974 {
   975     switch (texture->scaleMode) {
   976     case SDL_TEXTURESCALEMODE_NONE:
   977     case SDL_TEXTURESCALEMODE_FAST:
   978     case SDL_TEXTURESCALEMODE_SLOW:
   979         return 0;
   980     case SDL_TEXTURESCALEMODE_BEST:
   981         SDL_Unsupported();
   982         texture->scaleMode = SDL_TEXTURESCALEMODE_SLOW;
   983         return -1;
   984     default:
   985         SDL_Unsupported();
   986         texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
   987         return -1;
   988     }
   989 }
   990 
   991 static int
   992 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   993                  const SDL_Rect * rect, const void *pixels, int pitch)
   994 {
   995     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   996     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   997     GLenum result;
   998 
   999     renderdata->glGetError();
  1000     SetupTextureUpdate(renderdata, texture, pitch);
  1001     renderdata->glBindTexture(data->type, data->texture);
  1002 printf("texsubimage2d(%d,%d,%d,%d)\n", (int) rect->x, (int) rect->y, (int) rect->w, (int) rect->h);
  1003     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
  1004                                 rect->h, data->format, data->formattype,
  1005                                 pixels);
  1006     result = renderdata->glGetError();
  1007     if (result != GL_NO_ERROR) {
  1008         GL_SetError("glTexSubImage2D()", result);
  1009         return -1;
  1010     }
  1011     return 0;
  1012 }
  1013 
  1014 static int
  1015 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1016                const SDL_Rect * rect, int markDirty, void **pixels,
  1017                int *pitch)
  1018 {
  1019     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1020 
  1021     if (markDirty) {
  1022         SDL_AddDirtyRect(&data->dirty, rect);
  1023     }
  1024 
  1025     *pixels =
  1026         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
  1027                   rect->x * bytes_per_pixel(texture->format));
  1028     *pitch = data->pitch;
  1029     return 0;
  1030 }
  1031 
  1032 static void
  1033 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1034 {
  1035 }
  1036 
  1037 static void
  1038 GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
  1039                 const SDL_Rect * rects)
  1040 {
  1041     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1042     int i;
  1043 
  1044     for (i = 0; i < numrects; ++i) {
  1045         SDL_AddDirtyRect(&data->dirty, &rects[i]);
  1046     }
  1047 }
  1048 
  1049 static int
  1050 GL_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
  1051               const SDL_Rect * rect)
  1052 {
  1053     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1054     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
  1055 
  1056     data->glClearColor((GLclampf) r * inv255f, (GLclampf) g * inv255f,
  1057                        (GLclampf) b * inv255f, (GLclampf) a * inv255f);
  1058     data->glViewport(rect->x, window->h - rect->y, rect->w, rect->h);
  1059     data->glClear(GL_COLOR_BUFFER_BIT);
  1060     data->glViewport(0, 0, window->w, window->h);
  1061     return 0;
  1062 }
  1063 
  1064 static int
  1065 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1066               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1067 {
  1068     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1069     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1070     int minx, miny, maxx, maxy;
  1071     GLfloat minu, maxu, minv, maxv;
  1072 
  1073     if (texturedata->dirty.list) {
  1074         SDL_DirtyRect *dirty;
  1075         void *pixels;
  1076         int bpp = bytes_per_pixel(texture->format);
  1077         int pitch = texturedata->pitch;
  1078 
  1079         SetupTextureUpdate(data, texture, pitch);
  1080         data->glBindTexture(texturedata->type, texturedata->texture);
  1081         for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
  1082             SDL_Rect *rect = &dirty->rect;
  1083             pixels =
  1084                 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
  1085                           rect->x * bpp);
  1086 printf("texsubimage2d(%d,%d,%d,%d)\n", (int) rect->x, (int) rect->y, (int) rect->w, (int) rect->h);
  1087             data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
  1088                                   rect->w / texturedata->HACK_RYAN_FIXME, rect->h, texturedata->format,
  1089                                   texturedata->formattype, pixels);
  1090         }
  1091         SDL_ClearDirtyRects(&texturedata->dirty);
  1092     }
  1093 
  1094     minx = dstrect->x;
  1095     miny = dstrect->y;
  1096     maxx = dstrect->x + dstrect->w;
  1097     maxy = dstrect->y + dstrect->h;
  1098 
  1099     minu = (GLfloat) srcrect->x / texture->w;
  1100     minu *= texturedata->texw;
  1101     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1102     maxu *= texturedata->texw;
  1103     minv = (GLfloat) srcrect->y / texture->h;
  1104     minv *= texturedata->texh;
  1105     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1106     maxv *= texturedata->texh;
  1107 
  1108     data->glBindTexture(texturedata->type, texturedata->texture);
  1109 
  1110     if (texture->modMode) {
  1111         data->glColor4f((GLfloat) texture->r * inv255f,
  1112                         (GLfloat) texture->g * inv255f,
  1113                         (GLfloat) texture->b * inv255f,
  1114                         (GLfloat) texture->a * inv255f);
  1115     } else {
  1116         data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  1117     }
  1118 
  1119     if (texture->blendMode != data->blendMode) {
  1120         switch (texture->blendMode) {
  1121         case SDL_TEXTUREBLENDMODE_NONE:
  1122             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
  1123             data->glDisable(GL_BLEND);
  1124             break;
  1125         case SDL_TEXTUREBLENDMODE_MASK:
  1126         case SDL_TEXTUREBLENDMODE_BLEND:
  1127             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1128             data->glEnable(GL_BLEND);
  1129             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1130             break;
  1131         case SDL_TEXTUREBLENDMODE_ADD:
  1132             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1133             data->glEnable(GL_BLEND);
  1134             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  1135             break;
  1136         case SDL_TEXTUREBLENDMODE_MOD:
  1137             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1138             data->glEnable(GL_BLEND);
  1139             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
  1140             break;
  1141         }
  1142         data->blendMode = texture->blendMode;
  1143     }
  1144 
  1145     if (texture->scaleMode != data->scaleMode) {
  1146         switch (texture->scaleMode) {
  1147         case SDL_TEXTURESCALEMODE_NONE:
  1148         case SDL_TEXTURESCALEMODE_FAST:
  1149             data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
  1150                                   GL_NEAREST);
  1151             data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
  1152                                   GL_NEAREST);
  1153             break;
  1154         case SDL_TEXTURESCALEMODE_SLOW:
  1155         case SDL_TEXTURESCALEMODE_BEST:
  1156             data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
  1157                                   GL_LINEAR);
  1158             data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
  1159                                   GL_LINEAR);
  1160             break;
  1161         }
  1162         data->scaleMode = texture->scaleMode;
  1163     }
  1164 
  1165     if (texturedata->shader != 0) {
  1166         data->glEnable(GL_FRAGMENT_PROGRAM_ARB);
  1167         data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, texturedata->shader);
  1168     }
  1169 
  1170     data->glBegin(GL_TRIANGLE_STRIP);
  1171     data->glTexCoord2f(minu, minv);
  1172     data->glVertex2i(minx, miny);
  1173     data->glTexCoord2f(maxu, minv);
  1174     data->glVertex2i(maxx, miny);
  1175     data->glTexCoord2f(minu, maxv);
  1176     data->glVertex2i(minx, maxy);
  1177     data->glTexCoord2f(maxu, maxv);
  1178     data->glVertex2i(maxx, maxy);
  1179     data->glEnd();
  1180 
  1181     if (texturedata->shader != 0) {
  1182         data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
  1183     }
  1184     return 0;
  1185 }
  1186 
  1187 static void
  1188 GL_RenderPresent(SDL_Renderer * renderer)
  1189 {
  1190     SDL_GL_SwapWindow(renderer->window);
  1191 }
  1192 
  1193 static void
  1194 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1195 {
  1196     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  1197     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1198 
  1199     if (!data) {
  1200         return;
  1201     }
  1202     if (data->texture) {
  1203         renderdata->glDeleteTextures(1, &data->texture);
  1204     }
  1205     if (data->palette) {
  1206         SDL_free(data->palette);
  1207     }
  1208     if (data->pixels) {
  1209         SDL_free(data->pixels);
  1210     }
  1211     SDL_FreeDirtyRects(&data->dirty);
  1212     SDL_free(data);
  1213     texture->driverdata = NULL;
  1214 }
  1215 
  1216 static void
  1217 GL_DestroyRenderer(SDL_Renderer * renderer)
  1218 {
  1219     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1220 
  1221     if (data) {
  1222         if (data->context) {
  1223             if (data->GL_ARB_fragment_program_supported) {
  1224                 data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
  1225                 data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
  1226                 if (data->fragment_program_UYVY != 0) {
  1227                     data->glDeleteProgramsARB(1, &data->fragment_program_UYVY);
  1228                 }
  1229             }
  1230 
  1231             /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
  1232             SDL_GL_DeleteContext(data->context);
  1233         }
  1234         SDL_free(data);
  1235     }
  1236     SDL_free(renderer);
  1237 }
  1238 
  1239 #endif /* SDL_VIDEO_RENDER_OGL */
  1240 
  1241 /* vi: set ts=4 sw=4 expandtab: */