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