src/video/SDL_renderer_gl.c
author Bob Pendleton <bob@pendleton.com>
Fri, 09 Jan 2009 20:43:30 +0000
changeset 3011 8f4ed5ec2b06
parent 2937 017d4334accf
child 3013 8cc00819c8d6
permissions -rw-r--r--
I ran a global "make indent" it modified the following files.
     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     data->glEnable(GL_LINE_SMOOTH);
   427     if (data->GL_ARB_texture_rectangle_supported) {
   428         data->glEnable(GL_TEXTURE_RECTANGLE_ARB);
   429     } else {
   430         data->glEnable(GL_TEXTURE_2D);
   431     }
   432     data->updateSize = SDL_TRUE;
   433 
   434     return renderer;
   435 }
   436 
   437 static int
   438 GL_ActivateRenderer(SDL_Renderer * renderer)
   439 {
   440     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   441     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   442 
   443     if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
   444         return -1;
   445     }
   446     if (data->updateSize) {
   447         data->glMatrixMode(GL_PROJECTION);
   448         data->glLoadIdentity();
   449         data->glMatrixMode(GL_MODELVIEW);
   450         data->glLoadIdentity();
   451         data->glViewport(0, 0, window->w, window->h);
   452         data->glOrtho(0.0, (GLdouble) window->w, (GLdouble) window->h, 0.0,
   453                       0.0, 1.0);
   454         data->updateSize = SDL_FALSE;
   455     }
   456     return 0;
   457 }
   458 
   459 static int
   460 GL_DisplayModeChanged(SDL_Renderer * renderer)
   461 {
   462     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   463 
   464     /* Rebind the context to the window area and update matrices */
   465     data->updateSize = SDL_TRUE;
   466     return GL_ActivateRenderer(renderer);
   467 }
   468 
   469 static __inline__ int
   470 power_of_2(int input)
   471 {
   472     int value = 1;
   473 
   474     while (value < input) {
   475         value <<= 1;
   476     }
   477     return value;
   478 }
   479 
   480 
   481 //#define DEBUG_PROGRAM_COMPILE 1
   482 
   483 static GLuint
   484 compile_shader(GL_RenderData * data, GLenum shader_type, const char *_code)
   485 {
   486     const int have_texture_rects = data->GL_ARB_texture_rectangle_supported;
   487     const char *replacement = have_texture_rects ? "RECT" : "2D";
   488     const size_t replacementlen = SDL_strlen(replacement);
   489     const char *token = "%TEXTURETARGET%";
   490     const size_t tokenlen = SDL_strlen(token);
   491     char *code = NULL;
   492     char *ptr = NULL;
   493     GLuint program = 0;
   494 
   495     /*
   496      * The TEX instruction needs a different target depending on what we use.
   497      *  To handle this, we use "%TEXTURETARGET%" and replace the string before
   498      *  compiling the shader.
   499      */
   500     code = SDL_strdup(_code);
   501     if (code == NULL)
   502         return 0;
   503 
   504     for (ptr = SDL_strstr(code, token); ptr; ptr = SDL_strstr(ptr + 1, token)) {
   505         SDL_memcpy(ptr, replacement, replacementlen);
   506         SDL_memmove(ptr + replacementlen, ptr + tokenlen,
   507                     SDL_strlen(ptr + tokenlen) + 1);
   508     }
   509 
   510 #if DEBUG_PROGRAM_COMPILE
   511     printf("compiling shader:\n%s\n\n", code);
   512 #endif
   513 
   514     data->glGetError();         /* flush any existing error state. */
   515     data->glGenProgramsARB(1, &program);
   516     data->glBindProgramARB(shader_type, program);
   517     data->glProgramStringARB(shader_type, GL_PROGRAM_FORMAT_ASCII_ARB,
   518                              SDL_strlen(code), code);
   519 
   520     SDL_free(code);
   521 
   522     if (data->glGetError() == GL_INVALID_OPERATION) {
   523 #if DEBUG_PROGRAM_COMPILE
   524         GLint pos = 0;
   525         const GLubyte *errstr;
   526         data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
   527         errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
   528         printf("program compile error at position %d: %s\n\n",
   529                (int) pos, (const char *) errstr);
   530 #endif
   531         data->glBindProgramARB(shader_type, 0);
   532         data->glDeleteProgramsARB(1, &program);
   533         return 0;
   534     }
   535 
   536     return program;
   537 }
   538 
   539 
   540 /*
   541  * Fragment program that renders from UYVY textures.
   542  * The UYVY to RGB equasion is:
   543  *   R = 1.164(Y-16) + 1.596(Cr-128)
   544  *   G = 1.164(Y-16) - 0.813(Cr-128) - 0.391(Cb-128)
   545  *   B = 1.164(Y-16) + 2.018(Cb-128)
   546  * Byte layout is Cb, Y1, Cr, Y2, stored in the R, G, B, A channels.
   547  * 4 bytes == 2 pixels: Y1/Cb/Cr, Y2/Cb/Cr
   548  *
   549  * !!! FIXME: this ignores blendmodes, etc.
   550  * !!! FIXME: this could be more efficient...use a dot product for green, etc.
   551  */
   552 static const char *fragment_program_UYVY_source_code = "!!ARBfp1.0\n"
   553     /* outputs... */
   554     "OUTPUT outcolor = result.color;\n"
   555     /* scratch registers... */
   556     "TEMP uyvy;\n" "TEMP luminance;\n" "TEMP work;\n"
   557     /* Halve the coordinates to grab the correct 32 bits for the fragment. */
   558     "MUL work, fragment.texcoord, { 0.5, 1.0, 1.0, 1.0 };\n"
   559     /* Sample the YUV texture. Cb, Y1, Cr, Y2, are stored in x, y, z, w. */
   560     "TEX uyvy, work, texture[0], %TEXTURETARGET%;\n"
   561     /* Do subtractions (128/255, 16/255, 128/255, 16/255) */
   562     "SUB uyvy, uyvy, { 0.501960784313726, 0.06274509803922, 0.501960784313726, 0.06274509803922 };\n"
   563     /* Choose the luminance component by texcoord. */
   564     /* !!! FIXME: laziness wins out for now... just average Y1 and Y2. */
   565     "ADD luminance, uyvy.yyyy, uyvy.wwww;\n"
   566     "MUL luminance, luminance, { 0.5, 0.5, 0.5, 0.5 };\n"
   567     /* Multiply luminance by its magic value. */
   568     "MUL luminance, luminance, { 1.164, 1.164, 1.164, 1.164 };\n"
   569     /* uyvy.xyzw becomes Cr/Cr/Cb/Cb, with multiplications. */
   570     "MUL uyvy, uyvy.zzxx, { 1.596, -0.813, 2.018, -0.391 };\n"
   571     /* Add luminance to Cr and Cb, store to RGB channels. */
   572     "ADD work.rgb, luminance, uyvy;\n"
   573     /* Do final addition for Green channel.  (!!! FIXME: this should be a DPH?) */
   574     "ADD work.g, work.g, uyvy.w;\n"
   575     /* Make sure alpha channel is fully opaque.  (!!! FIXME: blend modes!) */
   576     "MOV work.a, { 1.0 };\n"
   577     /* Store out the final fragment color... */
   578     "MOV outcolor, work;\n"
   579     /* ...and we're done! */
   580     "END\n";
   581 
   582 
   583 static int
   584 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   585 {
   586     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   587     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   588     GL_TextureData *data;
   589     GLint internalFormat;
   590     GLenum format, type;
   591     int texture_w, texture_h;
   592     GLuint shader = 0;
   593     GLenum result;
   594 
   595     switch (texture->format) {
   596     case SDL_PIXELFORMAT_INDEX1LSB:
   597     case SDL_PIXELFORMAT_INDEX1MSB:
   598         internalFormat = GL_RGB;
   599         format = GL_COLOR_INDEX;
   600         type = GL_BITMAP;
   601         break;
   602     case SDL_PIXELFORMAT_INDEX8:
   603         if (!renderdata->GL_EXT_paletted_texture_supported) {
   604             SDL_SetError("Unsupported texture format");
   605             return -1;
   606         }
   607         internalFormat = GL_COLOR_INDEX8_EXT;
   608         format = GL_COLOR_INDEX;
   609         type = GL_UNSIGNED_BYTE;
   610         break;
   611     case SDL_PIXELFORMAT_RGB332:
   612         internalFormat = GL_R3_G3_B2;
   613         format = GL_RGB;
   614         type = GL_UNSIGNED_BYTE_3_3_2;
   615         break;
   616     case SDL_PIXELFORMAT_RGB444:
   617         internalFormat = GL_RGB4;
   618         format = GL_RGB;
   619         type = GL_UNSIGNED_SHORT_4_4_4_4;
   620         break;
   621     case SDL_PIXELFORMAT_RGB555:
   622         internalFormat = GL_RGB5;
   623         format = GL_RGB;
   624         type = GL_UNSIGNED_SHORT_5_5_5_1;
   625         break;
   626     case SDL_PIXELFORMAT_ARGB4444:
   627         internalFormat = GL_RGBA4;
   628         format = GL_BGRA;
   629         type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
   630         break;
   631     case SDL_PIXELFORMAT_ARGB1555:
   632         internalFormat = GL_RGB5_A1;
   633         format = GL_BGRA;
   634         type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
   635         break;
   636     case SDL_PIXELFORMAT_RGB565:
   637         internalFormat = GL_RGB8;
   638         format = GL_RGB;
   639         type = GL_UNSIGNED_SHORT_5_6_5;
   640         break;
   641     case SDL_PIXELFORMAT_RGB24:
   642         internalFormat = GL_RGB8;
   643         format = GL_RGB;
   644         type = GL_UNSIGNED_BYTE;
   645         break;
   646     case SDL_PIXELFORMAT_RGB888:
   647         internalFormat = GL_RGB8;
   648         format = GL_BGRA;
   649         type = GL_UNSIGNED_BYTE;
   650         break;
   651     case SDL_PIXELFORMAT_BGR24:
   652         internalFormat = GL_RGB8;
   653         format = GL_BGR;
   654         type = GL_UNSIGNED_BYTE;
   655         break;
   656     case SDL_PIXELFORMAT_BGR888:
   657         internalFormat = GL_RGB8;
   658         format = GL_RGBA;
   659         type = GL_UNSIGNED_BYTE;
   660         break;
   661     case SDL_PIXELFORMAT_ARGB8888:
   662 #ifdef __MACOSX__
   663         internalFormat = GL_RGBA;
   664         format = GL_BGRA;
   665         type = GL_UNSIGNED_INT_8_8_8_8_REV;
   666 #else
   667         internalFormat = GL_RGBA8;
   668         format = GL_BGRA;
   669         type = GL_UNSIGNED_BYTE;
   670 #endif
   671         break;
   672     case SDL_PIXELFORMAT_ABGR8888:
   673         internalFormat = GL_RGBA8;
   674         format = GL_RGBA;
   675         type = GL_UNSIGNED_BYTE;
   676         break;
   677     case SDL_PIXELFORMAT_ARGB2101010:
   678         internalFormat = GL_RGB10_A2;
   679         format = GL_BGRA;
   680         type = GL_UNSIGNED_INT_2_10_10_10_REV;
   681         break;
   682     case SDL_PIXELFORMAT_UYVY:
   683         if (renderdata->GL_APPLE_ycbcr_422_supported) {
   684             internalFormat = GL_RGB;
   685             format = GL_YCBCR_422_APPLE;
   686 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   687             type = GL_UNSIGNED_SHORT_8_8_APPLE;
   688 #else
   689             type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
   690 #endif
   691         } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
   692             internalFormat = GL_RGB;
   693             format = GL_YCBCR_MESA;
   694 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   695             type = GL_UNSIGNED_SHORT_8_8_MESA;
   696 #else
   697             type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
   698 #endif
   699         } else if (renderdata->GL_ARB_fragment_program_supported) {
   700             if (renderdata->fragment_program_UYVY == 0) {
   701                 renderdata->fragment_program_UYVY =
   702                     compile_shader(renderdata, GL_FRAGMENT_PROGRAM_ARB,
   703                                    fragment_program_UYVY_source_code);
   704                 if (renderdata->fragment_program_UYVY == 0) {
   705                     SDL_SetError("Fragment program compile error");
   706                     return -1;
   707                 }
   708             }
   709             shader = renderdata->fragment_program_UYVY;
   710             internalFormat = GL_RGBA;
   711             format = GL_RGBA;
   712             type = GL_UNSIGNED_BYTE;
   713         } else {
   714             SDL_SetError("Unsupported texture format");
   715             return -1;
   716         }
   717         break;
   718     case SDL_PIXELFORMAT_YUY2:
   719         if (renderdata->GL_APPLE_ycbcr_422_supported) {
   720             internalFormat = GL_RGB;
   721             format = GL_YCBCR_422_APPLE;
   722 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   723             type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
   724 #else
   725             type = GL_UNSIGNED_SHORT_8_8_APPLE;
   726 #endif
   727         } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
   728             internalFormat = GL_RGB;
   729             format = GL_YCBCR_MESA;
   730 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   731             type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
   732 #else
   733             type = GL_UNSIGNED_SHORT_8_8_MESA;
   734 #endif
   735         } else {
   736             SDL_SetError("Unsupported texture format");
   737             return -1;
   738         }
   739         break;
   740     default:
   741         SDL_SetError("Unsupported texture format");
   742         return -1;
   743     }
   744 
   745     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   746     if (!data) {
   747         SDL_OutOfMemory();
   748         return -1;
   749     }
   750 
   751     data->shader = shader;
   752 
   753     if (texture->format == SDL_PIXELFORMAT_INDEX8) {
   754         data->palette = (Uint8 *) SDL_malloc(3 * 256 * sizeof(Uint8));
   755         if (!data->palette) {
   756             SDL_OutOfMemory();
   757             SDL_free(data);
   758             return -1;
   759         }
   760         SDL_memset(data->palette, 0xFF, 3 * 256 * sizeof(Uint8));
   761     }
   762 
   763     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   764         data->pitch = texture->w * bytes_per_pixel(texture->format);
   765         data->pixels = SDL_malloc(texture->h * data->pitch);
   766         if (!data->pixels) {
   767             SDL_OutOfMemory();
   768             SDL_free(data);
   769             return -1;
   770         }
   771     }
   772 
   773     texture->driverdata = data;
   774 
   775     renderdata->glGetError();
   776     renderdata->glGenTextures(1, &data->texture);
   777     if (renderdata->GL_ARB_texture_rectangle_supported) {
   778         data->type = GL_TEXTURE_RECTANGLE_ARB;
   779         texture_w = texture->w;
   780         texture_h = texture->h;
   781         data->texw = (GLfloat) texture_w;
   782         data->texh = (GLfloat) texture_h;
   783     } else {
   784         data->type = GL_TEXTURE_2D;
   785         texture_w = power_of_2(texture->w);
   786         texture_h = power_of_2(texture->h);
   787         data->texw = (GLfloat) (texture->w) / texture_w;
   788         data->texh = (GLfloat) texture->h / texture_h;
   789     }
   790 
   791     /* YUV formats use RGBA but are really two bytes per pixel */
   792     if (internalFormat == GL_RGBA && bytes_per_pixel(texture->format) < 4) {
   793         data->HACK_RYAN_FIXME = 2;
   794     } else {
   795         data->HACK_RYAN_FIXME = 1;
   796     }
   797     texture_w /= data->HACK_RYAN_FIXME;
   798 
   799     data->format = format;
   800     data->formattype = type;
   801     renderdata->glEnable(data->type);
   802     renderdata->glBindTexture(data->type, data->texture);
   803     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   804                                 GL_NEAREST);
   805     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   806                                 GL_NEAREST);
   807     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   808                                 GL_CLAMP_TO_EDGE);
   809     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   810                                 GL_CLAMP_TO_EDGE);
   811 #ifdef __MACOSX__
   812 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   813 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   814 #endif
   815 #ifndef STORAGE_CACHED_APPLE
   816 #define STORAGE_CACHED_APPLE                0x85BE
   817 #endif
   818 #ifndef STORAGE_SHARED_APPLE
   819 #define STORAGE_SHARED_APPLE                0x85BF
   820 #endif
   821     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   822         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   823                                     GL_STORAGE_SHARED_APPLE);
   824     } else {
   825         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   826                                     GL_STORAGE_CACHED_APPLE);
   827     }
   828 /* This causes a crash in testoverlay for some reason.  Apple bug? */
   829 #if 0
   830     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   831         && texture->format == SDL_PIXELFORMAT_ARGB8888) {
   832         /*
   833            if (renderdata->glTextureRangeAPPLE) {
   834            renderdata->glTextureRangeAPPLE(data->type,
   835            texture->h * data->pitch,
   836            data->pixels);
   837            }
   838          */
   839         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   840         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   841                                  texture_h, 0, format, type, data->pixels);
   842     } else
   843 #endif
   844 #endif
   845     {
   846         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   847                                  texture_h, 0, format, type, NULL);
   848     }
   849     result = renderdata->glGetError();
   850     if (result != GL_NO_ERROR) {
   851         GL_SetError("glTexImage2D()", result);
   852         return -1;
   853     }
   854     return 0;
   855 }
   856 
   857 static int
   858 GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   859                       void **pixels, int *pitch)
   860 {
   861     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   862 
   863     *pixels = data->pixels;
   864     *pitch = data->pitch;
   865     return 0;
   866 }
   867 
   868 static int
   869 GL_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   870                      const SDL_Color * colors, int firstcolor, int ncolors)
   871 {
   872     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   873     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   874     Uint8 *palette;
   875 
   876     if (!data->palette) {
   877         SDL_SetError("Texture doesn't have a palette");
   878         return -1;
   879     }
   880     palette = data->palette + firstcolor * 3;
   881     while (ncolors--) {
   882         *palette++ = colors->r;
   883         *palette++ = colors->g;
   884         *palette++ = colors->b;
   885         ++colors;
   886     }
   887     renderdata->glEnable(data->type);
   888     renderdata->glBindTexture(data->type, data->texture);
   889     renderdata->glColorTableEXT(data->type, GL_RGB8, 256, GL_RGB,
   890                                 GL_UNSIGNED_BYTE, data->palette);
   891     return 0;
   892 }
   893 
   894 static int
   895 GL_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   896                      SDL_Color * colors, int firstcolor, int ncolors)
   897 {
   898     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   899     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   900     Uint8 *palette;
   901 
   902     if (!data->palette) {
   903         SDL_SetError("Texture doesn't have a palette");
   904         return -1;
   905     }
   906     palette = data->palette + firstcolor * 3;
   907     while (ncolors--) {
   908         colors->r = *palette++;
   909         colors->g = *palette++;
   910         colors->b = *palette++;
   911         colors->unused = SDL_ALPHA_OPAQUE;
   912         ++colors;
   913     }
   914     return 0;
   915 }
   916 
   917 static void
   918 SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture,
   919                    int pitch)
   920 {
   921     if (texture->format == SDL_PIXELFORMAT_INDEX1LSB) {
   922         renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
   923     } else if (texture->format == SDL_PIXELFORMAT_INDEX1MSB) {
   924         renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
   925     }
   926     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   927     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   928                               (pitch / bytes_per_pixel(texture->format)) /
   929                               ((GL_TextureData *) texture->
   930                                driverdata)->HACK_RYAN_FIXME);
   931 }
   932 
   933 static int
   934 GL_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   935 {
   936     return 0;
   937 }
   938 
   939 static int
   940 GL_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   941 {
   942     return 0;
   943 }
   944 
   945 static int
   946 GL_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   947 {
   948     switch (texture->blendMode) {
   949     case SDL_BLENDMODE_NONE:
   950     case SDL_BLENDMODE_MASK:
   951     case SDL_BLENDMODE_BLEND:
   952     case SDL_BLENDMODE_ADD:
   953     case SDL_BLENDMODE_MOD:
   954         return 0;
   955     default:
   956         SDL_Unsupported();
   957         texture->blendMode = SDL_BLENDMODE_NONE;
   958         return -1;
   959     }
   960 }
   961 
   962 static int
   963 GL_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   964 {
   965     switch (texture->scaleMode) {
   966     case SDL_TEXTURESCALEMODE_NONE:
   967     case SDL_TEXTURESCALEMODE_FAST:
   968     case SDL_TEXTURESCALEMODE_SLOW:
   969         return 0;
   970     case SDL_TEXTURESCALEMODE_BEST:
   971         SDL_Unsupported();
   972         texture->scaleMode = SDL_TEXTURESCALEMODE_SLOW;
   973         return -1;
   974     default:
   975         SDL_Unsupported();
   976         texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
   977         return -1;
   978     }
   979 }
   980 
   981 static int
   982 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   983                  const SDL_Rect * rect, const void *pixels, int pitch)
   984 {
   985     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   986     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   987     GLenum result;
   988 
   989     renderdata->glGetError();
   990     SetupTextureUpdate(renderdata, texture, pitch);
   991     renderdata->glEnable(data->type);
   992     renderdata->glBindTexture(data->type, data->texture);
   993     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   994                                 rect->h, data->format, data->formattype,
   995                                 pixels);
   996     result = renderdata->glGetError();
   997     if (result != GL_NO_ERROR) {
   998         GL_SetError("glTexSubImage2D()", result);
   999         return -1;
  1000     }
  1001     return 0;
  1002 }
  1003 
  1004 static int
  1005 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1006                const SDL_Rect * rect, int markDirty, void **pixels,
  1007                int *pitch)
  1008 {
  1009     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1010 
  1011     if (markDirty) {
  1012         SDL_AddDirtyRect(&data->dirty, rect);
  1013     }
  1014 
  1015     *pixels =
  1016         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
  1017                   rect->x * bytes_per_pixel(texture->format));
  1018     *pitch = data->pitch;
  1019     return 0;
  1020 }
  1021 
  1022 static void
  1023 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1024 {
  1025 }
  1026 
  1027 static void
  1028 GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
  1029                 const SDL_Rect * rects)
  1030 {
  1031     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1032     int i;
  1033 
  1034     for (i = 0; i < numrects; ++i) {
  1035         SDL_AddDirtyRect(&data->dirty, &rects[i]);
  1036     }
  1037 }
  1038 
  1039 static void
  1040 GL_SetBlendMode(GL_RenderData * data, int blendMode)
  1041 {
  1042     if (blendMode != data->blendMode) {
  1043         switch (blendMode) {
  1044         case SDL_BLENDMODE_NONE:
  1045             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  1046             data->glDisable(GL_BLEND);
  1047             break;
  1048         case SDL_BLENDMODE_MASK:
  1049         case SDL_BLENDMODE_BLEND:
  1050             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1051             data->glEnable(GL_BLEND);
  1052             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1053             break;
  1054         case SDL_BLENDMODE_ADD:
  1055             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1056             data->glEnable(GL_BLEND);
  1057             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  1058             break;
  1059         case SDL_BLENDMODE_MOD:
  1060             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1061             data->glEnable(GL_BLEND);
  1062             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
  1063             break;
  1064         }
  1065         data->blendMode = blendMode;
  1066     }
  1067 }
  1068 
  1069 static int
  1070 GL_RenderPoint(SDL_Renderer * renderer, int x, int y)
  1071 {
  1072     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1073 
  1074     GL_SetBlendMode(data, renderer->blendMode);
  1075 
  1076     data->glColor4f((GLfloat) renderer->r * inv255f,
  1077                     (GLfloat) renderer->g * inv255f,
  1078                     (GLfloat) renderer->b * inv255f,
  1079                     (GLfloat) renderer->a * inv255f);
  1080 
  1081     data->glBegin(GL_POINTS);
  1082     data->glVertex2i(x, y);
  1083     data->glEnd();
  1084 
  1085     return 0;
  1086 }
  1087 
  1088 static int
  1089 GL_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
  1090 {
  1091     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1092 
  1093     GL_SetBlendMode(data, renderer->blendMode);
  1094 
  1095     data->glColor4f((GLfloat) renderer->r * inv255f,
  1096                     (GLfloat) renderer->g * inv255f,
  1097                     (GLfloat) renderer->b * inv255f,
  1098                     (GLfloat) renderer->a * inv255f);
  1099 
  1100     data->glBegin(GL_LINES);
  1101     data->glVertex2i(x1, y1);
  1102     data->glVertex2i(x2, y2);
  1103     data->glEnd();
  1104 
  1105     return 0;
  1106 }
  1107 
  1108 static int
  1109 GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect)
  1110 {
  1111     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1112 
  1113     GL_SetBlendMode(data, renderer->blendMode);
  1114 
  1115     data->glColor4f((GLfloat) renderer->r * inv255f,
  1116                     (GLfloat) renderer->g * inv255f,
  1117                     (GLfloat) renderer->b * inv255f,
  1118                     (GLfloat) renderer->a * inv255f);
  1119 
  1120     data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
  1121 
  1122     return 0;
  1123 }
  1124 
  1125 static int
  1126 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1127               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1128 {
  1129     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1130     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
  1131     int minx, miny, maxx, maxy;
  1132     GLfloat minu, maxu, minv, maxv;
  1133 
  1134     if (texturedata->dirty.list) {
  1135         SDL_DirtyRect *dirty;
  1136         void *pixels;
  1137         int bpp = bytes_per_pixel(texture->format);
  1138         int pitch = texturedata->pitch;
  1139 
  1140         SetupTextureUpdate(data, texture, pitch);
  1141         data->glEnable(texturedata->type);
  1142         data->glBindTexture(texturedata->type, texturedata->texture);
  1143         for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
  1144             SDL_Rect *rect = &dirty->rect;
  1145             pixels =
  1146                 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
  1147                           rect->x * bpp);
  1148             data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
  1149                                   rect->w / texturedata->HACK_RYAN_FIXME,
  1150                                   rect->h, texturedata->format,
  1151                                   texturedata->formattype, pixels);
  1152         }
  1153         SDL_ClearDirtyRects(&texturedata->dirty);
  1154     }
  1155 
  1156     minx = dstrect->x;
  1157     miny = dstrect->y;
  1158     maxx = dstrect->x + dstrect->w;
  1159     maxy = dstrect->y + dstrect->h;
  1160 
  1161     minu = (GLfloat) srcrect->x / texture->w;
  1162     minu *= texturedata->texw;
  1163     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  1164     maxu *= texturedata->texw;
  1165     minv = (GLfloat) srcrect->y / texture->h;
  1166     minv *= texturedata->texh;
  1167     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  1168     maxv *= texturedata->texh;
  1169 
  1170     data->glEnable(texturedata->type);
  1171     data->glBindTexture(texturedata->type, texturedata->texture);
  1172 
  1173     if (texture->modMode) {
  1174         data->glColor4f((GLfloat) texture->r * inv255f,
  1175                         (GLfloat) texture->g * inv255f,
  1176                         (GLfloat) texture->b * inv255f,
  1177                         (GLfloat) texture->a * inv255f);
  1178     } else {
  1179         data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  1180     }
  1181 
  1182     GL_SetBlendMode(data, texture->blendMode);
  1183 
  1184     if (texture->scaleMode != data->scaleMode) {
  1185         switch (texture->scaleMode) {
  1186         case SDL_TEXTURESCALEMODE_NONE:
  1187         case SDL_TEXTURESCALEMODE_FAST:
  1188             data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
  1189                                   GL_NEAREST);
  1190             data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
  1191                                   GL_NEAREST);
  1192             break;
  1193         case SDL_TEXTURESCALEMODE_SLOW:
  1194         case SDL_TEXTURESCALEMODE_BEST:
  1195             data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
  1196                                   GL_LINEAR);
  1197             data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
  1198                                   GL_LINEAR);
  1199             break;
  1200         }
  1201         data->scaleMode = texture->scaleMode;
  1202     }
  1203 
  1204     if (texturedata->shader != 0) {
  1205         data->glEnable(GL_FRAGMENT_PROGRAM_ARB);
  1206         data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, texturedata->shader);
  1207     }
  1208 
  1209     data->glBegin(GL_TRIANGLE_STRIP);
  1210     data->glTexCoord2f(minu, minv);
  1211     data->glVertex2i(minx, miny);
  1212     data->glTexCoord2f(maxu, minv);
  1213     data->glVertex2i(maxx, miny);
  1214     data->glTexCoord2f(minu, maxv);
  1215     data->glVertex2i(minx, maxy);
  1216     data->glTexCoord2f(maxu, maxv);
  1217     data->glVertex2i(maxx, maxy);
  1218     data->glEnd();
  1219 
  1220     if (texturedata->shader != 0) {
  1221         data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
  1222     }
  1223 
  1224     data->glDisable(texturedata->type);
  1225 
  1226     return 0;
  1227 }
  1228 
  1229 static void
  1230 GL_RenderPresent(SDL_Renderer * renderer)
  1231 {
  1232     SDL_GL_SwapWindow(renderer->window);
  1233 }
  1234 
  1235 static void
  1236 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1237 {
  1238     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  1239     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  1240 
  1241     if (!data) {
  1242         return;
  1243     }
  1244     if (data->texture) {
  1245         renderdata->glDeleteTextures(1, &data->texture);
  1246     }
  1247     if (data->palette) {
  1248         SDL_free(data->palette);
  1249     }
  1250     if (data->pixels) {
  1251         SDL_free(data->pixels);
  1252     }
  1253     SDL_FreeDirtyRects(&data->dirty);
  1254     SDL_free(data);
  1255     texture->driverdata = NULL;
  1256 }
  1257 
  1258 static void
  1259 GL_DestroyRenderer(SDL_Renderer * renderer)
  1260 {
  1261     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  1262 
  1263     if (data) {
  1264         if (data->context) {
  1265             if (data->GL_ARB_fragment_program_supported) {
  1266                 data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
  1267                 data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
  1268                 if (data->fragment_program_UYVY != 0) {
  1269                     data->glDeleteProgramsARB(1,
  1270                                               &data->fragment_program_UYVY);
  1271                 }
  1272             }
  1273 
  1274             /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
  1275             SDL_GL_DeleteContext(data->context);
  1276         }
  1277         SDL_free(data);
  1278     }
  1279     SDL_free(renderer);
  1280 }
  1281 
  1282 #endif /* SDL_VIDEO_RENDER_OGL */
  1283 
  1284 /* vi: set ts=4 sw=4 expandtab: */