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