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