src/render/opengles/SDL_render_gles.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 13 Mar 2011 11:18:35 -0700
changeset 5484 e20c93bc9122
parent 5402 5d102cd8aef3
child 5503 be88d105e91c
permissions -rw-r--r--
Added the SDL_HINT_RENDER_SCALE_QUALITY hint, which defaults to nearest pixel sampling.
hfutrell@2739
     1
/*
hfutrell@2739
     2
    SDL - Simple DirectMedia Layer
slouken@5262
     3
    Copyright (C) 1997-2011 Sam Lantinga
hfutrell@2739
     4
hfutrell@2739
     5
    This library is free software; you can redistribute it and/or
hfutrell@2739
     6
    modify it under the terms of the GNU Lesser General Public
hfutrell@2739
     7
    License as published by the Free Software Foundation; either
hfutrell@2739
     8
    version 2.1 of the License, or (at your option) any later version.
hfutrell@2739
     9
hfutrell@2739
    10
    This library is distributed in the hope that it will be useful,
hfutrell@2739
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
hfutrell@2739
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
hfutrell@2739
    13
    Lesser General Public License for more details.
hfutrell@2739
    14
hfutrell@2739
    15
    You should have received a copy of the GNU Lesser General Public
hfutrell@2739
    16
    License along with this library; if not, write to the Free Software
hfutrell@2739
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
hfutrell@2739
    18
hfutrell@2739
    19
    Sam Lantinga
hfutrell@2739
    20
    slouken@libsdl.org
hfutrell@2739
    21
*/
hfutrell@2739
    22
#include "SDL_config.h"
hfutrell@2739
    23
slouken@5226
    24
#if SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED
hfutrell@2739
    25
slouken@5484
    26
#include "SDL_hints.h"
hfutrell@2739
    27
#include "SDL_opengles.h"
slouken@5154
    28
#include "../SDL_sysrender.h"
hfutrell@2739
    29
slouken@5150
    30
#if defined(SDL_VIDEO_DRIVER_PANDORA)
lestat@3165
    31
lestat@3165
    32
/* Empty function stub to get OpenGL ES 1.x support without  */
lestat@3165
    33
/* OpenGL ES extension GL_OES_draw_texture supported         */
slouken@3139
    34
GL_API void GL_APIENTRY
slouken@3139
    35
glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height)
slouken@3099
    36
{
slouken@3139
    37
    return;
slouken@3099
    38
}
slouken@3099
    39
slouken@5150
    40
#endif /* PANDORA */
slouken@3161
    41
hfutrell@2739
    42
/* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */
hfutrell@2739
    43
hfutrell@2739
    44
static const float inv255f = 1.0f / 255.0f;
hfutrell@2739
    45
hfutrell@2739
    46
static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
slouken@5147
    47
static void GLES_WindowEvent(SDL_Renderer * renderer,
slouken@5147
    48
                             const SDL_WindowEvent *event);
hfutrell@2739
    49
static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
hfutrell@2739
    50
static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@2753
    51
                              const SDL_Rect * rect, const void *pixels,
slouken@2753
    52
                              int pitch);
hfutrell@2739
    53
static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
    54
                            const SDL_Rect * rect, void **pixels, int *pitch);
slouken@2753
    55
static void GLES_UnlockTexture(SDL_Renderer * renderer,
slouken@2753
    56
                               SDL_Texture * texture);
slouken@5297
    57
static int GLES_UpdateViewport(SDL_Renderer * renderer);
slouken@5333
    58
static int GLES_RenderClear(SDL_Renderer * renderer);
slouken@3641
    59
static int GLES_RenderDrawPoints(SDL_Renderer * renderer,
slouken@3641
    60
                                 const SDL_Point * points, int count);
slouken@3641
    61
static int GLES_RenderDrawLines(SDL_Renderer * renderer,
slouken@3641
    62
                                const SDL_Point * points, int count);
slouken@3641
    63
static int GLES_RenderFillRects(SDL_Renderer * renderer,
slouken@5297
    64
                                const SDL_Rect * rects, int count);
hfutrell@2739
    65
static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@2753
    66
                           const SDL_Rect * srcrect,
slouken@2753
    67
                           const SDL_Rect * dstrect);
hfutrell@2739
    68
static void GLES_RenderPresent(SDL_Renderer * renderer);
slouken@2753
    69
static void GLES_DestroyTexture(SDL_Renderer * renderer,
slouken@2753
    70
                                SDL_Texture * texture);
hfutrell@2739
    71
static void GLES_DestroyRenderer(SDL_Renderer * renderer);
hfutrell@2739
    72
hfutrell@2739
    73
slouken@5201
    74
SDL_RenderDriver GLES_RenderDriver = {
hfutrell@2739
    75
    GLES_CreateRenderer,
hfutrell@2739
    76
    {
slouken@5203
    77
     "opengles",
slouken@5203
    78
     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
slouken@5156
    79
     1,
slouken@5156
    80
     {SDL_PIXELFORMAT_ABGR8888},
slouken@2753
    81
     0,
hfutrell@2739
    82
     0}
hfutrell@2739
    83
};
hfutrell@2739
    84
hfutrell@2739
    85
