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