cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_render_gles.c (37706B)


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