typedef struct
hfutrell@2739
    86
{
hfutrell@2739
    87
    SDL_GLContext context;
slouken@5355
    88
    struct {
slouken@5355
    89
        Uint32 color;
slouken@5355
    90
        int blendMode;
slouken@5355
    91
        GLenum scaleMode;
slouken@5355
    92
        SDL_bool tex_coords;
slouken@5355
    93
    } current;
slouken@2753
    94
slouken@2753
    95
    SDL_bool useDrawTexture;
slouken@2753
    96
    SDL_bool GL_OES_draw_texture_supported;
hfutrell@2739
    97
} GLES_RenderData;
hfutrell@2739
    98
hfutrell@2739
    99
typedef struct
hfutrell@2739
   100
{
hfutrell@2739
   101
    GLuint texture;
hfutrell@2739
   102
    GLenum type;
hfutrell@2739
   103
    GLfloat texw;
hfutrell@2739
   104
    GLfloat texh;
hfutrell@2739
   105
    GLenum format;
hfutrell@2739
   106
    GLenum formattype;
hfutrell@2739
   107
    void *pixels;
hfutrell@2739
   108
    int pitch;
slouken@5355
   109
    GLenum scaleMode;
hfutrell@2739
   110
} GLES_TextureData;
hfutrell@2739
   111
hfutrell@2739
   112
static void
hfutrell@2739
   113
GLES_SetError(const char *prefix, GLenum result)
hfutrell@2739
   114
{
hfutrell@2739
   115
    const char *error;
hfutrell@2739
   116
hfutrell@2739
   117
    switch (result) {
hfutrell@2739
   118
    case GL_NO_ERROR:
hfutrell@2739
   119
        error = "GL_NO_ERROR";
hfutrell@2739
   120
        break;
hfutrell@2739
   121
    case GL_INVALID_ENUM:
hfutrell@2739
   122
        error = "GL_INVALID_ENUM";
hfutrell@2739
   123
        break;
hfutrell@2739
   124
    case GL_INVALID_VALUE:
hfutrell@2739
   125
        error = "GL_INVALID_VALUE";
hfutrell@2739
   126
        break;
hfutrell@2739
   127
    case GL_INVALID_OPERATION:
hfutrell@2739
   128
        error = "GL_INVALID_OPERATION";
hfutrell@2739
   129
        break;
hfutrell@2739
   130
    case GL_STACK_OVERFLOW:
hfutrell@2739
   131
        error = "GL_STACK_OVERFLOW";
hfutrell@2739
   132
        break;
hfutrell@2739
   133
    case GL_STACK_UNDERFLOW:
hfutrell@2739
   134
        error = "GL_STACK_UNDERFLOW";
hfutrell@2739
   135
        break;
hfutrell@2739
   136
    case GL_OUT_OF_MEMORY:
hfutrell@2739
   137
        error = "GL_OUT_OF_MEMORY";
hfutrell@2739
   138
        break;
hfutrell@2739
   139
    default:
hfutrell@2739
   140
        error = "UNKNOWN";
hfutrell@2739
   141
        break;
hfutrell@2739
   142
    }
hfutrell@2739
   143
    SDL_SetError("%s: %s", prefix, error);
hfutrell@2739
   144
}
hfutrell@2739
   145
slouken@5297
   146
static SDL_GLContext SDL_CurrentContext = NULL;
slouken@5297
   147
slouken@5297
   148
static int
slouken@5297
   149
GLES_ActivateRenderer(SDL_Renderer * renderer)
slouken@5297
   150
{
slouken@5297
   151
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
slouken@5297
   152
slouken@5297
   153
    if (SDL_CurrentContext != data->context) {
slouken@5297
   154
        if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
slouken@5297
   155
            return -1;
slouken@5297
   156
        }
slouken@5297
   157
        SDL_CurrentContext = data->context;
slouken@5297
   158
slouken@5297
   159
        GLES_UpdateViewport(renderer);
slouken@5297
   160
    }
slouken@5297
   161
    return 0;
slouken@5297
   162
}
slouken@5297
   163
slouken@5355
   164
/* This is called if we need to invalidate all of the SDL OpenGL state */
slouken@5355
   165
static void
slouken@5355
   166
GLES_ResetState(SDL_Renderer *renderer)
slouken@5355
   167
{
slouken@5355
   168
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
slouken@5355
   169
slouken@5355
   170
    if (SDL_CurrentContext == data->context) {
slouken@5355
   171
        GLES_UpdateViewport(renderer);
slouken@5355
   172
    } else {
slouken@5355
   173
        GLES_ActivateRenderer(renderer);
slouken@5355
   174
    }
slouken@5355
   175
slouken@5355
   176
    data->current.color = 0;
slouken@5355
   177
    data->current.blendMode = -1;
slouken@5355
   178
    data->current.scaleMode = 0;
slouken@5355
   179
    data->current.tex_coords = SDL_FALSE;
slouken@5355
   180
slouken@5355
   181
    glDisable(GL_DEPTH_TEST);
slouken@5355
   182
    glDisable(GL_CULL_FACE);
slouken@5355
   183
slouken@5355
   184
    glMatrixMode(GL_MODELVIEW);
slouken@5355
   185
    glLoadIdentity();
slouken@5355
   186
slouken@5355
   187
    glEnableClientState(GL_VERTEX_ARRAY);
slouken@5355
   188
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
slouken@5355
   189
}
slouken@5355
   190
