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