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