hfutrell@2739
   191
SDL_Renderer *
hfutrell@2739
   192
GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
hfutrell@2739
   193
{
slouken@2753
   194
hfutrell@2739
   195
    SDL_Renderer *renderer;
hfutrell@2739
   196
    GLES_RenderData *data;
hfutrell@2739
   197
    GLint value;
hfutrell@2739
   198
hfutrell@2739
   199
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
hfutrell@2739
   200
    if (!renderer) {
hfutrell@2739
   201
        SDL_OutOfMemory();
hfutrell@2739
   202
        return NULL;
hfutrell@2739
   203
    }
hfutrell@2739
   204
hfutrell@2739
   205
    data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
hfutrell@2739
   206
    if (!data) {
hfutrell@2739
   207
        GLES_DestroyRenderer(renderer);
hfutrell@2739
   208
        SDL_OutOfMemory();
hfutrell@2739
   209
        return NULL;
hfutrell@2739
   210
    }
hfutrell@2739
   211
slouken@5147
   212
    renderer->WindowEvent = GLES_WindowEvent;
hfutrell@2739
   213
    renderer->CreateTexture = GLES_CreateTexture;
hfutrell@2739
   214
    renderer->UpdateTexture = GLES_UpdateTexture;
hfutrell@2739
   215
    renderer->LockTexture = GLES_LockTexture;
hfutrell@2739
   216
    renderer->UnlockTexture = GLES_UnlockTexture;
slouken@5297
   217
    renderer->UpdateViewport = GLES_UpdateViewport;
slouken@5333
   218
    renderer->RenderClear = GLES_RenderClear;
slouken@3641
   219
    renderer->RenderDrawPoints = GLES_RenderDrawPoints;
slouken@3641
   220
    renderer->RenderDrawLines = GLES_RenderDrawLines;
slouken@3641
   221
    renderer->RenderFillRects = GLES_RenderFillRects;
hfutrell@2739
   222
    renderer->RenderCopy = GLES_RenderCopy;
hfutrell@2739
   223
    renderer->RenderPresent = GLES_RenderPresent;
hfutrell@2739
   224
    renderer->DestroyTexture = GLES_DestroyTexture;
hfutrell@2739
   225
    renderer->DestroyRenderer = GLES_DestroyRenderer;
slouken@5201
   226
    renderer->info = GLES_RenderDriver.info;
slouken@5297
   227
    renderer->info.flags = SDL_RENDERER_ACCELERATED;
hfutrell@2739
   228
    renderer->driverdata = data;
slouken@2753
   229
slouken@5209
   230
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
slouken@5209
   231
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
slouken@5209
   232
slouken@3688
   233
    data->context = SDL_GL_CreateContext(window);
hfutrell@2739
   234
    if (!data->context) {
hfutrell@2739
   235
        GLES_DestroyRenderer(renderer);
hfutrell@2739
   236
        return NULL;
hfutrell@2739
   237
    }
slouken@3688
   238
    if (SDL_GL_MakeCurrent(window, data->context) < 0) {
hfutrell@2739
   239
        GLES_DestroyRenderer(renderer);
hfutrell@2739
   240
        return NULL;
hfutrell@2739
   241
    }
hfutrell@2739
   242
hfutrell@2739
   243
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
hfutrell@2739
   244
        SDL_GL_SetSwapInterval(1);
hfutrell@2739
   245
    } else {
hfutrell@2739
   246
        SDL_GL_SetSwapInterval(0);
hfutrell@2739
   247
    }
hfutrell@2739
   248
    if (SDL_GL_GetSwapInterval() > 0) {
hfutrell@2739
   249
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
hfutrell@2739
   250
    }
hfutrell@2739
   251
slouken@3161
   252
#if SDL_VIDEO_DRIVER_PANDORA
slouken@3161
   253
    data->GL_OES_draw_texture_supported = SDL_FALSE;
slouken@3161
   254
    data->useDrawTexture = SDL_FALSE;
slouken@3161
   255
#else
slouken@2753
   256
    if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) {
slouken@2753
   257
        data->GL_OES_draw_texture_supported = SDL_TRUE;
slouken@2753
   258
        data->useDrawTexture = SDL_TRUE;
slouken@2753
   259
    } else {
slouken@2753
   260
        data->GL_OES_draw_texture_supported = SDL_FALSE;
slouken@2753
   261
        data->useDrawTexture = SDL_FALSE;
slouken@2753
   262
    }
slouken@3161
   263
#endif
hfutrell@2739
   264
slouken@5204
   265
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
hfutrell@2739
   266
    renderer->info.max_texture_width = value;
slouken@5204
   267
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
hfutrell@2739
   268
    renderer->info.max_texture_height = value;
hfutrell@2739
   269
hfutrell@2739
   270
    /* Set up parameters for rendering */
slouken@5355
   271
    GLES_ResetState(renderer);
hfutrell@2739
   272
hfutrell@2739
   273
    return renderer;
hfutrell@2739
   274
}
hfutrell@2739
   275
slouken@5147
   276
static void
slouken@5147
   277
GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
hfutrell@2739
   278
{
slouken@5276
   279
    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
slouken@5147
   280
        /* Rebind the context to the window area and update matrices */
slouken@5147
   281
        SDL_CurrentContext = NULL;
slouken@5147
   282
    }
hfutrell@2739
   283
}
hfutrell@2739
   284
hfutrell@2739
   285
static __inline__ int
hfutrell@2739
   286
power_of_2(int input)
hfutrell@2739
   287
{
hfutrell@2739
   288
    int value = 1;
hfutrell@2739
   289
hfutrell@2739
   290
    while (value < input) {
hfutrell@2739
   291
        value <<= 1;
hfutrell@2739
   292
    }
hfutrell@2739
   293
    return value;
hfutrell@2739
   294
}
hfutrell@2739
   295
slouken@5484
   296
static GLenum
slouken@5484
   297
GetScaleQuality(void)
slouken@5484
   298
{
slouken@5484
   299
    const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
slouken@5484
   300
slouken@5484
   301
    if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
slouken@5484
   302
        return GL_NEAREST;
slouken@5484
   303
    } else {
slouken@5484
   304
        return GL_LINEAR;
slouken@5484
   305
    }
slouken@5484
   306
}
slouken@5484
   307
hfutrell@2739
   308
static int
slouken@3139
   309
GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
hfutrell@2739
   310
{
hfutrell@2739
   311
    GLES_TextureData *data;
hfutrell@2739
   312
    GLint internalFormat;
hfutrell@2739
   313
    GLenum format, type;
hfutrell@2739
   314
    int texture_w, texture_h;
hfutrell@2739
   315
    GLenum result;
slouken@3099
   316
slouken@5147
   317
    GLES_ActivateRenderer(renderer);
slouken@5147
   318
slouken@2753
   319
    switch (texture->format) {
slouken@2753
   320
    case SDL_PIXELFORMAT_ABGR8888:
slouken@3139
   321
        internalFormat = GL_RGBA;
slouken@3139
   322
        format = GL_RGBA;
slouken@3139
   323
        type = GL_UNSIGNED_BYTE;
slouken@3139
   324
        break;
slouken@2753
   325
    default:
slouken@5203
   326
        SDL_SetError("Texture format not supported");
slouken@2753
   327
        return -1;
hfutrell@2739
   328
    }
slouken@2753
   329
slouken@2753
   330
    data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data));
hfutrell@2739
   331
    if (!data) {
hfutrell@2739
   332
        SDL_OutOfMemory();
hfutrell@2739
   333
        return -1;
hfutrell@2739
   334
    }
hfutrell@2739
   335
hfutrell@2739
   336
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
hfutrell@2739
   337
        data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
slouken@5402
   338
        data->pixels = SDL_calloc(1, texture->h * data->pitch);
hfutrell@2739
   339
        if (!data->pixels) {
hfutrell@2739
   340
            SDL_OutOfMemory();
hfutrell@2739
   341
            SDL_free(data);
hfutrell@2739
   342
            return -1;
hfutrell@2739
   343
        }
hfutrell@2739
   344
    }
hfutrell@2739
   345
hfutrell@2739
   346
    texture->driverdata = data;
hfutrell@2739
   347
slouken@5204
   348
    glGetError();
slouken@5204
   349
    glEnable(GL_TEXTURE_2D);
slouken@5204
   350
    glGenTextures(1, &data->texture);
slouken@2753
   351
slouken@2753
   352
    data->type = GL_TEXTURE_2D;
slouken@2753
   353
    /* no NPOV textures allowed in OpenGL ES (yet) */
slouken@2753
   354
    texture_w = power_of_2(texture->w);
slouken@2753
   355
    texture_h = power_of_2(texture->h);
slouken@2753
   356
    data->texw = (GLfloat) texture->w / texture_w;
slouken@2753
   357
    data->texh = (GLfloat) texture->h / texture_h;
slouken@2753
   358
hfutrell@2739
   359
    data->format = format;
hfutrell@2739
   360
    data->formattype = type;
slouken@5484
   361
    data->scaleMode = GetScaleQuality();
slouken@5204
   362
    glBindTexture(data->type, data->texture);
slouken@5355
   363
    glTexParameteri(data->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
slouken@5355
   364
    glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
slouken@2753
   365
slouken@5204
   366
    glTexImage2D(data->type, 0, internalFormat, texture_w,
slouken@2753
   367
                             texture_h, 0, format, type, NULL);
slouken@5204
   368
    glDisable(GL_TEXTURE_2D);
hfutrell@2739
   369
slouken@5204
   370
    result = glGetError();
hfutrell@2739
   371
    if (result != GL_NO_ERROR) {
hfutrell@2739
   372
        GLES_SetError("glTexImage2D()", result);
hfutrell@2739
   373
        return -1;
hfutrell@2739
   374
    }
hfutrell@2739
   375
    return 0;
hfutrell@2739
   376
}
hfutrell@2739
   377
hfutrell@2739
   378
static int
slouken@3139
   379
GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@3139
   380
                   const SDL_Rect * rect, const void *pixels, int pitch)
