src/video/SDL_renderer_gles.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Dec 2009 08:11:06 +0000
changeset 3565 f43c8f688f77
parent 3547 8b18669c2663
child 3641 1e2e19d51265
permissions -rw-r--r--
Fixed bug #906

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