src/video/SDL_renderer_gles.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 20 Dec 2008 12:00:00 +0000
changeset 2884 9dde605c7540
parent 2859 99210400e8b9
child 2936 066384910f50
permissions -rw-r--r--
Date: Fri, 19 Dec 2008 20:17:35 +0100
From: Couriersud
Subject: Re: Aw: Experience using SDL1.3 in sdlmame/Proposal for api additions

> For consistency you'd probably want:
> SDL_SetRenderDrawColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
> SDL_SetRenderDrawBlendMode(SDL_BlendMode blendMode);
> SDL_RenderLine(int x1, int y1, int x2, int y2);
> SDL_RenderFill(SDL_Rect *rect);
>
> You probably also want to add API functions query the current state.
>

I have implemented the above api for the opengl, x11, directfb and
software renderers. I have also renamed *TEXTUREBLENDMODE* constants to
BLENDMODE*. The unix build compiles. The windows renderer still needs to
be updated, but I have no windows development machine at hand. Have a
look at the x11 renderer for a sample.

Vector games now run at 90% both on opengl and directfb in comparison to
sdlmame's own opengl renderer. The same applies to raster games.

The diff also includes

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