hfutrell@2739
   381
{
hfutrell@2739
   382
    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
slouken@5227
   383
    Uint8 *blob = NULL;
slouken@5227
   384
    Uint8 *src;
slouken@5227
   385
    int srcPitch;
slouken@5227
   386
    int y;
hfutrell@2739
   387
slouken@5147
   388
    GLES_ActivateRenderer(renderer);
slouken@5147
   389
slouken@5227
   390
    /* Bail out if we're supposed to update an empty rectangle */
slouken@5227
   391
    if (rect->w <= 0 || rect->h <= 0)
slouken@5227
   392
        return 0;
slouken@5227
   393
slouken@5227
   394
    /* Reformat the texture data into a tightly packed array */
slouken@5227
   395
    srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format);
slouken@5227
   396
    src = (Uint8 *)pixels;
slouken@5227
   397
    if (pitch != srcPitch)
slouken@5227
   398
    {
slouken@5227
   399
        blob = (Uint8 *)SDL_malloc(srcPitch * rect->h);
slouken@5227
   400
        if (!blob)
slouken@5227
   401
        {
slouken@5227
   402
            SDL_OutOfMemory();
slouken@5227
   403
            return -1;
slouken@5227
   404
        }
slouken@5227
   405
        src = blob;
slouken@5227
   406
        for (y = 0; y < rect->h; ++y)
slouken@5227
   407
        {
slouken@5227
   408
            SDL_memcpy(src, pixels, srcPitch);
slouken@5227
   409
            src += srcPitch;
slouken@5227
   410
            pixels = (Uint8 *)pixels + pitch;
slouken@5227
   411
        }
slouken@5227
   412
        src = blob;
slouken@5227
   413
    }
slouken@5227
   414
slouken@5227
   415
    /* Create a texture subimage with the supplied data */
slouken@5204
   416
    glGetError();
slouken@5204
   417
    glEnable(data->type);
slouken@5204
   418
    glBindTexture(data->type, data->texture);
slouken@5227
   419
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@5227
   420
    glTexSubImage2D(data->type,
slouken@5227
   421
                    0,
slouken@5227
   422
                    rect->x,
slouken@5227
   423
                    rect->y,
slouken@5227
   424
                    rect->w,
slouken@5227
   425
                    rect->h,
slouken@5227
   426
                    data->format,
slouken@5227
   427
                    data->formattype,
slouken@5227
   428
                    src);
slouken@5227
   429
    if (blob) {
slouken@5227
   430
        SDL_free(blob);
slouken@5052
   431
    }
slouken@5052
   432
slouken@5227
   433
    if (glGetError() != GL_NO_ERROR)
slouken@5227
   434
    {
slouken@5227
   435
        SDL_SetError("Failed to update texture");
hfutrell@2739
   436
        return -1;
hfutrell@2739
   437
    }
hfutrell@2739
   438
    return 0;
hfutrell@2739
   439
}
hfutrell@2739
   440
hfutrell@2739
   441
static int
hfutrell@2739
   442
GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   443
                 const SDL_Rect * rect, void **pixels, int *pitch)
hfutrell@2739
   444
{
hfutrell@2739
   445
    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
hfutrell@2739
   446
hfutrell@2739
   447
    *pixels =
hfutrell@2739
   448
        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
hfutrell@2739
   449
                  rect->x * SDL_BYTESPERPIXEL(texture->format));
hfutrell@2739
   450
    *pitch = data->pitch;
hfutrell@2739
   451
    return 0;
hfutrell@2739
   452
}
hfutrell@2739
   453
hfutrell@2739
   454
static void
hfutrell@2739
   455
GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
hfutrell@2739
   456
{
slouken@5156
   457
    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
slouken@5227
   458
    SDL_Rect rect;
hfutrell@2739
   459
slouken@5227
   460
    /* We do whole texture updates, at least for now */
slouken@5227
   461
    rect.x = 0;
slouken@5227
   462
    rect.y = 0;
slouken@5227
   463
    rect.w = texture->w;
slouken@5227
   464
    rect.h = texture->h;
slouken@5227
   465
    GLES_UpdateTexture(renderer, texture, &rect, data->pixels, data->pitch);
hfutrell@2739
   466
}
hfutrell@2739
   467
slouken@5297
   468
static int
slouken@5297
   469
GLES_UpdateViewport(SDL_Renderer * renderer)
slouken@5224
   470
{
slouken@5297
   471
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
slouken@5224
   472
slouken@5297
   473
    if (SDL_CurrentContext != data->context) {
slouken@5297
   474
        /* We'll update the viewport after we rebind the context */
slouken@5297
   475
        return 0;
slouken@5297
   476
    }
slouken@5224
   477
slouken@5297
   478
    glViewport(renderer->viewport.x, renderer->viewport.y,
slouken@5297
   479
               renderer->viewport.w, renderer->viewport.h);
slouken@5297
   480
slouken@5297
   481
    glMatrixMode(GL_PROJECTION);
slouken@5297
   482
    glLoadIdentity();
slouken@5297
   483
    glOrthof((GLfloat) 0,
slouken@5297
   484
			 (GLfloat) renderer->viewport.w,
slouken@5297
   485
             (GLfloat) renderer->viewport.h,
slouken@5297
   486
             (GLfloat) 0, 0.0, 1.0);
slouken@5297
   487
    return 0;
slouken@5224
   488
}
slouken@5224
   489
slouken@5355
   490
static void
slouken@5355
   491
