src/video/SDL_renderer_gles.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 08 Dec 2008 00:27:32 +0000
changeset 2859 99210400e8b9
parent 2753 0969758c8809
child 2884 9dde605c7540
permissions -rw-r--r--
Updated copyright date
     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_ES
    25 
    26 #include "SDL_video.h"
    27 #include "SDL_opengles.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 ES 1.1 renderer implementation, based on the OpenGL renderer */
    34 
    35 static const float inv255f = 1.0f / 255.0f;
    36 
    37 static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
    38 static int GLES_ActivateRenderer(SDL_Renderer * renderer);
    39 static int GLES_DisplayModeChanged(SDL_Renderer * renderer);
    40 static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    41 static int GLES_QueryTexturePixels(SDL_Renderer * renderer,
    42                                    SDL_Texture * texture, void **pixels,
    43                                    int *pitch);
    44 static int GLES_SetTexturePalette(SDL_Renderer * renderer,
    45                                   SDL_Texture * texture,
    46                                   const SDL_Color * colors, int firstcolor,
    47                                   int ncolors);
    48 static int GLES_GetTexturePalette(SDL_Renderer * renderer,
    49                                   SDL_Texture * texture, SDL_Color * colors,
    50                                   int firstcolor, int ncolors);
    51 static int GLES_SetTextureColorMod(SDL_Renderer * renderer,
    52                                    SDL_Texture * texture);
    53 static int GLES_SetTextureAlphaMod(SDL_Renderer * renderer,
    54                                    SDL_Texture * texture);
    55 static int GLES_SetTextureBlendMode(SDL_Renderer * renderer,
    56                                     SDL_Texture * texture);
    57 static int GLES_SetTextureScaleMode(SDL_Renderer * renderer,
    58                                     SDL_Texture * texture);
    59 static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    60                               const SDL_Rect * rect, const void *pixels,
    61                               int pitch);
    62 static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    63                             const SDL_Rect * rect, int markDirty,
    64                             void **pixels, int *pitch);
    65 static void GLES_UnlockTexture(SDL_Renderer * renderer,
    66                                SDL_Texture * texture);
    67 static void GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    68                               int numrects, const SDL_Rect * rects);
    69 static int GLES_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b,
    70                            Uint8 a, const SDL_Rect * rect);
    71 static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    72                            const SDL_Rect * srcrect,
    73                            const SDL_Rect * dstrect);
    74 static void GLES_RenderPresent(SDL_Renderer * renderer);
    75 static void GLES_DestroyTexture(SDL_Renderer * renderer,
    76                                 SDL_Texture * texture);
    77 static void GLES_DestroyRenderer(SDL_Renderer * renderer);
    78 
    79 
    80 SDL_RenderDriver GL_ES_RenderDriver = {
    81     GLES_CreateRenderer,
    82     {
    83      "opengl_es",
    84      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD |
    85       SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
    86      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
    87       SDL_TEXTUREMODULATE_ALPHA),
    88      (SDL_TEXTUREBLENDMODE_NONE | SDL_TEXTUREBLENDMODE_MASK |
    89       SDL_TEXTUREBLENDMODE_BLEND | SDL_TEXTUREBLENDMODE_ADD |
    90       SDL_TEXTUREBLENDMODE_MOD),
    91      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST |
    92       SDL_TEXTURESCALEMODE_SLOW), 2,
    93      {
    94       SDL_PIXELFORMAT_RGB24,
    95       SDL_PIXELFORMAT_ABGR8888,
    96       },
    97      0,
    98      0}
    99 };
   100 
   101 typedef struct
   102 {
   103     SDL_GLContext context;
   104     SDL_bool updateSize;
   105     int blendMode;
   106 
   107 #ifndef APIENTRY
   108 #define APIENTRY
   109 #endif
   110 
   111     SDL_bool useDrawTexture;
   112     SDL_bool GL_OES_draw_texture_supported;
   113 
   114     /* OpenGL ES functions */
   115 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   116 #include "SDL_glesfuncs.h"
   117 #undef SDL_PROC
   118 
   119 } GLES_RenderData;
   120 
   121 typedef struct
   122 {
   123     GLuint texture;
   124     GLenum type;
   125     GLfloat texw;
   126     GLfloat texh;
   127     GLenum format;
   128     GLenum formattype;
   129     void *pixels;
   130     int pitch;
   131     SDL_DirtyRectList dirty;
   132 } GLES_TextureData;
   133 
   134 static void
   135 GLES_SetError(const char *prefix, GLenum result)
   136 {
   137     const char *error;
   138 
   139     switch (result) {
   140     case GL_NO_ERROR:
   141         error = "GL_NO_ERROR";
   142         break;
   143     case GL_INVALID_ENUM:
   144         error = "GL_INVALID_ENUM";
   145         break;
   146     case GL_INVALID_VALUE:
   147         error = "GL_INVALID_VALUE";
   148         break;
   149     case GL_INVALID_OPERATION:
   150         error = "GL_INVALID_OPERATION";
   151         break;
   152     case GL_STACK_OVERFLOW:
   153         error = "GL_STACK_OVERFLOW";
   154         break;
   155     case GL_STACK_UNDERFLOW:
   156         error = "GL_STACK_UNDERFLOW";
   157         break;
   158     case GL_OUT_OF_MEMORY:
   159         error = "GL_OUT_OF_MEMORY";
   160         break;
   161     default:
   162         error = "UNKNOWN";
   163         break;
   164     }
   165     SDL_SetError("%s: %s", prefix, error);
   166 }
   167 
   168 static int
   169 GLES_LoadFunctions(GLES_RenderData * data)
   170 {
   171 
   172 #define SDL_PROC(ret,func,params) \
   173 	data->func = func;
   174 #include "SDL_glesfuncs.h"
   175 #undef SDL_PROC
   176 
   177     return 0;
   178 }
   179 
   180 void
   181 GLES_AddRenderDriver(_THIS)
   182 {
   183     if (_this->GL_CreateContext) {
   184         SDL_AddRenderDriver(0, &GL_ES_RenderDriver);
   185     }
   186 }
   187 
   188 SDL_Renderer *
   189 GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
   190 {
   191 
   192     SDL_Renderer *renderer;
   193     GLES_RenderData *data;
   194     GLint value;
   195     int doublebuffer;
   196 
   197     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   198         if (SDL_RecreateWindow(window, window->flags | SDL_WINDOW_OPENGL) < 0) {
   199             return NULL;
   200         }
   201     }
   202 
   203     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   204     if (!renderer) {
   205         SDL_OutOfMemory();
   206         return NULL;
   207     }
   208 
   209     data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
   210     if (!data) {
   211         GLES_DestroyRenderer(renderer);
   212         SDL_OutOfMemory();
   213         return NULL;
   214     }
   215 
   216     renderer->ActivateRenderer = GLES_ActivateRenderer;
   217     renderer->DisplayModeChanged = GLES_DisplayModeChanged;
   218     renderer->CreateTexture = GLES_CreateTexture;
   219     renderer->QueryTexturePixels = GLES_QueryTexturePixels;
   220     renderer->SetTexturePalette = GLES_SetTexturePalette;
   221     renderer->GetTexturePalette = GLES_GetTexturePalette;
   222     renderer->SetTextureColorMod = GLES_SetTextureColorMod;
   223     renderer->SetTextureAlphaMod = GLES_SetTextureAlphaMod;
   224     renderer->SetTextureBlendMode = GLES_SetTextureBlendMode;
   225     renderer->SetTextureScaleMode = GLES_SetTextureScaleMode;
   226     renderer->UpdateTexture = GLES_UpdateTexture;
   227     renderer->LockTexture = GLES_LockTexture;
   228     renderer->UnlockTexture = GLES_UnlockTexture;
   229     renderer->DirtyTexture = GLES_DirtyTexture;
   230     renderer->RenderFill = GLES_RenderFill;
   231     renderer->RenderCopy = GLES_RenderCopy;
   232     renderer->RenderPresent = GLES_RenderPresent;
   233     renderer->DestroyTexture = GLES_DestroyTexture;
   234     renderer->DestroyRenderer = GLES_DestroyRenderer;
   235     renderer->info = GL_ES_RenderDriver.info;
   236     renderer->window = window->id;
   237     renderer->driverdata = data;
   238 
   239 
   240     renderer->info.flags =
   241         (SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED);
   242 
   243     if (GLES_LoadFunctions(data) < 0) {
   244         GLES_DestroyRenderer(renderer);
   245         return NULL;
   246     }
   247 
   248     data->context = SDL_GL_CreateContext(window->id);
   249     if (!data->context) {
   250         GLES_DestroyRenderer(renderer);
   251         return NULL;
   252     }
   253     if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
   254         GLES_DestroyRenderer(renderer);
   255         return NULL;
   256     }
   257 
   258     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   259         SDL_GL_SetSwapInterval(1);
   260     } else {
   261         SDL_GL_SetSwapInterval(0);
   262     }
   263     if (SDL_GL_GetSwapInterval() > 0) {
   264         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   265     }
   266 
   267     if (SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doublebuffer) == 0) {
   268         if (!doublebuffer) {
   269             renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER;
   270         }
   271     }
   272 
   273     if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) {
   274         data->GL_OES_draw_texture_supported = SDL_TRUE;
   275         data->useDrawTexture = SDL_TRUE;
   276     } else {
   277         data->GL_OES_draw_texture_supported = SDL_FALSE;
   278         data->useDrawTexture = SDL_FALSE;
   279     }
   280 
   281     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   282     renderer->info.max_texture_width = value;
   283     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   284     renderer->info.max_texture_height = value;
   285 
   286     /* Set up parameters for rendering */
   287     data->blendMode = -1;
   288     data->glDisable(GL_DEPTH_TEST);
   289     data->glDisable(GL_CULL_FACE);
   290     data->glEnable(GL_TEXTURE_2D);
   291     data->updateSize = SDL_TRUE;
   292 
   293     return renderer;
   294 }
   295 
   296 static int
   297 GLES_ActivateRenderer(SDL_Renderer * renderer)
   298 {
   299 
   300     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   301     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   302 
   303     if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
   304         return -1;
   305     }
   306     if (data->updateSize) {
   307         data->glMatrixMode(GL_PROJECTION);
   308         data->glLoadIdentity();
   309         data->glMatrixMode(GL_MODELVIEW);
   310         data->glLoadIdentity();
   311         data->glViewport(0, 0, window->w, window->h);
   312         data->glOrthof(0.0, (GLfloat) window->w, (GLfloat) window->h, 0.0,
   313                        0.0, 1.0);
   314         data->updateSize = SDL_FALSE;
   315     }
   316     return 0;
   317 }
   318 
   319 static int
   320 GLES_DisplayModeChanged(SDL_Renderer * renderer)
   321 {
   322     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   323 
   324     data->updateSize = SDL_TRUE;
   325     return 0;
   326 }
   327 
   328 static __inline__ int
   329 power_of_2(int input)
   330 {
   331     int value = 1;
   332 
   333     while (value < input) {
   334         value <<= 1;
   335     }
   336     return value;
   337 }
   338 
   339 static int
   340 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   341 {
   342     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   343     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   344     GLES_TextureData *data;
   345     GLint internalFormat;
   346     GLenum format, type;
   347     int texture_w, texture_h;
   348     GLenum result;
   349     switch (texture->format) {
   350     case SDL_PIXELFORMAT_INDEX1LSB:
   351     case SDL_PIXELFORMAT_INDEX1MSB:
   352     case SDL_PIXELFORMAT_INDEX8:
   353     case SDL_PIXELFORMAT_RGB332:
   354     case SDL_PIXELFORMAT_RGB444:
   355     case SDL_PIXELFORMAT_RGB555:
   356     case SDL_PIXELFORMAT_ARGB4444:
   357     case SDL_PIXELFORMAT_ARGB1555:
   358     case SDL_PIXELFORMAT_BGR24:
   359     case SDL_PIXELFORMAT_BGR888:
   360     case SDL_PIXELFORMAT_RGB888:
   361     case SDL_PIXELFORMAT_RGBA8888:
   362     case SDL_PIXELFORMAT_ARGB2101010:
   363     case SDL_PIXELFORMAT_ARGB8888:
   364     case SDL_PIXELFORMAT_RGB24:
   365         internalFormat = GL_RGB;
   366         format = GL_RGB;
   367         type = GL_UNSIGNED_BYTE;
   368         break;
   369     case SDL_PIXELFORMAT_ABGR8888:
   370         internalFormat = GL_RGBA;
   371         format = GL_RGBA;
   372         type = GL_UNSIGNED_BYTE;
   373         break;
   374         /*
   375            These formats would be supported if SDL had the necessary pixel formats
   376            case SDL_PIXELFORMAT_BGR565:
   377            internalFormat = GL_RGB;
   378            format = GL_RGB;
   379            type = GL_UNSIGNED_SHORT_5_6_5;
   380            break;                       
   381            case SDL_PIXELFORMAT_ABGR5551:
   382            internalFormat = GL_RGBA;
   383            format = GL_RGBA;
   384            type = GL_UNSIGNED_SHORT_5_5_5_1;
   385            break;
   386            case SDL_PIXELFORMAT_ABGR4444:
   387            internalFormat = GL_RGBA;
   388            format = GL_RGBA;
   389            type = GL_UNSIGNED_SHORT_4_4_4_4;
   390            break;
   391          */
   392     default:
   393         SDL_SetError("Unsupported texture format");
   394         return -1;
   395     }
   396 
   397     data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data));
   398     if (!data) {
   399         SDL_OutOfMemory();
   400         return -1;
   401     }
   402 
   403     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   404         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   405         data->pixels = SDL_malloc(texture->h * data->pitch);
   406         if (!data->pixels) {
   407             SDL_OutOfMemory();
   408             SDL_free(data);
   409             return -1;
   410         }
   411     }
   412 
   413     texture->driverdata = data;
   414 
   415     renderdata->glGetError();
   416     renderdata->glGenTextures(1, &data->texture);
   417 
   418     data->type = GL_TEXTURE_2D;
   419     /* no NPOV textures allowed in OpenGL ES (yet) */
   420     texture_w = power_of_2(texture->w);
   421     texture_h = power_of_2(texture->h);
   422     data->texw = (GLfloat) texture->w / texture_w;
   423     data->texh = (GLfloat) texture->h / texture_h;
   424 
   425     data->format = format;
   426     data->formattype = type;
   427     renderdata->glBindTexture(data->type, data->texture);
   428     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   429                                 GL_NEAREST);
   430     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   431                                 GL_NEAREST);
   432     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   433                                 GL_CLAMP_TO_EDGE);
   434     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   435                                 GL_CLAMP_TO_EDGE);
   436 
   437     renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   438                              texture_h, 0, format, type, NULL);
   439 
   440     result = renderdata->glGetError();
   441     if (result != GL_NO_ERROR) {
   442         GLES_SetError("glTexImage2D()", result);
   443         return -1;
   444     }
   445     return 0;
   446 }
   447 
   448 static int
   449 GLES_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   450                         void **pixels, int *pitch)
   451 {
   452     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   453 
   454     *pixels = data->pixels;
   455     *pitch = data->pitch;
   456     return 0;
   457 }
   458 
   459 static int
   460 GLES_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   461                        const SDL_Color * colors, int firstcolor, int ncolors)
   462 {
   463     SDL_SetError("OpenGL ES does not support paletted textures");
   464     return -1;
   465 }
   466 
   467 static int
   468 GLES_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   469                        SDL_Color * colors, int firstcolor, int ncolors)
   470 {
   471     SDL_SetError("OpenGL ES does not support paletted textures");
   472     return -1;
   473 }
   474 
   475 static void
   476 SetupTextureUpdate(GLES_RenderData * renderdata, SDL_Texture * texture,
   477                    int pitch)
   478 {
   479 
   480 
   481     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   482     renderdata->glBindTexture(data->type, data->texture);
   483     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   484 }
   485 
   486 static int
   487 GLES_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   488 {
   489     return 0;
   490 }
   491 
   492 static int
   493 GLES_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   494 {
   495     return 0;
   496 }
   497 
   498 static int
   499 GLES_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   500 {
   501     switch (texture->blendMode) {
   502     case SDL_TEXTUREBLENDMODE_NONE:
   503     case SDL_TEXTUREBLENDMODE_MASK:
   504     case SDL_TEXTUREBLENDMODE_BLEND:
   505     case SDL_TEXTUREBLENDMODE_ADD:
   506     case SDL_TEXTUREBLENDMODE_MOD:
   507         return 0;
   508     default:
   509         SDL_Unsupported();
   510         texture->blendMode = SDL_TEXTUREBLENDMODE_NONE;
   511         return -1;
   512     }
   513 }
   514 
   515 static int
   516 GLES_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   517 {
   518     switch (texture->scaleMode) {
   519     case SDL_TEXTURESCALEMODE_NONE:
   520     case SDL_TEXTURESCALEMODE_FAST:
   521     case SDL_TEXTURESCALEMODE_SLOW:
   522         return 0;
   523     case SDL_TEXTURESCALEMODE_BEST:
   524         SDL_Unsupported();
   525         texture->scaleMode = SDL_TEXTURESCALEMODE_SLOW;
   526         return -1;
   527     default:
   528         SDL_Unsupported();
   529         texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
   530         return -1;
   531     }
   532 }
   533 
   534 static int
   535 GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   536                    const SDL_Rect * rect, const void *pixels, int pitch)
   537 {
   538     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   539     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   540     GLenum result;
   541 
   542     SetupTextureUpdate(renderdata, texture, pitch);
   543     renderdata->glGetError();
   544     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   545                                 rect->h, data->format, data->formattype,
   546                                 pixels);
   547     result = renderdata->glGetError();
   548     if (result != GL_NO_ERROR) {
   549         GLES_SetError("glTexSubImage2D()", result);
   550         return -1;
   551     }
   552     return 0;
   553 }
   554 
   555 static int
   556 GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   557                  const SDL_Rect * rect, int markDirty, void **pixels,
   558                  int *pitch)
   559 {
   560     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   561 
   562     if (markDirty) {
   563         SDL_AddDirtyRect(&data->dirty, rect);
   564     }
   565 
   566     *pixels =
   567         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   568                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   569     *pitch = data->pitch;
   570     return 0;
   571 }
   572 
   573 static void
   574 GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   575 {
   576 }
   577 
   578 static void
   579 GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   580                   int numrects, const SDL_Rect * rects)
   581 {
   582     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   583     int i;
   584 
   585     for (i = 0; i < numrects; ++i) {
   586         SDL_AddDirtyRect(&data->dirty, &rects[i]);
   587     }
   588 }
   589 
   590 static int
   591 GLES_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
   592                 const SDL_Rect * rect)
   593 {
   594 
   595     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   596     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   597 
   598     /* set proper drawing color */
   599     GLfloat oldClearColor[4];
   600 
   601     data->glGetFloatv(GL_COLOR_CLEAR_VALUE, oldClearColor);
   602 
   603     data->glClearColor((GLclampf) r * inv255f, (GLclampf) g * inv255f,
   604                        (GLclampf) b * inv255f, (GLclampf) a * inv255f);
   605 
   606     data->glScissor(rect->x, window->h - rect->y - rect->h, rect->w, rect->h);
   607     data->glEnable(GL_SCISSOR_TEST);
   608     data->glClear(GL_COLOR_BUFFER_BIT);
   609     data->glDisable(GL_SCISSOR_TEST);
   610 
   611     /* reset clear color */
   612     data->glClearColor(oldClearColor[0], oldClearColor[1], oldClearColor[2],
   613                        oldClearColor[2]);
   614 
   615     return 0;
   616 }
   617 
   618 static int
   619 GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   620                 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   621 {
   622 
   623     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   624     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   625     int minx, miny, maxx, maxy;
   626     GLfloat minu, maxu, minv, maxv;
   627     int i;
   628     void *temp_buffer;          /* used for reformatting dirty rect pixels */
   629     void *temp_ptr;
   630 
   631     if (texturedata->dirty.list) {
   632         SDL_DirtyRect *dirty;
   633         void *pixels;
   634         int bpp = SDL_BYTESPERPIXEL(texture->format);
   635         int pitch = texturedata->pitch;
   636 
   637         SetupTextureUpdate(data, texture, pitch);
   638 
   639         data->glBindTexture(texturedata->type, texturedata->texture);
   640         for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
   641             SDL_Rect *rect = &dirty->rect;
   642             pixels =
   643                 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
   644                           rect->x * bpp);
   645             /*      There is no GL_UNPACK_ROW_LENGTH in OpenGLES 
   646                we must do this reformatting ourselves(!)
   647 
   648                maybe it'd be a good idea to keep a temp buffer around
   649                for this purpose rather than allocating it each time
   650              */
   651             temp_buffer = SDL_malloc(rect->w * rect->h * bpp);
   652             temp_ptr = temp_buffer;
   653             for (i = 0; i < rect->h; i++) {
   654                 SDL_memcpy(temp_ptr, pixels, rect->w * bpp);
   655                 temp_ptr += rect->w * bpp;
   656                 pixels += pitch;
   657             }
   658 
   659             data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
   660                                   rect->w, rect->h, texturedata->format,
   661                                   texturedata->formattype, temp_buffer);
   662 
   663             SDL_free(temp_buffer);
   664 
   665         }
   666         SDL_ClearDirtyRects(&texturedata->dirty);
   667     }
   668 
   669     data->glBindTexture(texturedata->type, texturedata->texture);
   670     data->glEnable(GL_TEXTURE_2D);
   671 
   672     if (texture->modMode) {
   673         data->glColor4f((GLfloat) texture->r * inv255f,
   674                         (GLfloat) texture->g * inv255f,
   675                         (GLfloat) texture->b * inv255f,
   676                         (GLfloat) texture->a * inv255f);
   677     } else {
   678         data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
   679     }
   680 
   681     if (texture->blendMode != data->blendMode) {
   682         switch (texture->blendMode) {
   683         case SDL_TEXTUREBLENDMODE_NONE:
   684             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
   685             data->glDisable(GL_BLEND);
   686             break;
   687         case SDL_TEXTUREBLENDMODE_MASK:
   688         case SDL_TEXTUREBLENDMODE_BLEND:
   689             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   690             data->glEnable(GL_BLEND);
   691             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   692             break;
   693         case SDL_TEXTUREBLENDMODE_ADD:
   694             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   695             data->glEnable(GL_BLEND);
   696             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   697             break;
   698         case SDL_TEXTUREBLENDMODE_MOD:
   699             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   700             data->glEnable(GL_BLEND);
   701             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   702             break;
   703         }
   704         data->blendMode = texture->blendMode;
   705     }
   706 
   707     switch (texture->scaleMode) {
   708     case SDL_TEXTURESCALEMODE_NONE:
   709     case SDL_TEXTURESCALEMODE_FAST:
   710         data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
   711                               GL_NEAREST);
   712         data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
   713                               GL_NEAREST);
   714         break;
   715     case SDL_TEXTURESCALEMODE_SLOW:
   716     case SDL_TEXTURESCALEMODE_BEST:
   717         data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
   718                               GL_LINEAR);
   719         data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
   720                               GL_LINEAR);
   721         break;
   722     }
   723 
   724     if (data->GL_OES_draw_texture_supported && data->useDrawTexture) {
   725         /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */
   726         SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   727         GLint cropRect[4];
   728         cropRect[0] = srcrect->x;
   729         cropRect[1] = srcrect->y + srcrect->h;
   730         cropRect[2] = srcrect->w;
   731         cropRect[3] = -srcrect->h;
   732         data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
   733                                cropRect);
   734         data->glDrawTexiOES(dstrect->x, window->h - dstrect->y - dstrect->h,
   735                             0, dstrect->w, dstrect->h);
   736     } else {
   737 
   738         minx = dstrect->x;
   739         miny = dstrect->y;
   740         maxx = dstrect->x + dstrect->w;
   741         maxy = dstrect->y + dstrect->h;
   742 
   743         minu = (GLfloat) srcrect->x / texture->w;
   744         minu *= texturedata->texw;
   745         maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   746         maxu *= texturedata->texw;
   747         minv = (GLfloat) srcrect->y / texture->h;
   748         minv *= texturedata->texh;
   749         maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   750         maxv *= texturedata->texh;
   751 
   752         GLshort vertices[8];
   753         GLfloat texCoords[8];
   754 
   755         vertices[0] = minx;
   756         vertices[1] = miny;
   757         vertices[2] = maxx;
   758         vertices[3] = miny;
   759         vertices[4] = minx;
   760         vertices[5] = maxy;
   761         vertices[6] = maxx;
   762         vertices[7] = maxy;
   763 
   764         texCoords[0] = minu;
   765         texCoords[1] = minv;
   766         texCoords[2] = maxu;
   767         texCoords[3] = minv;
   768         texCoords[4] = minu;
   769         texCoords[5] = maxv;
   770         texCoords[6] = maxu;
   771         texCoords[7] = maxv;
   772 
   773         data->glVertexPointer(2, GL_SHORT, 0, vertices);
   774         data->glEnableClientState(GL_VERTEX_ARRAY);
   775         data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
   776         data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   777         data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   778 
   779     }
   780 
   781     return 0;
   782 }
   783 
   784 static void
   785 GLES_RenderPresent(SDL_Renderer * renderer)
   786 {
   787     SDL_GL_SwapWindow(renderer->window);
   788 }
   789 
   790 static void
   791 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   792 {
   793     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   794     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   795 
   796     if (!data) {
   797         return;
   798     }
   799     if (data->texture) {
   800         glDeleteTextures(1, &data->texture);
   801     }
   802     if (data->pixels) {
   803         SDL_free(data->pixels);
   804     }
   805     SDL_FreeDirtyRects(&data->dirty);
   806     SDL_free(data);
   807     texture->driverdata = NULL;
   808 }
   809 
   810 static void
   811 GLES_DestroyRenderer(SDL_Renderer * renderer)
   812 {
   813     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   814 
   815     if (data) {
   816         if (data->context) {
   817             /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
   818             SDL_GL_DeleteContext(data->context);
   819         }
   820         SDL_free(data);
   821     }
   822     SDL_free(renderer);
   823 }
   824 
   825 #endif /* SDL_VIDEO_RENDER_OGL */
   826 
   827 /* vi: set ts=4 sw=4 expandtab: */