src/video/SDL_renderer_gl.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 22 Jul 2006 21:02:57 +0000
changeset 1924 69217fdd2c0a
parent 1923 d4572b97b08f
child 1926 307355678142
permissions -rw-r--r--
If the OpenGL renderer is selected for a non-OpenGL window, recreate the window with OpenGL enabled.
Added OpenGL renderer error checking.
Use fast-path texture formats in the OpenGL renderer.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_OPENGL
    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 /* OpenGL renderer implementation */
    34 
    35 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    36 static int GL_ActivateRenderer(SDL_Renderer * renderer);
    37 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    38 static int GL_SetTexturePalette(SDL_Renderer * renderer,
    39                                 SDL_Texture * texture,
    40                                 const SDL_Color * colors, int firstcolor,
    41                                 int ncolors);
    42 static int GL_GetTexturePalette(SDL_Renderer * renderer,
    43                                 SDL_Texture * texture, SDL_Color * colors,
    44                                 int firstcolor, int ncolors);
    45 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    46                             const SDL_Rect * rect, const void *pixels,
    47                             int pitch);
    48 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    49                           const SDL_Rect * rect, int markDirty,
    50                           void **pixels, int *pitch);
    51 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    52 static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    53                             int numrects, const SDL_Rect * rects);
    54 static int GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
    55                          Uint32 color);
    56 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    57                          const SDL_Rect * srcrect, const SDL_Rect * dstrect,
    58                          int blendMode, int scaleMode);
    59 static void GL_RenderPresent(SDL_Renderer * renderer);
    60 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    61 static void GL_DestroyRenderer(SDL_Renderer * renderer);
    62 
    63 
    64 SDL_RenderDriver GL_RenderDriver = {
    65     GL_CreateRenderer,
    66     {
    67      "opengl",
    68      (SDL_Renderer_PresentDiscard | SDL_Renderer_PresentVSync |
    69       SDL_Renderer_Accelerated),
    70      (SDL_TextureBlendMode_None | SDL_TextureBlendMode_Mask |
    71       SDL_TextureBlendMode_Blend | SDL_TextureBlendMode_Add |
    72       SDL_TextureBlendMode_Mod),
    73      (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast |
    74       SDL_TextureScaleMode_Slow),
    75      16,
    76      {
    77       SDL_PixelFormat_Index1LSB,
    78       SDL_PixelFormat_Index1MSB,
    79       SDL_PixelFormat_Index8,
    80       SDL_PixelFormat_RGB332,
    81       SDL_PixelFormat_RGB444,
    82       SDL_PixelFormat_RGB555,
    83       SDL_PixelFormat_ARGB4444,
    84       SDL_PixelFormat_ARGB1555,
    85       SDL_PixelFormat_RGB565,
    86       SDL_PixelFormat_RGB24,
    87       SDL_PixelFormat_BGR24,
    88       SDL_PixelFormat_RGB888,
    89       SDL_PixelFormat_BGR888,
    90       SDL_PixelFormat_ARGB8888,
    91       SDL_PixelFormat_ABGR8888,
    92       SDL_PixelFormat_ARGB2101010},
    93      0,
    94      0}
    95 };
    96 
    97 typedef struct
    98 {
    99     SDL_GLContext context;
   100 } GL_RenderData;
   101 
   102 typedef struct
   103 {
   104     GLuint texture;
   105     GLenum type;
   106     GLfloat texw;
   107     GLfloat texh;
   108     GLenum format;
   109     GLenum formattype;
   110     void *pixels;
   111     int pitch;
   112     SDL_DirtyRectList dirty;
   113 } GL_TextureData;
   114 
   115 
   116 static void
   117 GL_SetError(const char *prefix, GLenum result)
   118 {
   119     const char *error;
   120 
   121     switch (result) {
   122     case GL_NO_ERROR:
   123         error = "GL_NO_ERROR";
   124         break;
   125     case GL_INVALID_ENUM:
   126         error = "GL_INVALID_ENUM";
   127         break;
   128     case GL_INVALID_VALUE:
   129         error = "GL_INVALID_VALUE";
   130         break;
   131     case GL_INVALID_OPERATION:
   132         error = "GL_INVALID_OPERATION";
   133         break;
   134     case GL_STACK_OVERFLOW:
   135         error = "GL_STACK_OVERFLOW";
   136         break;
   137     case GL_STACK_UNDERFLOW:
   138         error = "GL_STACK_UNDERFLOW";
   139         break;
   140     case GL_OUT_OF_MEMORY:
   141         error = "GL_OUT_OF_MEMORY";
   142         break;
   143     case GL_TABLE_TOO_LARGE:
   144         error = "GL_TABLE_TOO_LARGE";
   145         break;
   146     default:
   147         error = "UNKNOWN";
   148         break;
   149     }
   150     SDL_SetError("%s: %s", prefix, error);
   151 }
   152 
   153 void
   154 GL_AddRenderDriver(_THIS)
   155 {
   156     if (_this->GL_CreateContext) {
   157         SDL_AddRenderDriver(0, &GL_RenderDriver);
   158     }
   159 }
   160 
   161 SDL_Renderer *
   162 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
   163 {
   164     SDL_Renderer *renderer;
   165     GL_RenderData *data;
   166 
   167     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   168         window->flags |= SDL_WINDOW_OPENGL;
   169         if (SDL_RecreateWindow(window) < 0) {
   170             return NULL;
   171         }
   172     }
   173 
   174     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   175     if (!renderer) {
   176         SDL_OutOfMemory();
   177         return NULL;
   178     }
   179 
   180     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   181     if (!data) {
   182         GL_DestroyRenderer(renderer);
   183         SDL_OutOfMemory();
   184         return NULL;
   185     }
   186 
   187     renderer->ActivateRenderer = GL_ActivateRenderer;
   188     renderer->CreateTexture = GL_CreateTexture;
   189     renderer->SetTexturePalette = GL_SetTexturePalette;
   190     renderer->GetTexturePalette = GL_GetTexturePalette;
   191     renderer->UpdateTexture = GL_UpdateTexture;
   192     renderer->LockTexture = GL_LockTexture;
   193     renderer->UnlockTexture = GL_UnlockTexture;
   194     renderer->DirtyTexture = GL_DirtyTexture;
   195     renderer->RenderFill = GL_RenderFill;
   196     renderer->RenderCopy = GL_RenderCopy;
   197     renderer->RenderPresent = GL_RenderPresent;
   198     renderer->DestroyTexture = GL_DestroyTexture;
   199     renderer->DestroyRenderer = GL_DestroyRenderer;
   200     renderer->info = GL_RenderDriver.info;
   201     renderer->window = window->id;
   202     renderer->driverdata = data;
   203 
   204     renderer->info.flags =
   205         (SDL_Renderer_PresentDiscard | SDL_Renderer_Accelerated);
   206 
   207     data->context = SDL_GL_CreateContext(window->id);
   208     if (!data->context) {
   209         GL_DestroyRenderer(renderer);
   210         return NULL;
   211     }
   212     if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
   213         GL_DestroyRenderer(renderer);
   214         return NULL;
   215     }
   216 
   217     if (flags & SDL_Renderer_PresentVSync) {
   218         SDL_GL_SetSwapInterval(1);
   219     } else {
   220         SDL_GL_SetSwapInterval(0);
   221     }
   222     if (SDL_GL_GetSwapInterval() > 0) {
   223         renderer->info.flags |= SDL_Renderer_PresentVSync;
   224     }
   225 
   226     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &renderer->info.max_texture_width);
   227     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &renderer->info.max_texture_height);
   228 
   229     /* FIXME: Check for GL_ARB_texture_rectangle and GL_EXT_texture_rectangle */
   230 
   231     /* Set up parameters for rendering */
   232     glDisable(GL_DEPTH_TEST);
   233     glDisable(GL_CULL_FACE);
   234 #ifdef USE_GL_TEXTURE_RECTANGLE
   235     glEnable(GL_TEXTURE_RECTANGLE_ARB);
   236 #else
   237     glEnable(GL_TEXTURE_2D);
   238 #endif
   239     glMatrixMode(GL_PROJECTION);
   240     glLoadIdentity();
   241     glMatrixMode(GL_MODELVIEW);
   242     glLoadIdentity();
   243     glViewport(0, 0, window->w, window->h);
   244     glOrtho(0.0, (GLdouble) window->w, (GLdouble) window->h, 0.0, 0.0, 1.0);
   245 
   246     return renderer;
   247 }
   248 
   249 static int
   250 GL_ActivateRenderer(SDL_Renderer * renderer)
   251 {
   252     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   253     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   254 
   255     return SDL_GL_MakeCurrent(window->id, data->context);
   256 }
   257 
   258 static __inline__ int
   259 power_of_2(int input)
   260 {
   261     int value = 1;
   262 
   263     while (value < input) {
   264         value <<= 1;
   265     }
   266     return value;
   267 }
   268 
   269 static int
   270 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   271 {
   272     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   273     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   274     GL_TextureData *data;
   275     GLint internalFormat;
   276     GLenum format, type;
   277     int texture_w, texture_h;
   278     GLenum result;
   279 
   280     switch (texture->format) {
   281     case SDL_PixelFormat_Index1LSB:
   282     case SDL_PixelFormat_Index1MSB:
   283         internalFormat = GL_RGB;
   284         format = GL_COLOR_INDEX;
   285         type = GL_BITMAP;
   286         break;
   287     case SDL_PixelFormat_Index8:
   288         internalFormat = GL_RGB;
   289         format = GL_COLOR_INDEX;
   290         type = GL_UNSIGNED_BYTE;
   291         break;
   292     case SDL_PixelFormat_RGB332:
   293         internalFormat = GL_R3_G3_B2;
   294         format = GL_RGB;
   295         type = GL_UNSIGNED_BYTE_3_3_2;
   296         break;
   297     case SDL_PixelFormat_RGB444:
   298         internalFormat = GL_RGB4;
   299         format = GL_RGB;
   300         type = GL_UNSIGNED_SHORT_4_4_4_4;
   301         break;
   302     case SDL_PixelFormat_RGB555:
   303         internalFormat = GL_RGB5;
   304         format = GL_RGB;
   305         type = GL_UNSIGNED_SHORT_5_5_5_1;
   306         break;
   307     case SDL_PixelFormat_ARGB4444:
   308         internalFormat = GL_RGBA4;
   309         format = GL_BGRA;
   310         type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
   311         break;
   312     case SDL_PixelFormat_ARGB1555:
   313         internalFormat = GL_RGB5_A1;
   314         format = GL_BGRA;
   315         type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
   316         break;
   317     case SDL_PixelFormat_RGB565:
   318         internalFormat = GL_RGB8;
   319         format = GL_RGB;
   320         type = GL_UNSIGNED_SHORT_5_6_5;
   321         break;
   322     case SDL_PixelFormat_RGB24:
   323         internalFormat = GL_RGB8;
   324         format = GL_RGB;
   325         type = GL_UNSIGNED_BYTE;
   326         break;
   327     case SDL_PixelFormat_RGB888:
   328         internalFormat = GL_RGB8;
   329         format = GL_BGRA;
   330         type = GL_UNSIGNED_BYTE;
   331         break;
   332     case SDL_PixelFormat_BGR24:
   333         internalFormat = GL_RGB8;
   334         format = GL_BGR;
   335         type = GL_UNSIGNED_BYTE;
   336         break;
   337     case SDL_PixelFormat_BGR888:
   338         internalFormat = GL_RGB8;
   339         format = GL_RGBA;
   340         type = GL_UNSIGNED_BYTE;
   341         break;
   342     case SDL_PixelFormat_ARGB8888:
   343         internalFormat = GL_RGBA8;
   344         format = GL_BGRA;
   345         type = GL_UNSIGNED_BYTE;
   346         break;
   347     case SDL_PixelFormat_ABGR8888:
   348         internalFormat = GL_RGBA8;
   349         format = GL_RGBA;
   350         type = GL_UNSIGNED_BYTE;
   351         break;
   352     case SDL_PixelFormat_ARGB2101010:
   353         internalFormat = GL_RGB10_A2;
   354         format = GL_BGRA;
   355         type = GL_UNSIGNED_INT_2_10_10_10_REV;
   356         break;
   357     default:
   358         SDL_SetError("Unsupported texture format");
   359         return -1;
   360     }
   361 
   362     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   363     if (!data) {
   364         SDL_OutOfMemory();
   365         return -1;
   366     }
   367 
   368     texture->driverdata = data;
   369 
   370     glGetError();
   371     glGenTextures(1, &data->texture);
   372 #ifdef USE_GL_TEXTURE_RECTANGLE
   373     data->type = GL_TEXTURE_RECTANGLE_ARB;
   374     texture_w = texture->w;
   375     texture_h = texture->h;
   376     data->texw = (GLfloat) texture->w;
   377     data->texh = (GLfloat) texture->h;
   378 #else
   379     data->type = GL_TEXTURE_2D;
   380     texture_w = power_of_2(texture->w);
   381     texture_h = power_of_2(texture->h);
   382     data->texw = (GLfloat) texture->w / texture_w;
   383     data->texh = (GLfloat) texture->h / texture_h;
   384 #endif
   385     data->format = format;
   386     data->formattype = type;
   387     glBindTexture(data->type, data->texture);
   388     glTexImage2D(data->type, 0, internalFormat, texture_w, texture_h, 0,
   389                  format, type, NULL);
   390     result = glGetError();
   391     if (result != GL_NO_ERROR) {
   392         GL_SetError("glTexImage2D()", result);
   393         return -1;
   394     }
   395     return 0;
   396 }
   397 
   398 static int
   399 GL_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   400                      const SDL_Color * colors, int firstcolor, int ncolors)
   401 {
   402     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   403     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   404 
   405     return 0;
   406 }
   407 
   408 static int
   409 GL_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   410                      SDL_Color * colors, int firstcolor, int ncolors)
   411 {
   412     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   413 
   414     return 0;
   415 }
   416 
   417 static void
   418 SetupTextureUpdate(SDL_Texture * texture, int pitch)
   419 {
   420     if (texture->format == SDL_PixelFormat_Index1LSB) {
   421         glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
   422     } else if (texture->format == SDL_PixelFormat_Index1MSB) {
   423         glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
   424     }
   425     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   426     glPixelStorei(GL_UNPACK_ROW_LENGTH,
   427                   pitch / SDL_BYTESPERPIXEL(texture->format));
   428 }
   429 
   430 static int
   431 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   432                  const SDL_Rect * rect, const void *pixels, int pitch)
   433 {
   434     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   435     GLenum result;
   436 
   437     glGetError();
   438     SetupTextureUpdate(texture, pitch);
   439     glBindTexture(data->type, data->texture);
   440     glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, rect->h,
   441                     data->format, data->formattype, pixels);
   442     result = glGetError();
   443     if (result != GL_NO_ERROR) {
   444         GL_SetError("glTexSubImage2D()", result);
   445         return -1;
   446     }
   447     return 0;
   448 }
   449 
   450 static int
   451 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   452                const SDL_Rect * rect, int markDirty, void **pixels,
   453                int *pitch)
   454 {
   455     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   456 
   457     if (!data->pixels) {
   458         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   459         data->pixels = SDL_malloc(texture->h * data->pitch);
   460         if (!data->pixels) {
   461             SDL_OutOfMemory();
   462             return -1;
   463         }
   464     }
   465 
   466     if (markDirty) {
   467         SDL_AddDirtyRect(&data->dirty, rect);
   468     }
   469 
   470     *pixels =
   471         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   472                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   473     *pitch = data->pitch;
   474     return 0;
   475 }
   476 
   477 static void
   478 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   479 {
   480 }
   481 
   482 static void
   483 GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
   484                 const SDL_Rect * rects)
   485 {
   486     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   487     int i;
   488 
   489     for (i = 0; i < numrects; ++i) {
   490         SDL_AddDirtyRect(&data->dirty, &rects[i]);
   491     }
   492 }
   493 
   494 static int
   495 GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 color)
   496 {
   497     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   498     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   499     GLclampf r, g, b, a;
   500 
   501     a = ((GLclampf) ((color >> 24) & 0xFF)) / 255.0f;
   502     r = ((GLclampf) ((color >> 16) & 0xFF)) / 255.0f;
   503     g = ((GLclampf) ((color >> 8) & 0xFF)) / 255.0f;
   504     b = ((GLclampf) (color & 0xFF)) / 255.0f;
   505 
   506     glClearColor(r, g, b, a);
   507     glViewport(rect->x, window->h - rect->y, rect->w, rect->h);
   508     glClear(GL_COLOR_BUFFER_BIT);
   509     glViewport(0, 0, window->w, window->h);
   510     return 0;
   511 }
   512 
   513 static int
   514 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   515               const SDL_Rect * srcrect, const SDL_Rect * dstrect,
   516               int blendMode, int scaleMode)
   517 {
   518     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   519     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   520     int minx, miny, maxx, maxy;
   521     GLfloat minu, maxu, minv, maxv;
   522 
   523     if (texturedata->dirty.count > 0) {
   524         SDL_DirtyRect *dirty;
   525         void *pixels;
   526         int bpp = SDL_BYTESPERPIXEL(texture->format);
   527         int pitch = texturedata->pitch;
   528 
   529         SetupTextureUpdate(texture, pitch);
   530         glBindTexture(texturedata->type, texturedata->texture);
   531         for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
   532             SDL_Rect *rect = &dirty->rect;
   533             pixels =
   534                 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
   535                           rect->x * bpp);
   536             glTexSubImage2D(texturedata->type, 0, rect->x, rect->y, rect->w,
   537                             rect->h, texturedata->format,
   538                             texturedata->formattype, pixels);
   539         }
   540         SDL_ClearDirtyRects(&texturedata->dirty);
   541     }
   542 
   543     minx = dstrect->x;
   544     miny = dstrect->y;
   545     maxx = dstrect->x + dstrect->w;
   546     maxy = dstrect->y + dstrect->h;
   547 
   548     minu = (GLfloat) srcrect->x / texture->w;
   549     minu *= texturedata->texw;
   550     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   551     maxu *= texturedata->texw;
   552     minv = (GLfloat) srcrect->y / texture->h;
   553     minv *= texturedata->texh;
   554     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   555     maxv *= texturedata->texh;
   556 
   557     glBindTexture(texturedata->type, texturedata->texture);
   558 
   559     switch (blendMode) {
   560     case SDL_TextureBlendMode_None:
   561         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
   562         glDisable(GL_BLEND);
   563         break;
   564     case SDL_TextureBlendMode_Mask:
   565     case SDL_TextureBlendMode_Blend:
   566         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   567         glEnable(GL_BLEND);
   568         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   569         break;
   570     case SDL_TextureBlendMode_Add:
   571         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   572         glEnable(GL_BLEND);
   573         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   574         break;
   575     case SDL_TextureBlendMode_Mod:
   576         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   577         glEnable(GL_BLEND);
   578         glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   579         break;
   580     }
   581 
   582     switch (scaleMode) {
   583     case SDL_TextureScaleMode_None:
   584     case SDL_TextureScaleMode_Fast:
   585         glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   586         glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   587         break;
   588     case SDL_TextureScaleMode_Slow:
   589     case SDL_TextureScaleMode_Best:
   590         glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   591         glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   592         break;
   593     }
   594 
   595     glBegin(GL_TRIANGLE_STRIP);
   596     glTexCoord2f(minu, minv);
   597     glVertex2i(minx, miny);
   598     glTexCoord2f(maxu, minv);
   599     glVertex2i(maxx, miny);
   600     glTexCoord2f(minu, maxv);
   601     glVertex2i(minx, maxy);
   602     glTexCoord2f(maxu, maxv);
   603     glVertex2i(maxx, maxy);
   604     glEnd();
   605 
   606     return 0;
   607 }
   608 
   609 static void
   610 GL_RenderPresent(SDL_Renderer * renderer)
   611 {
   612     SDL_GL_SwapWindow(renderer->window);
   613 }
   614 
   615 static void
   616 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   617 {
   618     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   619 
   620     if (!data) {
   621         return;
   622     }
   623     if (data->texture) {
   624         glDeleteTextures(1, &data->texture);
   625     }
   626     if (data->pixels) {
   627         SDL_free(data->pixels);
   628     }
   629     SDL_FreeDirtyRects(&data->dirty);
   630     SDL_free(data);
   631     texture->driverdata = NULL;
   632 }
   633 
   634 void
   635 GL_DestroyRenderer(SDL_Renderer * renderer)
   636 {
   637     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   638 
   639     if (data) {
   640         if (data->context) {
   641             SDL_GL_MakeCurrent(0, NULL);
   642             SDL_GL_DeleteContext(data->context);
   643         }
   644         SDL_free(data);
   645     }
   646     SDL_free(renderer);
   647 }
   648 
   649 #endif /* SDL_VIDEO_OPENGL */
   650 
   651 /* vi: set ts=4 sw=4 expandtab: */