GLES_SetColor(GLES_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
slouken@5333
   492
{
slouken@5355
   493
    Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
slouken@5333
   494
slouken@5355
   495
    if (color != data->current.color) {
slouken@5355
   496
        glColor4f((GLfloat) r * inv255f,
slouken@5355
   497
                        (GLfloat) g * inv255f,
slouken@5355
   498
                        (GLfloat) b * inv255f,
slouken@5355
   499
                        (GLfloat) a * inv255f);
slouken@5355
   500
        data->current.color = color;
slouken@5355
   501
    }
slouken@5333
   502
}
slouken@5333
   503
slouken@5224
   504
static void
slouken@5140
   505
GLES_SetBlendMode(GLES_RenderData * data, int blendMode)
slouken@2936
   506
{
slouken@5355
   507
    if (blendMode != data->current.blendMode) {
slouken@2936
   508
        switch (blendMode) {
slouken@2936
   509
        case SDL_BLENDMODE_NONE:
slouken@5204
   510
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
slouken@5204
   511
            glDisable(GL_BLEND);
slouken@2936
   512
            break;
slouken@2936
   513
        case SDL_BLENDMODE_BLEND:
slouken@5204
   514
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@5204
   515
            glEnable(GL_BLEND);
slouken@5204
   516
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
slouken@2936
   517
            break;
slouken@2936
   518
        case SDL_BLENDMODE_ADD:
slouken@5204
   519
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@5204
   520
            glEnable(GL_BLEND);
slouken@5204
   521
            glBlendFunc(GL_SRC_ALPHA, GL_ONE);
slouken@2936
   522
            break;
slouken@5184
   523
        case SDL_BLENDMODE_MOD:
slouken@5204
   524
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@5204
   525
            glEnable(GL_BLEND);
slouken@5204
   526
            glBlendFunc(GL_ZERO, GL_SRC_COLOR);
slouken@5184
   527
            break;
slouken@2936
   528
        }
slouken@5355
   529
        data->current.blendMode = blendMode;
slouken@2936
   530
    }
slouken@2936
   531
}
slouken@2936
   532
slouken@5355
   533
static void
slouken@5355
   534
GLES_SetTexCoords(GLES_RenderData * data, SDL_bool enabled)
slouken@5355
   535
{
slouken@5355
   536
    if (enabled != data->current.tex_coords) {
slouken@5355
   537
        if (enabled) {
slouken@5355
   538
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
slouken@5355
   539
        } else {
slouken@5355
   540
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
slouken@5355
   541
        }
slouken@5355
   542
        data->current.tex_coords = enabled;
slouken@5355
   543
    }
slouken@5355
   544
}
slouken@5355
   545
slouken@5355
   546
static void
slouken@5355
   547
GLES_SetDrawingState(SDL_Renderer * renderer)
slouken@5355
   548
{
slouken@5355
   549
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
slouken@5355
   550
slouken@5355
   551
    GLES_ActivateRenderer(renderer);
slouken@5355
   552
slouken@5355
   553
    GLES_SetColor(data, (GLfloat) renderer->r,
slouken@5355
   554
                        (GLfloat) renderer->g,
slouken@5355
   555
                        (GLfloat) renderer->b,
slouken@5355
   556
                        (GLfloat) renderer->a);
slouken@5355
   557
slouken@5355
   558
    GLES_SetBlendMode(data, renderer->blendMode);
slouken@5355
   559
slouken@5355
   560
    GLES_SetTexCoords(data, SDL_FALSE);
slouken@5355
   561
}
slouken@5355
   562
slouken@5355
   563
static int
slouken@5355
   564
GLES_RenderClear(SDL_Renderer * renderer)
slouken@5355
   565
{
slouken@5355
   566
    GLES_ActivateRenderer(renderer);
slouken@5355
   567
slouken@5355
   568
    glClearColor((GLfloat) renderer->r * inv255f,
slouken@5355
   569
                 (GLfloat) renderer->g * inv255f,
slouken@5355
   570
                 (GLfloat) renderer->b * inv255f,
slouken@5355
   571
                 (GLfloat) renderer->a * inv255f);
slouken@5355
   572
slouken@5355
   573
    glClear(GL_COLOR_BUFFER_BIT);
slouken@5355
   574
slouken@5355
   575
    return 0;
slouken@5355
   576
}
slouken@5355
   577
hfutrell@2739
   578
static int
slouken@3641
   579
GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
slouken@3641
   580
                      int count)
hfutrell@2739
   581
{
slouken@2936
   582
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
slouken@3547
   583
    int i;
slouken@3547
   584
    GLshort *vertices;
slouken@2753
   585
slouken@5355
   586
    GLES_SetDrawingState(renderer);
slouken@2936
   587
slouken@3547
   588
    vertices = SDL_stack_alloc(GLshort, count*2);
slouken@3547
   589
    for (i = 0; i < count; ++i) {
slouken@3547
   590
        vertices[2*i+0] = (GLshort)points[i].x;
slouken@3547
   591
        vertices[2*i+1] = (GLshort)points[i].y;
slouken@3547
   592
    }
slouken@5204
   593
    glVertexPointer(2, GL_SHORT, 0, vertices);
slouken@5204
   594
    glDrawArrays(GL_POINTS, 0, count);
slouken@3547
   595
    SDL_stack_free(vertices);
slouken@2964
   596
slouken@2936
   597
    return 0;
slouken@2936
   598
}
slouken@2936
   599
