src/render/opengles/SDL_render_gles.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 29 May 2013 03:07:55 -0700
changeset 7239 04dda95ba22c
parent 7191 75360622e65f
child 7420 fe82b639c4d6
permissions -rw-r--r--
Fixed bug 1622 - SDL_RenderSetViewport with empty SDL_Rect raises wrong error for OpenGL rendering backend

It's now legal to set an empty viewport rect - it will prevent any rendering.

Also added an API to query the output size: SDL_GetRendererOutputSize()
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED
    24 
    25 #include "SDL_hints.h"
    26 #include "SDL_opengles.h"
    27 #include "../SDL_sysrender.h"
    28 
    29 #if defined(SDL_VIDEO_DRIVER_PANDORA)
    30 
    31 /* Empty function stub to get OpenGL ES 1.x support without  */
    32 /* OpenGL ES extension GL_OES_draw_texture supported         */
    33 GL_API void GL_APIENTRY
    34 glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height)
    35 {
    36     return;
    37 }
    38 
    39 #endif /* PANDORA */
    40 
    41 /* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */
    42 
    43 /* Used to re-create the window with OpenGL ES capability */
    44 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    45 
    46 static const float inv255f = 1.0f / 255.0f;
    47 
    48 static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
    49 static void GLES_WindowEvent(SDL_Renderer * renderer,
    50                              const SDL_WindowEvent *event);
    51 static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    52 static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    53                               const SDL_Rect * rect, const void *pixels,
    54                               int pitch);
    55 static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    56                             const SDL_Rect * rect, void **pixels, int *pitch);
    57 static void GLES_UnlockTexture(SDL_Renderer * renderer,
    58                                SDL_Texture * texture);
    59 static int GLES_SetRenderTarget(SDL_Renderer * renderer,
    60                                  SDL_Texture * texture);
    61 static int GLES_UpdateViewport(SDL_Renderer * renderer);
    62 static int GLES_UpdateClipRect(SDL_Renderer * renderer);
    63 static int GLES_RenderClear(SDL_Renderer * renderer);
    64 static int GLES_RenderDrawPoints(SDL_Renderer * renderer,
    65                                  const SDL_FPoint * points, int count);
    66 static int GLES_RenderDrawLines(SDL_Renderer * renderer,
    67                                 const SDL_FPoint * points, int count);
    68 static int GLES_RenderFillRects(SDL_Renderer * renderer,
    69                                 const SDL_FRect * rects, int count);
    70 static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    71                            const SDL_Rect * srcrect,
    72                            const SDL_FRect * dstrect);
    73 static int GLES_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
    74                          const SDL_Rect * srcrect, const SDL_FRect * dstrect,
    75                          const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
    76 static int GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    77                     Uint32 pixel_format, void * pixels, int pitch);
    78 static void GLES_RenderPresent(SDL_Renderer * renderer);
    79 static void GLES_DestroyTexture(SDL_Renderer * renderer,
    80                                 SDL_Texture * texture);
    81 static void GLES_DestroyRenderer(SDL_Renderer * renderer);
    82 static int GLES_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
    83 static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
    84 
    85 typedef struct GLES_FBOList GLES_FBOList;
    86 
    87 struct GLES_FBOList
    88 {
    89    Uint32 w, h;
    90    GLuint FBO;
    91    GLES_FBOList *next;
    92 };
    93 
    94 
    95 SDL_RenderDriver GLES_RenderDriver = {
    96     GLES_CreateRenderer,
    97     {
    98      "opengles",
    99      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
   100      1,
   101      {SDL_PIXELFORMAT_ABGR8888},
   102      0,
   103      0}
   104 };
   105 
   106 typedef struct
   107 {
   108     SDL_GLContext context;
   109     struct {
   110         Uint32 color;
   111         int blendMode;
   112         SDL_bool tex_coords;
   113     } current;
   114 
   115 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
   116 #include "SDL_glesfuncs.h"
   117 #undef SDL_PROC
   118     SDL_bool GL_OES_framebuffer_object_supported;
   119     GLES_FBOList *framebuffers;
   120     GLuint window_framebuffer;
   121 
   122     SDL_bool useDrawTexture;
   123     SDL_bool GL_OES_draw_texture_supported;
   124 } GLES_RenderData;
   125 
   126 typedef struct
   127 {
   128     GLuint texture;
   129     GLenum type;
   130     GLfloat texw;
   131     GLfloat texh;
   132     GLenum format;
   133     GLenum formattype;
   134     void *pixels;
   135     int pitch;
   136     GLES_FBOList *fbo;
   137 } GLES_TextureData;
   138 
   139 static int
   140 GLES_SetError(const char *prefix, GLenum result)
   141 {
   142     const char *error;
   143 
   144     switch (result) {
   145     case GL_NO_ERROR:
   146         error = "GL_NO_ERROR";
   147         break;
   148     case GL_INVALID_ENUM:
   149         error = "GL_INVALID_ENUM";
   150         break;
   151     case GL_INVALID_VALUE:
   152         error = "GL_INVALID_VALUE";
   153         break;
   154     case GL_INVALID_OPERATION:
   155         error = "GL_INVALID_OPERATION";
   156         break;
   157     case GL_STACK_OVERFLOW:
   158         error = "GL_STACK_OVERFLOW";
   159         break;
   160     case GL_STACK_UNDERFLOW:
   161         error = "GL_STACK_UNDERFLOW";
   162         break;
   163     case GL_OUT_OF_MEMORY:
   164         error = "GL_OUT_OF_MEMORY";
   165         break;
   166     default:
   167         error = "UNKNOWN";
   168         break;
   169     }
   170     return SDL_SetError("%s: %s", prefix, error);
   171 }
   172 
   173 static int GLES_LoadFunctions(GLES_RenderData * data)
   174 {
   175 #if SDL_VIDEO_DRIVER_UIKIT
   176 #define __SDL_NOGETPROCADDR__
   177 #elif SDL_VIDEO_DRIVER_ANDROID
   178 #define __SDL_NOGETPROCADDR__
   179 #elif SDL_VIDEO_DRIVER_PANDORA
   180 #define __SDL_NOGETPROCADDR__
   181 #endif
   182 
   183 #ifdef __SDL_NOGETPROCADDR__
   184 #define SDL_PROC(ret,func,params) data->func=func;
   185 #else
   186 #define SDL_PROC(ret,func,params) \
   187     do { \
   188         data->func = SDL_GL_GetProcAddress(#func); \
   189         if ( ! data->func ) { \
   190             return SDL_SetError("Couldn't load GLES function %s: %s\n", #func, SDL_GetError()); \
   191         } \
   192     } while ( 0 );
   193 #endif /* _SDL_NOGETPROCADDR_ */
   194 
   195 #include "SDL_glesfuncs.h"
   196 #undef SDL_PROC
   197     return 0;
   198 }
   199 
   200 static SDL_GLContext SDL_CurrentContext = NULL;
   201 
   202 GLES_FBOList *
   203 GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h)
   204 {
   205    GLES_FBOList *result = data->framebuffers;
   206    while ((result) && ((result->w != w) || (result->h != h)) )
   207    {
   208        result = result->next;
   209    }
   210    if (result == NULL)
   211    {
   212        result = SDL_malloc(sizeof(GLES_FBOList));
   213        result->w = w;
   214        result->h = h;
   215        data->glGenFramebuffersOES(1, &result->FBO);
   216        result->next = data->framebuffers;
   217        data->framebuffers = result;
   218    }
   219    return result;
   220 }
   221 
   222 
   223 static int
   224 GLES_ActivateRenderer(SDL_Renderer * renderer)
   225 {
   226     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   227 
   228     if (SDL_CurrentContext != data->context) {
   229         if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
   230             return -1;
   231         }
   232         SDL_CurrentContext = data->context;
   233 
   234         GLES_UpdateViewport(renderer);
   235     }
   236     return 0;
   237 }
   238 
   239 /* This is called if we need to invalidate all of the SDL OpenGL state */
   240 static void
   241 GLES_ResetState(SDL_Renderer *renderer)
   242 {
   243     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   244 
   245     if (SDL_CurrentContext == data->context) {
   246         GLES_UpdateViewport(renderer);
   247     } else {
   248         GLES_ActivateRenderer(renderer);
   249     }
   250 
   251     data->current.color = 0;
   252     data->current.blendMode = -1;
   253     data->current.tex_coords = SDL_FALSE;
   254 
   255     data->glDisable(GL_DEPTH_TEST);
   256     data->glDisable(GL_CULL_FACE);
   257 
   258     data->glMatrixMode(GL_MODELVIEW);
   259     data->glLoadIdentity();
   260 
   261     data->glEnableClientState(GL_VERTEX_ARRAY);
   262     data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   263 }
   264 
   265 SDL_Renderer *
   266 GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
   267 {
   268 
   269     SDL_Renderer *renderer;
   270     GLES_RenderData *data;
   271     GLint value;
   272     Uint32 windowFlags;
   273 
   274     SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, 1);
   275     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
   276     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
   277 
   278     windowFlags = SDL_GetWindowFlags(window);
   279     if (!(windowFlags & SDL_WINDOW_OPENGL)) {
   280         if (SDL_RecreateWindow(window, windowFlags | SDL_WINDOW_OPENGL) < 0) {
   281             /* Uh oh, better try to put it back... */
   282             SDL_RecreateWindow(window, windowFlags);
   283             return NULL;
   284         }
   285     }
   286 
   287     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   288     if (!renderer) {
   289         SDL_OutOfMemory();
   290         return NULL;
   291     }
   292 
   293     data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
   294     if (!data) {
   295         GLES_DestroyRenderer(renderer);
   296         SDL_OutOfMemory();
   297         return NULL;
   298     }
   299 
   300     renderer->WindowEvent = GLES_WindowEvent;
   301     renderer->CreateTexture = GLES_CreateTexture;
   302     renderer->UpdateTexture = GLES_UpdateTexture;
   303     renderer->LockTexture = GLES_LockTexture;
   304     renderer->UnlockTexture = GLES_UnlockTexture;
   305     renderer->SetRenderTarget = GLES_SetRenderTarget;
   306     renderer->UpdateViewport = GLES_UpdateViewport;
   307     renderer->UpdateClipRect = GLES_UpdateClipRect;
   308     renderer->RenderClear = GLES_RenderClear;
   309     renderer->RenderDrawPoints = GLES_RenderDrawPoints;
   310     renderer->RenderDrawLines = GLES_RenderDrawLines;
   311     renderer->RenderFillRects = GLES_RenderFillRects;
   312     renderer->RenderCopy = GLES_RenderCopy;
   313     renderer->RenderCopyEx = GLES_RenderCopyEx;
   314     renderer->RenderReadPixels = GLES_RenderReadPixels;
   315     renderer->RenderPresent = GLES_RenderPresent;
   316     renderer->DestroyTexture = GLES_DestroyTexture;
   317     renderer->DestroyRenderer = GLES_DestroyRenderer;
   318     renderer->GL_BindTexture = GLES_BindTexture;
   319     renderer->GL_UnbindTexture = GLES_UnbindTexture;
   320     renderer->info = GLES_RenderDriver.info;
   321     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   322     renderer->driverdata = data;
   323     renderer->window = window;
   324 
   325     data->context = SDL_GL_CreateContext(window);
   326     if (!data->context) {
   327         GLES_DestroyRenderer(renderer);
   328         return NULL;
   329     }
   330     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   331         GLES_DestroyRenderer(renderer);
   332         return NULL;
   333     }
   334 
   335     if (GLES_LoadFunctions(data) < 0) {
   336         GLES_DestroyRenderer(renderer);
   337         return NULL;
   338     }
   339 
   340     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   341         SDL_GL_SetSwapInterval(1);
   342     } else {
   343         SDL_GL_SetSwapInterval(0);
   344     }
   345     if (SDL_GL_GetSwapInterval() > 0) {
   346         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   347     }
   348 
   349 #if SDL_VIDEO_DRIVER_PANDORA
   350     data->GL_OES_draw_texture_supported = SDL_FALSE;
   351     data->useDrawTexture = SDL_FALSE;
   352 #else
   353     if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) {
   354         data->GL_OES_draw_texture_supported = SDL_TRUE;
   355         data->useDrawTexture = SDL_TRUE;
   356     } else {
   357         data->GL_OES_draw_texture_supported = SDL_FALSE;
   358         data->useDrawTexture = SDL_FALSE;
   359     }
   360 #endif
   361 
   362     value = 0;
   363     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   364     renderer->info.max_texture_width = value;
   365     value = 0;
   366     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   367     renderer->info.max_texture_height = value;
   368 
   369     if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object")) {
   370         data->GL_OES_framebuffer_object_supported = SDL_TRUE;
   371         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
   372 
   373         value = 0;
   374         data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value);
   375         data->window_framebuffer = (GLuint)value;
   376     }
   377     data->framebuffers = NULL;
   378 
   379     /* Set up parameters for rendering */
   380     GLES_ResetState(renderer);
   381 
   382     return renderer;
   383 }
   384 
   385 static void
   386 GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   387 {
   388     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   389 
   390     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
   391         event->event == SDL_WINDOWEVENT_SHOWN ||
   392         event->event == SDL_WINDOWEVENT_HIDDEN) {
   393         /* Rebind the context to the window area and update matrices */
   394         SDL_CurrentContext = NULL;
   395     }
   396 
   397     if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
   398         /* According to Apple documentation, we need to finish drawing NOW! */
   399         data->glFinish();
   400     }
   401 }
   402 
   403 static __inline__ int
   404 power_of_2(int input)
   405 {
   406     int value = 1;
   407 
   408     while (value < input) {
   409         value <<= 1;
   410     }
   411     return value;
   412 }
   413 
   414 static GLenum
   415 GetScaleQuality(void)
   416 {
   417     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   418 
   419     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   420         return GL_NEAREST;
   421     } else {
   422         return GL_LINEAR;
   423     }
   424 }
   425 
   426 static int
   427 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   428 {
   429     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   430     GLES_TextureData *data;
   431     GLint internalFormat;
   432     GLenum format, type;
   433     int texture_w, texture_h;
   434     GLenum scaleMode;
   435     GLenum result;
   436 
   437     GLES_ActivateRenderer(renderer);
   438 
   439     switch (texture->format) {
   440     case SDL_PIXELFORMAT_ABGR8888:
   441         internalFormat = GL_RGBA;
   442         format = GL_RGBA;
   443         type = GL_UNSIGNED_BYTE;
   444         break;
   445     default:
   446         return SDL_SetError("Texture format not supported");
   447     }
   448 
   449     data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data));
   450     if (!data) {
   451         return SDL_OutOfMemory();
   452     }
   453 
   454     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   455         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   456         data->pixels = SDL_calloc(1, texture->h * data->pitch);
   457         if (!data->pixels) {
   458             SDL_free(data);
   459             return SDL_OutOfMemory();
   460         }
   461     }
   462 
   463     texture->driverdata = data;
   464     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   465        data->fbo = GLES_GetFBO(renderer->driverdata, texture->w, texture->h);
   466     } else {
   467        data->fbo = NULL;
   468     }
   469 
   470     renderdata->glGetError();
   471     renderdata->glEnable(GL_TEXTURE_2D);
   472     renderdata->glGenTextures(1, &data->texture);
   473 
   474     data->type = GL_TEXTURE_2D;
   475     /* no NPOV textures allowed in OpenGL ES (yet) */
   476     texture_w = power_of_2(texture->w);
   477     texture_h = power_of_2(texture->h);
   478     data->texw = (GLfloat) texture->w / texture_w;
   479     data->texh = (GLfloat) texture->h / texture_h;
   480 
   481     data->format = format;
   482     data->formattype = type;
   483     scaleMode = GetScaleQuality();
   484     renderdata->glBindTexture(data->type, data->texture);
   485     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
   486     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
   487     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   488     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   489 
   490     renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   491                              texture_h, 0, format, type, NULL);
   492     renderdata->glDisable(GL_TEXTURE_2D);
   493 
   494     result = renderdata->glGetError();
   495     if (result != GL_NO_ERROR) {
   496         return GLES_SetError("glTexImage2D()", result);
   497     }
   498     return 0;
   499 }
   500 
   501 static int
   502 GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   503                    const SDL_Rect * rect, const void *pixels, int pitch)
   504 {
   505     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
   506     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   507     Uint8 *blob = NULL;
   508     Uint8 *src;
   509     int srcPitch;
   510     int y;
   511 
   512     GLES_ActivateRenderer(renderer);
   513 
   514     /* Bail out if we're supposed to update an empty rectangle */
   515     if (rect->w <= 0 || rect->h <= 0)
   516         return 0;
   517 
   518     /* Reformat the texture data into a tightly packed array */
   519     srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format);
   520     src = (Uint8 *)pixels;
   521     if (pitch != srcPitch) {
   522         blob = (Uint8 *)SDL_malloc(srcPitch * rect->h);
   523         if (!blob) {
   524             return SDL_OutOfMemory();
   525         }
   526         src = blob;
   527         for (y = 0; y < rect->h; ++y) {
   528             SDL_memcpy(src, pixels, srcPitch);
   529             src += srcPitch;
   530             pixels = (Uint8 *)pixels + pitch;
   531         }
   532         src = blob;
   533     }
   534 
   535     /* Create a texture subimage with the supplied data */
   536     renderdata->glGetError();
   537     renderdata->glEnable(data->type);
   538     renderdata->glBindTexture(data->type, data->texture);
   539     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   540     renderdata->glTexSubImage2D(data->type,
   541                     0,
   542                     rect->x,
   543                     rect->y,
   544                     rect->w,
   545                     rect->h,
   546                     data->format,
   547                     data->formattype,
   548                     src);
   549     if (blob) {
   550         SDL_free(blob);
   551     }
   552 
   553     if (renderdata->glGetError() != GL_NO_ERROR)
   554     {
   555         return SDL_SetError("Failed to update texture");
   556     }
   557     return 0;
   558 }
   559 
   560 static int
   561 GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   562                  const SDL_Rect * rect, void **pixels, int *pitch)
   563 {
   564     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   565 
   566     *pixels =
   567         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   568                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   569     *pitch = data->pitch;
   570     return 0;
   571 }
   572 
   573 static void
   574 GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   575 {
   576     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
   577     SDL_Rect rect;
   578 
   579     /* We do whole texture updates, at least for now */
   580     rect.x = 0;
   581     rect.y = 0;
   582     rect.w = texture->w;
   583     rect.h = texture->h;
   584     GLES_UpdateTexture(renderer, texture, &rect, data->pixels, data->pitch);
   585 }
   586 
   587 static int
   588 GLES_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   589 {
   590     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   591     GLES_TextureData *texturedata = NULL;
   592     GLenum status;
   593 
   594     GLES_ActivateRenderer(renderer);
   595 
   596     if (texture == NULL) {
   597         data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, data->window_framebuffer);
   598         return 0;
   599     }
   600 
   601     texturedata = (GLES_TextureData *) texture->driverdata;
   602     data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO);
   603     /* TODO: check if texture pixel format allows this operation */
   604     data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0);
   605     /* Check FBO status */
   606     status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
   607     if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
   608         return SDL_SetError("glFramebufferTexture2DOES() failed");
   609     }
   610     return 0;
   611 }
   612 
   613 static int
   614 GLES_UpdateViewport(SDL_Renderer * renderer)
   615 {
   616     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   617 
   618     if (SDL_CurrentContext != data->context) {
   619         /* We'll update the viewport after we rebind the context */
   620         return 0;
   621     }
   622 
   623     data->glViewport(renderer->viewport.x, renderer->viewport.y,
   624                renderer->viewport.w, renderer->viewport.h);
   625 
   626     if (renderer->viewport.w && renderer->viewport.h) {
   627         data->glMatrixMode(GL_PROJECTION);
   628         data->glLoadIdentity();
   629         data->glOrthof((GLfloat) 0,
   630                  (GLfloat) renderer->viewport.w,
   631                  (GLfloat) renderer->viewport.h,
   632                  (GLfloat) 0, 0.0, 1.0);
   633     }
   634     return 0;
   635 }
   636 
   637 static int
   638 GLES_UpdateClipRect(SDL_Renderer * renderer)
   639 {
   640     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   641     const SDL_Rect *rect = &renderer->clip_rect;
   642 
   643     if (SDL_CurrentContext != data->context) {
   644         /* We'll update the clip rect after we rebind the context */
   645         return 0;
   646     }
   647 
   648     if (!SDL_RectEmpty(rect)) {
   649         data->glEnable(GL_SCISSOR_TEST);
   650         data->glScissor(rect->x, renderer->viewport.h - rect->y - rect->h, rect->w, rect->h);
   651     } else {
   652         data->glDisable(GL_SCISSOR_TEST);
   653     }
   654     return 0;
   655 }
   656 
   657 static void
   658 GLES_SetColor(GLES_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
   659 {
   660     Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
   661 
   662     if (color != data->current.color) {
   663         data->glColor4f((GLfloat) r * inv255f,
   664                         (GLfloat) g * inv255f,
   665                         (GLfloat) b * inv255f,
   666                         (GLfloat) a * inv255f);
   667         data->current.color = color;
   668     }
   669 }
   670 
   671 static void
   672 GLES_SetBlendMode(GLES_RenderData * data, int blendMode)
   673 {
   674     if (blendMode != data->current.blendMode) {
   675         switch (blendMode) {
   676         case SDL_BLENDMODE_NONE:
   677             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   678             data->glDisable(GL_BLEND);
   679             break;
   680         case SDL_BLENDMODE_BLEND:
   681             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   682             data->glEnable(GL_BLEND);
   683             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   684             break;
   685         case SDL_BLENDMODE_ADD:
   686             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   687             data->glEnable(GL_BLEND);
   688             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   689             break;
   690         case SDL_BLENDMODE_MOD:
   691             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   692             data->glEnable(GL_BLEND);
   693             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   694             break;
   695         }
   696         data->current.blendMode = blendMode;
   697     }
   698 }
   699 
   700 static void
   701 GLES_SetTexCoords(GLES_RenderData * data, SDL_bool enabled)
   702 {
   703     if (enabled != data->current.tex_coords) {
   704         if (enabled) {
   705             data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   706         } else {
   707             data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   708         }
   709         data->current.tex_coords = enabled;
   710     }
   711 }
   712 
   713 static void
   714 GLES_SetDrawingState(SDL_Renderer * renderer)
   715 {
   716     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   717 
   718     GLES_ActivateRenderer(renderer);
   719 
   720     GLES_SetColor(data, (GLfloat) renderer->r,
   721                         (GLfloat) renderer->g,
   722                         (GLfloat) renderer->b,
   723                         (GLfloat) renderer->a);
   724 
   725     GLES_SetBlendMode(data, renderer->blendMode);
   726 
   727     GLES_SetTexCoords(data, SDL_FALSE);
   728 }
   729 
   730 static int
   731 GLES_RenderClear(SDL_Renderer * renderer)
   732 {
   733     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   734 
   735     GLES_ActivateRenderer(renderer);
   736 
   737     data->glClearColor((GLfloat) renderer->r * inv255f,
   738                  (GLfloat) renderer->g * inv255f,
   739                  (GLfloat) renderer->b * inv255f,
   740                  (GLfloat) renderer->a * inv255f);
   741 
   742     data->glClear(GL_COLOR_BUFFER_BIT);
   743 
   744     return 0;
   745 }
   746 
   747 static int
   748 GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
   749                       int count)
   750 {
   751     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   752 
   753     GLES_SetDrawingState(renderer);
   754 
   755     data->glVertexPointer(2, GL_FLOAT, 0, points);
   756     data->glDrawArrays(GL_POINTS, 0, count);
   757 
   758     return 0;
   759 }
   760 
   761 static int
   762 GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
   763                      int count)
   764 {
   765     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   766 
   767     GLES_SetDrawingState(renderer);
   768 
   769     data->glVertexPointer(2, GL_FLOAT, 0, points);
   770     if (count > 2 &&
   771         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
   772         /* GL_LINE_LOOP takes care of the final segment */
   773         --count;
   774         data->glDrawArrays(GL_LINE_LOOP, 0, count);
   775     } else {
   776         data->glDrawArrays(GL_LINE_STRIP, 0, count);
   777         /* We need to close the endpoint of the line */
   778         data->glDrawArrays(GL_POINTS, count-1, 1);
   779     }
   780 
   781     return 0;
   782 }
   783 
   784 static int
   785 GLES_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
   786                      int count)
   787 {
   788     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   789     int i;
   790 
   791     GLES_SetDrawingState(renderer);
   792 
   793     for (i = 0; i < count; ++i) {
   794         const SDL_FRect *rect = &rects[i];
   795         GLfloat minx = rect->x;
   796         GLfloat maxx = rect->x + rect->w;
   797         GLfloat miny = rect->y;
   798         GLfloat maxy = rect->y + rect->h;
   799         GLfloat vertices[8];
   800         vertices[0] = minx;
   801         vertices[1] = miny;
   802         vertices[2] = maxx;
   803         vertices[3] = miny;
   804         vertices[4] = minx;
   805         vertices[5] = maxy;
   806         vertices[6] = maxx;
   807         vertices[7] = maxy;
   808 
   809         data->glVertexPointer(2, GL_FLOAT, 0, vertices);
   810         data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   811     }
   812 
   813     return 0;
   814 }
   815 
   816 static int
   817 GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   818                 const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   819 {
   820     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   821     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   822     GLfloat minx, miny, maxx, maxy;
   823     GLfloat minu, maxu, minv, maxv;
   824 
   825     GLES_ActivateRenderer(renderer);
   826 
   827     data->glEnable(GL_TEXTURE_2D);
   828 
   829     data->glBindTexture(texturedata->type, texturedata->texture);
   830 
   831     if (texture->modMode) {
   832         GLES_SetColor(data, texture->r, texture->g, texture->b, texture->a);
   833     } else {
   834         GLES_SetColor(data, 255, 255, 255, 255);
   835     }
   836 
   837     GLES_SetBlendMode(data, texture->blendMode);
   838 
   839     GLES_SetTexCoords(data, SDL_TRUE);
   840 
   841     if (data->GL_OES_draw_texture_supported && data->useDrawTexture) {
   842         /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */
   843         GLint cropRect[4];
   844         int w, h;
   845         SDL_Window *window = renderer->window;
   846 
   847         SDL_GetWindowSize(window, &w, &h);
   848         if (renderer->target) {
   849             cropRect[0] = srcrect->x;
   850             cropRect[1] = srcrect->y;
   851             cropRect[2] = srcrect->w;
   852             cropRect[3] = srcrect->h;
   853             data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
   854                                    cropRect);
   855             data->glDrawTexfOES(renderer->viewport.x + dstrect->x, renderer->viewport.y + dstrect->y, 0,
   856                                 dstrect->w, dstrect->h);
   857         } else {
   858             cropRect[0] = srcrect->x;
   859             cropRect[1] = srcrect->y + srcrect->h;
   860             cropRect[2] = srcrect->w;
   861             cropRect[3] = -srcrect->h;
   862             data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
   863                                    cropRect);
   864             data->glDrawTexfOES(renderer->viewport.x + dstrect->x,
   865                         h - (renderer->viewport.y + dstrect->y) - dstrect->h, 0,
   866                         dstrect->w, dstrect->h);
   867         }
   868     } else {
   869 
   870         minx = dstrect->x;
   871         miny = dstrect->y;
   872         maxx = dstrect->x + dstrect->w;
   873         maxy = dstrect->y + dstrect->h;
   874 
   875         minu = (GLfloat) srcrect->x / texture->w;
   876         minu *= texturedata->texw;
   877         maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   878         maxu *= texturedata->texw;
   879         minv = (GLfloat) srcrect->y / texture->h;
   880         minv *= texturedata->texh;
   881         maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   882         maxv *= texturedata->texh;
   883 
   884         GLfloat vertices[8];
   885         GLfloat texCoords[8];
   886 
   887         vertices[0] = minx;
   888         vertices[1] = miny;
   889         vertices[2] = maxx;
   890         vertices[3] = miny;
   891         vertices[4] = minx;
   892         vertices[5] = maxy;
   893         vertices[6] = maxx;
   894         vertices[7] = maxy;
   895 
   896         texCoords[0] = minu;
   897         texCoords[1] = minv;
   898         texCoords[2] = maxu;
   899         texCoords[3] = minv;
   900         texCoords[4] = minu;
   901         texCoords[5] = maxv;
   902         texCoords[6] = maxu;
   903         texCoords[7] = maxv;
   904 
   905         data->glVertexPointer(2, GL_FLOAT, 0, vertices);
   906         data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
   907         data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   908     }
   909     data->glDisable(GL_TEXTURE_2D);
   910 
   911     return 0;
   912 }
   913 
   914 static int
   915 GLES_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   916                 const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   917                 const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
   918 {
   919 
   920     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
   921     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
   922     GLfloat minx, miny, maxx, maxy;
   923     GLfloat minu, maxu, minv, maxv;
   924     GLfloat centerx, centery;
   925 
   926     GLES_ActivateRenderer(renderer);
   927 
   928     data->glEnable(GL_TEXTURE_2D);
   929 
   930     data->glBindTexture(texturedata->type, texturedata->texture);
   931 
   932     if (texture->modMode) {
   933         GLES_SetColor(data, texture->r, texture->g, texture->b, texture->a);
   934     } else {
   935         GLES_SetColor(data, 255, 255, 255, 255);
   936     }
   937 
   938     GLES_SetBlendMode(data, texture->blendMode);
   939 
   940     GLES_SetTexCoords(data, SDL_TRUE);
   941 
   942     centerx = center->x;
   943     centery = center->y;
   944 
   945     /* Rotate and translate */
   946     data->glPushMatrix();
   947     data->glTranslatef(dstrect->x + centerx, dstrect->y + centery, 0.0f);
   948     data->glRotatef((GLfloat)angle, 0.0f, 0.0f, 1.0f);
   949 
   950     if (flip & SDL_FLIP_HORIZONTAL) {
   951         minx =  dstrect->w - centerx;
   952         maxx = -centerx;
   953     } else {
   954         minx = -centerx;
   955         maxx = dstrect->w - centerx;
   956     }
   957 
   958     if (flip & SDL_FLIP_VERTICAL) {
   959         miny = dstrect->h - centery;
   960         maxy = -centery;
   961     } else {
   962         miny = -centery;
   963         maxy = dstrect->h - centery;
   964     }
   965 
   966     minu = (GLfloat) srcrect->x / texture->w;
   967     minu *= texturedata->texw;
   968     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   969     maxu *= texturedata->texw;
   970     minv = (GLfloat) srcrect->y / texture->h;
   971     minv *= texturedata->texh;
   972     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   973     maxv *= texturedata->texh;
   974 
   975     GLfloat vertices[8];
   976     GLfloat texCoords[8];
   977 
   978     vertices[0] = minx;
   979     vertices[1] = miny;
   980     vertices[2] = maxx;
   981     vertices[3] = miny;
   982     vertices[4] = minx;
   983     vertices[5] = maxy;
   984     vertices[6] = maxx;
   985     vertices[7] = maxy;
   986 
   987     texCoords[0] = minu;
   988     texCoords[1] = minv;
   989     texCoords[2] = maxu;
   990     texCoords[3] = minv;
   991     texCoords[4] = minu;
   992     texCoords[5] = maxv;
   993     texCoords[6] = maxu;
   994     texCoords[7] = maxv;
   995     data->glVertexPointer(2, GL_FLOAT, 0, vertices);
   996     data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
   997     data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   998     data->glPopMatrix();
   999     data->glDisable(GL_TEXTURE_2D);
  1000 
  1001     return 0;
  1002 }
  1003 
  1004 static int
  1005 GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1006                     Uint32 pixel_format, void * pixels, int pitch)
  1007 {
  1008     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1009     SDL_Window *window = renderer->window;
  1010     Uint32 temp_format = SDL_PIXELFORMAT_ABGR8888;
  1011     void *temp_pixels;
  1012     int temp_pitch;
  1013     Uint8 *src, *dst, *tmp;
  1014     int w, h, length, rows;
  1015     int status;
  1016 
  1017     GLES_ActivateRenderer(renderer);
  1018 
  1019     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1020     temp_pixels = SDL_malloc(rect->h * temp_pitch);
  1021     if (!temp_pixels) {
  1022         return SDL_OutOfMemory();
  1023     }
  1024 
  1025     SDL_GetWindowSize(window, &w, &h);
  1026 
  1027     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
  1028 
  1029     data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
  1030                        GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
  1031 
  1032     /* Flip the rows to be top-down */
  1033     length = rect->w * SDL_BYTESPERPIXEL(temp_format);
  1034     src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
  1035     dst = (Uint8*)temp_pixels;
  1036     tmp = SDL_stack_alloc(Uint8, length);
  1037     rows = rect->h / 2;
  1038     while (rows--) {
  1039         SDL_memcpy(tmp, dst, length);
  1040         SDL_memcpy(dst, src, length);
  1041         SDL_memcpy(src, tmp, length);
  1042         dst += temp_pitch;
  1043         src -= temp_pitch;
  1044     }
  1045     SDL_stack_free(tmp);
  1046 
  1047     status = SDL_ConvertPixels(rect->w, rect->h,
  1048                                temp_format, temp_pixels, temp_pitch,
  1049                                pixel_format, pixels, pitch);
  1050     SDL_free(temp_pixels);
  1051 
  1052     return status;
  1053 }
  1054 
  1055 static void
  1056 GLES_RenderPresent(SDL_Renderer * renderer)
  1057 {
  1058     GLES_ActivateRenderer(renderer);
  1059 
  1060     SDL_GL_SwapWindow(renderer->window);
  1061 }
  1062 
  1063 static void
  1064 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1065 {
  1066     GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
  1067 
  1068     GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
  1069 
  1070     GLES_ActivateRenderer(renderer);
  1071 
  1072     if (!data) {
  1073         return;
  1074     }
  1075     if (data->texture) {
  1076         renderdata->glDeleteTextures(1, &data->texture);
  1077     }
  1078     if (data->pixels) {
  1079         SDL_free(data->pixels);
  1080     }
  1081     SDL_free(data);
  1082     texture->driverdata = NULL;
  1083 }
  1084 
  1085 static void
  1086 GLES_DestroyRenderer(SDL_Renderer * renderer)
  1087 {
  1088     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1089 
  1090     if (data) {
  1091         if (data->context) {
  1092             while (data->framebuffers) {
  1093                GLES_FBOList *nextnode = data->framebuffers->next;
  1094                data->glDeleteFramebuffersOES(1, &data->framebuffers->FBO);
  1095                SDL_free(data->framebuffers);
  1096                data->framebuffers = nextnode;
  1097             }
  1098             SDL_GL_DeleteContext(data->context);
  1099         }
  1100         SDL_free(data);
  1101     }
  1102     SDL_free(renderer);
  1103 }
  1104 
  1105 static int GLES_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
  1106 {
  1107     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1108     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
  1109     GLES_ActivateRenderer(renderer);
  1110 
  1111     data->glEnable(GL_TEXTURE_2D);
  1112     data->glBindTexture(texturedata->type, texturedata->texture);
  1113 
  1114     if(texw) *texw = (float)texturedata->texw;
  1115     if(texh) *texh = (float)texturedata->texh;
  1116 
  1117     return 0;
  1118 }
  1119 
  1120 static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
  1121 {
  1122     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
  1123     GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
  1124     GLES_ActivateRenderer(renderer);
  1125     data->glDisable(texturedata->type);
  1126 
  1127     return 0;
  1128 }
  1129 
  1130 #endif /* SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED */
  1131 
  1132 /* vi: set ts=4 sw=4 expandtab: */