slouken@2936
   600
static int
slouken@3641
   601
GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
slouken@3641
   602
                     int count)
slouken@2936
   603
{
slouken@2936
   604
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
slouken@3547
   605
    int i;
slouken@3547
   606
    GLshort *vertices;
slouken@2936
   607
slouken@5355
   608
    GLES_SetDrawingState(renderer);
slouken@2936
   609
slouken@3547
   610
    vertices = SDL_stack_alloc(GLshort, count*2);
slouken@3547
   611
    for (i = 0; i < count; ++i) {
slouken@3547
   612
        vertices[2*i+0] = (GLshort)points[i].x;
slouken@3547
   613
        vertices[2*i+1] = (GLshort)points[i].y;
slouken@3547
   614
    }
slouken@5204
   615
    glVertexPointer(2, GL_SHORT, 0, vertices);
slouken@3536
   616
    if (count > 2 && 
slouken@3536
   617
        points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
slouken@3536
   618
        /* GL_LINE_LOOP takes care of the final segment */
slouken@3536
   619
        --count;
slouken@5204
   620
        glDrawArrays(GL_LINE_LOOP, 0, count);
slouken@3536
   621
    } else {
slouken@5204
   622
        glDrawArrays(GL_LINE_STRIP, 0, count);
slouken@3536
   623
    }
slouken@3547
   624
    SDL_stack_free(vertices);
hfutrell@2949
   625
slouken@2936
   626
    return 0;
slouken@2936
   627
}
slouken@2936
   628
slouken@2936
   629
static int
slouken@5297
   630
GLES_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects,
slouken@3641
   631
                     int count)
slouken@2936
   632
{
slouken@2753
   633
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
slouken@3536
   634
    int i;
slouken@2753
   635
slouken@5355
   636
    GLES_SetDrawingState(renderer);
slouken@2753
   637
slouken@3536
   638
    for (i = 0; i < count; ++i) {
slouken@5297
   639
        const SDL_Rect *rect = &rects[i];
slouken@3536
   640
        GLshort minx = rect->x;
slouken@3536
   641
        GLshort maxx = rect->x + rect->w;
slouken@3536
   642
        GLshort miny = rect->y;
slouken@3536
   643
        GLshort maxy = rect->y + rect->h;
slouken@3536
   644
        GLshort vertices[8];
slouken@3536
   645
        vertices[0] = minx;
slouken@3536
   646
        vertices[1] = miny;
slouken@3536
   647
        vertices[2] = maxx;
slouken@3536
   648
        vertices[3] = miny;
slouken@3536
   649
        vertices[4] = minx;
slouken@3536
   650
        vertices[5] = maxy;
slouken@3536
   651
        vertices[6] = maxx;
slouken@3536
   652
        vertices[7] = maxy;
slouken@2964
   653
slouken@5204
   654
        glVertexPointer(2, GL_SHORT, 0, vertices);
slouken@5204
   655
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
slouken@3536
   656
    }
hfutrell@2949
   657
slouken@2753
   658
    return 0;
hfutrell@2739
   659
}
hfutrell@2739
   660
hfutrell@2739
   661
static int
hfutrell@2739
   662
GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@2753
   663
                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
hfutrell@2739
   664
{
slouken@2753
   665
hfutrell@2739
   666
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
hfutrell@2739
   667
    GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
hfutrell@2739
   668
    int minx, miny, maxx, maxy;
hfutrell@2739
   669
    GLfloat minu, maxu, minv, maxv;
slouken@2753
   670
slouken@5147
   671
    GLES_ActivateRenderer(renderer);
slouken@5147
   672
slouken@5204
   673
    glEnable(GL_TEXTURE_2D);
lestat@3122
   674
slouken@5204
   675
    glBindTexture(texturedata->type, texturedata->texture);
slouken@2753
   676
slouken@5355
   677
    if (texturedata->scaleMode != data->current.scaleMode) {
slouken@5355
   678
        glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
slouken@5355
   679
                        texturedata->scaleMode);
slouken@5355
   680
        glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
slouken@5355
   681
                        texturedata->scaleMode);
slouken@5355
   682
        data->current.scaleMode = texturedata->scaleMode;
slouken@5355
   683
    }
slouken@5355
   684
hfutrell@2739
   685
    if (texture->modMode) {
slouken@5355
   686
        GLES_SetColor(data, texture->r, texture->g, texture->b, texture->a);
hfutrell@2739
   687
    } else {
slouken@5355
   688
        GLES_SetColor(data, 255, 255, 255, 255);
hfutrell@2739
   689
    }
hfutrell@2739
   690
slouken@5140
   691
    GLES_SetBlendMode(data, texture->blendMode);
hfutrell@2739
   692
slouken@5355
   693
    GLES_SetTexCoords(data, SDL_TRUE);
slouken@5355
   694
slouken@2753
   695
    if (data->GL_OES_draw_texture_supported && data->useDrawTexture) {
slouken@2753
   696
        /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */
slouken@5154
   697
        GLint cropRect[4];
slouken@5154
   698
        int w, h;
slouken@3685
   699
        SDL_Window *window = renderer->window;
slouken@5154
   700
slouken@5154
   701
        SDL_GetWindowSize(window, &w, &h);
slouken@2753
   702
        cropRect[0] = srcrect->x;
slouken@2753
   703
        cropRect[1] = srcrect->y + srcrect->h;
slouken@2753
   704
        cropRect[2] = srcrect->w;
slouken@2753
   705
        cropRect[3] = -srcrect->h;
slouken@5204
   706
        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
slouken@2753
   707
                               cropRect);
slouken@5204
   708
        glDrawTexiOES(dstrect->x, h - dstrect->y - dstrect->h, 0,
slouken@5154
   709
                            dstrect->w, dstrect->h);
slouken@2753
   710
    } else {
slouken@2753
   711
slouken@2753
   712
        minx = dstrect->x;
slouken@2753
   713
        miny = dstrect->y;
slouken@2753
   714
        maxx = dstrect->x + dstrect->w;
slouken@2753
   715
        maxy = dstrect->y + dstrect->h;
slouken@2753
   716
slouken@2753
   717
        minu = (GLfloat) srcrect->x / texture->w;
slouken@2753
   718
        minu *= texturedata->texw;
slouken@2753
   719
        maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
slouken@2753
   720
        maxu *= texturedata->texw;
slouken@2753
   721
        minv = (GLfloat) srcrect->y / texture->h;
slouken@2753
   722
        minv *= texturedata->texh;
slouken@2753
   723
        maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
slouken@2753
   724
        maxv *= texturedata->texh;
slouken@2753
   725
slouken@2753
   726
        GLshort vertices[8];
slouken@2753
   727
        GLfloat texCoords[8];
slouken@2753
   728
slouken@2753
   729
        vertices[0] = minx;
slouken@2753
   730
        vertices[1] = miny;
slouken@2753
   731
        vertices[2] = maxx;
slouken@2753
   732
        vertices[3] = miny;
slouken@2753
   733
        vertices[4] = minx;
slouken@2753
   734
        vertices[5] = maxy;
slouken@2753
   735
        vertices[6] = maxx;
slouken@2753
   736
        vertices[7] = maxy;
slouken@2753
   737
slouken@2753
   738
        texCoords[0] = minu;
slouken@2753
   739
        texCoords[1] = minv;
slouken@2753
   740
        texCoords[2] = maxu;
slouken@2753
   741
        texCoords[3] = minv;
slouken@2753
   742
        texCoords[4] = minu;
slouken@2753
   743
        texCoords[5] = maxv;
slouken@2753
   744
        texCoords[6] = maxu;
slouken@2753
   745
        texCoords[7] = maxv;
slouken@2753
   746
slouken@5204
   747
        glVertexPointer(2, GL_SHORT, 0, vertices);
slouken@5204
   748
        glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
slouken@5204
   749
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
lestat@3122
   750
    }
slouken@5204
   751
    glDisable(GL_TEXTURE_2D);
slouken@2753
   752
hfutrell@2739
   753
    return 0;
hfutrell@2739
   754
}
hfutrell@2739
   755
hfutrell@2739
   756
static void
slouken@3139
   757
GLES_RenderPresent(SDL_Renderer * renderer)
hfutrell@2739
   758
{
slouken@5147
   759
    GLES_ActivateRenderer(renderer);
slouken@5147
   760
hfutrell@2739
   761
    SDL_GL_SwapWindow(renderer->window);
hfutrell@2739
   762
}
hfutrell@2739
   763
hfutrell@2739
   764
static void
hfutrell@2739
   765
GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
hfutrell@2739
   766
{
hfutrell@2739
   767
    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
hfutrell@2739
   768
slouken@5147
   769
    GLES_ActivateRenderer(renderer);
slouken@5147
   770
hfutrell@2739
   771
    if (!data) {
hfutrell@2739
   772
        return;
hfutrell@2739
   773
    }
hfutrell@2739
   774
    if (data->texture) {
slouken@2753
   775
        glDeleteTextures(1, &data->texture);
hfutrell@2739
   776
    }
hfutrell@2739
   777
    if (data->pixels) {
hfutrell@2739
   778
        SDL_free(data->pixels);
hfutrell@2739
   779
    }
hfutrell@2739
   780
    SDL_free(data);
hfutrell@2739
   781
    texture->driverdata = NULL;
hfutrell@2739
   782
}
hfutrell@2739
   783
hfutrell@2739
   784
static void
hfutrell@2739
   785
GLES_DestroyRenderer(SDL_Renderer * renderer)
hfutrell@2739
   786
{
hfutrell@2739
   787
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
hfutrell@2739
   788
hfutrell@2739
   789
    if (data) {
hfutrell@2739
   790
        if (data->context) {
hfutrell@2739
   791
            SDL_GL_DeleteContext(data->context);
hfutrell@2739
   792
        }
hfutrell@2739
   793
        SDL_free(data);
hfutrell@2739
   794
    }
hfutrell@2739
   795
    SDL_free(renderer);
hfutrell@2739
   796
}
hfutrell@2739
   797
slouken@5226
   798
#endif /* SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED */
hfutrell@2739
   799
hfutrell@2739
   800
/* vi: set ts=4 sw=4 expandtab: */