src/render/opengl/SDL_render_gl.c
author Alex Szpakowski <slime73@gmail.com>
Tue, 15 Jul 2014 02:01:43 -0300
branchiOS-improvements
changeset 9489 6cd0275146b3
parent 8906 c8da136e2a83
child 9011 c3591f14ab7e
permissions -rw-r--r--
iOS now respects SDL_HINT_ACCELEROMETER_AS_JOYSTICK.
slouken@1918
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@1918
     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.
slouken@1918
     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:
slouken@1918
    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.
slouken@1918
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1918
    22
slouken@5226
    23
#if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
slouken@1920
    24
slouken@5233
    25
#include "SDL_hints.h"
slouken@5233
    26
#include "SDL_log.h"
icculus@8650
    27
#include "SDL_assert.h"
slouken@1920
    28
#include "SDL_opengl.h"
slouken@5154
    29
#include "../SDL_sysrender.h"
slouken@5228
    30
#include "SDL_shaders_gl.h"
slouken@1918
    31
slouken@2246
    32
#ifdef __MACOSX__
slouken@2246
    33
#include <OpenGL/OpenGL.h>
slouken@2246
    34
#endif
slouken@2246
    35
gabomdq@8264
    36
/* To prevent unnecessary window recreation, 
gabomdq@8264
    37
 * these should match the defaults selected in SDL_GL_ResetAttributes 
gabomdq@8264
    38
 */
gabomdq@8264
    39
gabomdq@8257
    40
#define RENDERER_CONTEXT_MAJOR 2
gabomdq@8264
    41
#define RENDERER_CONTEXT_MINOR 1
slouken@2778
    42
slouken@1918
    43
/* OpenGL renderer implementation */
slouken@1918
    44
slouken@2230
    45
/* Details on optimizing the texture path on Mac OS X:
slouken@5203
    46
   http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
slouken@2230
    47
*/
slouken@2230
    48
slouken@5154
    49
/* Used to re-create the window with OpenGL capability */
slouken@5154
    50
extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
icculus@2835
    51
slouken@1985
    52
static const float inv255f = 1.0f / 255.0f;
slouken@1985
    53
slouken@1918
    54
static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
slouken@5147
    55
static void GL_WindowEvent(SDL_Renderer * renderer,
slouken@5147
    56
                           const SDL_WindowEvent *event);
urkle@7746
    57
static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
slouken@1918
    58
static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1918
    59
static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
    60
                            const SDL_Rect * rect, const void *pixels,
slouken@1918
    61
                            int pitch);
slouken@7759
    62
static int GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@7759
    63
                               const SDL_Rect * rect,
slouken@7759
    64
                               const Uint8 *Yplane, int Ypitch,
slouken@7759
    65
                               const Uint8 *Uplane, int Upitch,
slouken@7759
    66
                               const Uint8 *Vplane, int Vpitch);
slouken@1918
    67
static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
    68
                          const SDL_Rect * rect, void **pixels, int *pitch);
slouken@1918
    69
static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@6247
    70
static int GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@5297
    71
static int GL_UpdateViewport(SDL_Renderer * renderer);
slouken@7141
    72
static int GL_UpdateClipRect(SDL_Renderer * renderer);
slouken@3596
    73
static int GL_RenderClear(SDL_Renderer * renderer);
slouken@3596
    74
static int GL_RenderDrawPoints(SDL_Renderer * renderer,
slouken@6528
    75
                               const SDL_FPoint * points, int count);
slouken@3596
    76
static int GL_RenderDrawLines(SDL_Renderer * renderer,
slouken@6528
    77
                              const SDL_FPoint * points, int count);
slouken@3596
    78
static int GL_RenderFillRects(SDL_Renderer * renderer,
slouken@6528
    79
                              const SDL_FRect * rects, int count);
slouken@1918
    80
static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
    81
                         const SDL_Rect * srcrect, const SDL_FRect * dstrect);
gabomdq@6320
    82
static int GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
    83
                         const SDL_Rect * srcrect, const SDL_FRect * dstrect,
slouken@6528
    84
                         const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
slouken@3431
    85
static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
    86
                               Uint32 pixel_format, void * pixels, int pitch);
slouken@1918
    87
static void GL_RenderPresent(SDL_Renderer * renderer);
slouken@1918
    88
static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1918
    89
static void GL_DestroyRenderer(SDL_Renderer * renderer);
gabomdq@6414
    90
static int GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
gabomdq@6414
    91
static int GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
slouken@1918
    92
slouken@1918
    93
SDL_RenderDriver GL_RenderDriver = {
slouken@1918
    94
    GL_CreateRenderer,
slouken@1918
    95
    {
slouken@1918
    96
     "opengl",
slouken@6237
    97
     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
slouken@5156
    98
     1,
slouken@5156
    99
     {SDL_PIXELFORMAT_ARGB8888},
slouken@1918
   100
     0,
slouken@1918
   101
     0}
slouken@1918
   102
};
slouken@1918
   103
slouken@6232
   104
typedef struct GL_FBOList GL_FBOList;
slouken@6232
   105
slouken@6232
   106
struct GL_FBOList
slouken@6232
   107
{
slouken@6232
   108
    Uint32 w, h;
slouken@6232
   109
    GLuint FBO;
slouken@6232
   110
    GL_FBOList *next;
slouken@6232
   111
};
slouken@6232
   112
slouken@1918
   113
typedef struct
slouken@1918
   114
{
slouken@1918
   115
    SDL_GLContext context;
slouken@7194
   116
slouken@7198
   117
    SDL_bool debug_enabled;
slouken@7194
   118
    SDL_bool GL_ARB_debug_output_supported;
slouken@7194
   119
    int errors;
slouken@7194
   120
    char **error_messages;
slouken@7194
   121
    GLDEBUGPROCARB next_error_callback;
slouken@7194
   122
    GLvoid *next_error_userparam;
slouken@7194
   123
slouken@2233
   124
    SDL_bool GL_ARB_texture_rectangle_supported;
slouken@5355
   125
    struct {
slouken@5355
   126
        GL_Shader shader;
slouken@5355
   127
        Uint32 color;
slouken@5355
   128
        int blendMode;
slouken@5355
   129
    } current;
slouken@7191
   130
slouken@6232
   131
    SDL_bool GL_EXT_framebuffer_object_supported;
slouken@6232
   132
    GL_FBOList *framebuffers;
slouken@1927
   133
slouken@1927
   134
    /* OpenGL functions */
slouken@1927
   135
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
slouken@5204
   136
#include "SDL_glfuncs.h"
slouken@1927
   137
#undef SDL_PROC
slouken@1974
   138
slouken@5228
   139
    /* Multitexture support */
slouken@5228
   140
    SDL_bool GL_ARB_multitexture_supported;
slouken@5228
   141
    PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
slouken@5351
   142
    GLint num_texture_units;
slouken@7191
   143
slouken@6232
   144
    PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
slouken@6232
   145
    PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
slouken@6232
   146
    PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
slouken@6232
   147
    PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
slouken@6232
   148
    PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
slouken@5228
   149
slouken@5228
   150
    /* Shader support */
slouken@5228
   151
    GL_ShaderContext *shaders;
slouken@5228
   152
slouken@1918
   153
} GL_RenderData;
slouken@1918
   154
slouken@1918
   155
typedef struct
slouken@1918
   156
{
slouken@1918
   157
    GLuint texture;
slouken@1920
   158
    GLenum type;
slouken@1918
   159
    GLfloat texw;
slouken@1918
   160
    GLfloat texh;
slouken@1920
   161
    GLenum format;
slouken@1920
   162
    GLenum formattype;
slouken@1918
   163
    void *pixels;
slouken@1918
   164
    int pitch;
slouken@5227
   165
    SDL_Rect locked_rect;
slouken@5264
   166
slouken@5264
   167
    /* YV12 texture support */
slouken@5264
   168
    SDL_bool yuv;
slouken@5264
   169
    GLuint utexture;
slouken@5264
   170
    GLuint vtexture;
slouken@7191
   171
slouken@6232
   172
    GL_FBOList *fbo;
slouken@1918
   173
} GL_TextureData;
slouken@1918
   174
slouken@7194
   175
SDL_FORCE_INLINE const char*
slouken@6494
   176
GL_TranslateError (GLenum error)
slouken@6494
   177
{
slouken@6494
   178
#define GL_ERROR_TRANSLATE(e) case e: return #e;
slouken@6494
   179
    switch (error) {
slouken@6494
   180
    GL_ERROR_TRANSLATE(GL_INVALID_ENUM)
slouken@6494
   181
    GL_ERROR_TRANSLATE(GL_INVALID_VALUE)
slouken@6494
   182
    GL_ERROR_TRANSLATE(GL_INVALID_OPERATION)
slouken@6494
   183
    GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY)
slouken@6494
   184
    GL_ERROR_TRANSLATE(GL_NO_ERROR)
slouken@6494
   185
    GL_ERROR_TRANSLATE(GL_STACK_OVERFLOW)
slouken@6494
   186
    GL_ERROR_TRANSLATE(GL_STACK_UNDERFLOW)
slouken@6494
   187
    GL_ERROR_TRANSLATE(GL_TABLE_TOO_LARGE)
slouken@6494
   188
    default:
slouken@6494
   189
        return "UNKNOWN";
slouken@6494
   190
}
slouken@6494
   191
#undef GL_ERROR_TRANSLATE
slouken@6494
   192
}
slouken@1918
   193
slouken@7194
   194
SDL_FORCE_INLINE void
slouken@7194
   195
GL_ClearErrors(SDL_Renderer *renderer)
slouken@7194
   196
{
slouken@7194
   197
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@7194
   198
slouken@7198
   199
    if (!data->debug_enabled)
slouken@7198
   200
    {
slouken@7198
   201
        return;
slouken@7198
   202
    }
slouken@7194
   203
    if (data->GL_ARB_debug_output_supported) {
slouken@7194
   204
        if (data->errors) {
slouken@7194
   205
            int i;
slouken@7194
   206
            for (i = 0; i < data->errors; ++i) {
slouken@7194
   207
                SDL_free(data->error_messages[i]);
slouken@7194
   208
            }
slouken@7194
   209
            SDL_free(data->error_messages);
slouken@7194
   210
slouken@7194
   211
            data->errors = 0;
slouken@7194
   212
            data->error_messages = NULL;
slouken@7194
   213
        }
slouken@7194
   214
    } else {
slouken@7194
   215
        while (data->glGetError() != GL_NO_ERROR) {
slouken@7194
   216
            continue;
slouken@7194
   217
        }
slouken@7194
   218
    }
slouken@7194
   219
}
slouken@7194
   220
slouken@7194
   221
SDL_FORCE_INLINE int
slouken@7194
   222
GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
slouken@1924
   223
{
slouken@6494
   224
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@6494
   225
    int ret = 0;
slouken@7194
   226
slouken@7198
   227
    if (!data->debug_enabled)
slouken@7198
   228
    {
slouken@7198
   229
        return 0;
slouken@7198
   230
    }
slouken@7194
   231
    if (data->GL_ARB_debug_output_supported) {
slouken@7194
   232
        if (data->errors) {
slouken@7194
   233
            int i;
slouken@7194
   234
            for (i = 0; i < data->errors; ++i) {
slouken@7194
   235
                SDL_SetError("%s: %s (%d): %s %s", prefix, file, line, function, data->error_messages[i]);
slouken@7194
   236
                ret = -1;
slouken@6494
   237
            }
slouken@7194
   238
            GL_ClearErrors(renderer);
slouken@7194
   239
        }
slouken@7194
   240
    } else {
slouken@7194
   241
        /* check gl errors (can return multiple errors) */
slouken@7194
   242
        for (;;) {
slouken@7194
   243
            GLenum error = data->glGetError();
slouken@7194
   244
            if (error != GL_NO_ERROR) {
slouken@7194
   245
                if (prefix == NULL || prefix[0] == '\0') {
slouken@7194
   246
                    prefix = "generic";
slouken@7194
   247
                }
slouken@7194
   248
                SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
slouken@7194
   249
                ret = -1;
slouken@7194
   250
            } else {
slouken@7194
   251
                break;
slouken@7194
   252
            }
slouken@6494
   253
        }
slouken@6494
   254
    }
slouken@6494
   255
    return ret;
slouken@6494
   256
}
slouken@1924
   257
icculus@6499
   258
#if 0
icculus@6499
   259
#define GL_CheckError(prefix, renderer)
icculus@6499
   260
#elif defined(_MSC_VER)
icculus@6499
   261
#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, __FILE__, __LINE__, __FUNCTION__)
icculus@6499
   262
#else
slouken@6494
   263
#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, __FILE__, __LINE__, __PRETTY_FUNCTION__)
slouken@6494
   264
#endif
slouken@1924
   265
slouken@1927
   266
static int
slouken@1927
   267
GL_LoadFunctions(GL_RenderData * data)
slouken@1927
   268
{
slouken@1927
   269
#ifdef __SDL_NOGETPROCADDR__
slouken@1927
   270
#define SDL_PROC(ret,func,params) data->func=func;
slouken@1927
   271
#else
slouken@1927
   272
#define SDL_PROC(ret,func,params) \
slouken@1927
   273
    do { \
slouken@1927
   274
        data->func = SDL_GL_GetProcAddress(#func); \
slouken@1927
   275
        if ( ! data->func ) { \
icculus@7037
   276
            return SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
slouken@1927
   277
        } \
slouken@1927
   278
    } while ( 0 );
slouken@1927
   279
#endif /* __SDL_NOGETPROCADDR__ */
slouken@1927
   280
slouken@5204
   281
#include "SDL_glfuncs.h"
slouken@1927
   282
#undef SDL_PROC
slouken@1927
   283
    return 0;
slouken@1927
   284
}
slouken@1927
   285
slouken@5297
   286
static SDL_GLContext SDL_CurrentContext = NULL;
slouken@5297
   287
slouken@5297
   288
static int
slouken@5297
   289
GL_ActivateRenderer(SDL_Renderer * renderer)
slouken@5297
   290
{
slouken@5297
   291
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5297
   292
slouken@8869
   293
    if (SDL_CurrentContext != data->context ||
slouken@8869
   294
        SDL_GL_GetCurrentContext() != data->context) {
slouken@5297
   295
        if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
slouken@5297
   296
            return -1;
slouken@5297
   297
        }
slouken@5297
   298
        SDL_CurrentContext = data->context;
slouken@5297
   299
slouken@5297
   300
        GL_UpdateViewport(renderer);
slouken@5297
   301
    }
icculus@7486
   302
icculus@7486
   303
    GL_ClearErrors(renderer);
icculus@7486
   304
slouken@5297
   305
    return 0;
slouken@5297
   306
}
slouken@5297
   307
slouken@5355
   308
/* This is called if we need to invalidate all of the SDL OpenGL state */
slouken@5355
   309
static void
slouken@5355
   310
GL_ResetState(SDL_Renderer *renderer)
slouken@5355
   311
{
slouken@5355
   312
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5355
   313
slouken@8869
   314
    if (SDL_GL_GetCurrentContext() == data->context) {
slouken@5355
   315
        GL_UpdateViewport(renderer);
slouken@5355
   316
    } else {
slouken@5355
   317
        GL_ActivateRenderer(renderer);
slouken@5355
   318
    }
slouken@5355
   319
slouken@5355
   320
    data->current.shader = SHADER_NONE;
slouken@5355
   321
    data->current.color = 0;
slouken@5355
   322
    data->current.blendMode = -1;
slouken@5355
   323
slouken@5355
   324
    data->glDisable(GL_DEPTH_TEST);
slouken@5355
   325
    data->glDisable(GL_CULL_FACE);
slouken@5355
   326
    /* This ended up causing video discrepancies between OpenGL and Direct3D */
gabomdq@7678
   327
    /* data->glEnable(GL_LINE_SMOOTH); */
slouken@5355
   328
slouken@5355
   329
    data->glMatrixMode(GL_MODELVIEW);
slouken@5355
   330
    data->glLoadIdentity();
slouken@6494
   331
slouken@6494
   332
    GL_CheckError("", renderer);
slouken@5355
   333
}
slouken@5355
   334
slouken@7197
   335
static void APIENTRY
jorgen@8811
   336
GL_HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
slouken@7194
   337
{
slouken@7194
   338
    SDL_Renderer *renderer = (SDL_Renderer *) userParam;
slouken@7194
   339
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@6232
   340
slouken@7194
   341
    if (type == GL_DEBUG_TYPE_ERROR_ARB) {
slouken@7194
   342
        /* Record this error */
slouken@7194
   343
        ++data->errors;
slouken@7194
   344
        data->error_messages = SDL_realloc(data->error_messages, data->errors * sizeof(*data->error_messages));
slouken@7194
   345
        if (data->error_messages) {
slouken@7194
   346
            data->error_messages[data->errors-1] = SDL_strdup(message);
slouken@7194
   347
        }
slouken@7194
   348
    }
slouken@7194
   349
slouken@7194
   350
    /* If there's another error callback, pass it along, otherwise log it */
slouken@7194
   351
    if (data->next_error_callback) {
slouken@7194
   352
        data->next_error_callback(source, type, id, severity, length, message, data->next_error_userparam);
slouken@7194
   353
    } else {
slouken@7194
   354
        if (type == GL_DEBUG_TYPE_ERROR_ARB) {
slouken@7194
   355
            SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", message);
slouken@7194
   356
        } else {
slouken@7194
   357
            SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "%s", message);
slouken@7194
   358
        }
slouken@7194
   359
    }
slouken@7194
   360
}
slouken@7194
   361
slouken@7194
   362
static GL_FBOList *
slouken@6232
   363
GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
slouken@6232
   364
{
slouken@6232
   365
    GL_FBOList *result = data->framebuffers;
slouken@6232
   366
slouken@6232
   367
    while (result && ((result->w != w) || (result->h != h))) {
slouken@6232
   368
        result = result->next;
slouken@6232
   369
    }
slouken@6232
   370
slouken@6232
   371
    if (!result) {
slouken@6232
   372
        result = SDL_malloc(sizeof(GL_FBOList));
slouken@6232
   373
        if (result) {
slouken@6232
   374
            result->w = w;
slouken@6232
   375
            result->h = h;
slouken@6232
   376
            data->glGenFramebuffersEXT(1, &result->FBO);
slouken@6232
   377
            result->next = data->framebuffers;
slouken@6232
   378
            data->framebuffers = result;
slouken@6232
   379
        }
slouken@6232
   380
    }
slouken@6232
   381
    return result;
slouken@6232
   382
}
slouken@6232
   383
slouken@1918
   384
SDL_Renderer *
slouken@1918
   385
GL_CreateRenderer(SDL_Window * window, Uint32 flags)
slouken@1918
   386
{
slouken@1918
   387
    SDL_Renderer *renderer;
slouken@1918
   388
    GL_RenderData *data;
slouken@5233
   389
    const char *hint;
slouken@1952
   390
    GLint value;
slouken@5154
   391
    Uint32 window_flags;
gabomdq@8257
   392
    int profile_mask, major, minor;
slouken@8906
   393
    SDL_bool changed_window = SDL_FALSE;
gabomdq@8257
   394
gabomdq@8257
   395
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
gabomdq@8257
   396
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
gabomdq@8257
   397
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
gabomdq@8257
   398
    
slouken@5154
   399
    window_flags = SDL_GetWindowFlags(window);
gabomdq@8257
   400
    if (!(window_flags & SDL_WINDOW_OPENGL) ||
gabomdq@8264
   401
        profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
slouken@8906
   402
slouken@8906
   403
        changed_window = SDL_TRUE;
gabomdq@8264
   404
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
gabomdq@8264
   405
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
gabomdq@8264
   406
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
gabomdq@8264
   407
slouken@5154
   408
        if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
slouken@8906
   409
            goto error;
slouken@1924
   410
        }
slouken@1918
   411
    }
slouken@1918
   412
slouken@1920
   413
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
slouken@1918
   414
    if (!renderer) {
slouken@1918
   415
        SDL_OutOfMemory();
slouken@8906
   416
        goto error;
slouken@1918
   417
    }
slouken@1918
   418
slouken@1920
   419
    data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
slouken@1918
   420
    if (!data) {
slouken@1918
   421
        GL_DestroyRenderer(renderer);
slouken@1918
   422
        SDL_OutOfMemory();
slouken@8906
   423
        goto error;
slouken@1918
   424
    }
slouken@1918
   425
slouken@5147
   426
    renderer->WindowEvent = GL_WindowEvent;
urkle@7746
   427
    renderer->GetOutputSize = GL_GetOutputSize;
slouken@1918
   428
    renderer->CreateTexture = GL_CreateTexture;
slouken@1918
   429
    renderer->UpdateTexture = GL_UpdateTexture;
slouken@7759
   430
    renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
slouken@1918
   431
    renderer->LockTexture = GL_LockTexture;
slouken@1918
   432
    renderer->UnlockTexture = GL_UnlockTexture;
slouken@6247
   433
    renderer->SetRenderTarget = GL_SetRenderTarget;
slouken@5297
   434
    renderer->UpdateViewport = GL_UpdateViewport;
slouken@7141
   435
    renderer->UpdateClipRect = GL_UpdateClipRect;
slouken@3596
   436
    renderer->RenderClear = GL_RenderClear;
slouken@3596
   437
    renderer->RenderDrawPoints = GL_RenderDrawPoints;
slouken@3596
   438
    renderer->RenderDrawLines = GL_RenderDrawLines;
slouken@3596
   439
    renderer->RenderFillRects = GL_RenderFillRects;
slouken@1918
   440
    renderer->RenderCopy = GL_RenderCopy;
gabomdq@6320
   441
    renderer->RenderCopyEx = GL_RenderCopyEx;
slouken@3431
   442
    renderer->RenderReadPixels = GL_RenderReadPixels;
slouken@1918
   443
    renderer->RenderPresent = GL_RenderPresent;
slouken@1918
   444
    renderer->DestroyTexture = GL_DestroyTexture;
slouken@1918
   445
    renderer->DestroyRenderer = GL_DestroyRenderer;
gabomdq@6414
   446
    renderer->GL_BindTexture = GL_BindTexture;
gabomdq@6414
   447
    renderer->GL_UnbindTexture = GL_UnbindTexture;
slouken@1918
   448
    renderer->info = GL_RenderDriver.info;
slouken@8590
   449
    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
slouken@1918
   450
    renderer->driverdata = data;
slouken@6171
   451
    renderer->window = window;
slouken@1918
   452
slouken@3685
   453
    data->context = SDL_GL_CreateContext(window);
slouken@1918
   454
    if (!data->context) {
slouken@1918
   455
        GL_DestroyRenderer(renderer);
slouken@8906
   456
        goto error;
slouken@1918
   457
    }
slouken@3685
   458
    if (SDL_GL_MakeCurrent(window, data->context) < 0) {
slouken@1918
   459
        GL_DestroyRenderer(renderer);
slouken@8906
   460
        goto error;
slouken@1918
   461
    }
slouken@5204
   462
slouken@5204
   463
    if (GL_LoadFunctions(data) < 0) {
slouken@5204
   464
        GL_DestroyRenderer(renderer);
slouken@8906
   465
        goto error;
slouken@5204
   466
    }
slouken@5204
   467
slouken@2246
   468
#ifdef __MACOSX__
slouken@2246
   469
    /* Enable multi-threaded rendering */
slouken@2246
   470
    /* Disabled until Ryan finishes his VBO/PBO code...
bob@2295
   471
       CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
bob@2295
   472
     */
slouken@2246
   473
#endif
slouken@2246
   474
slouken@1965
   475
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
slouken@1918
   476
        SDL_GL_SetSwapInterval(1);
slouken@1918
   477
    } else {
slouken@1918
   478
        SDL_GL_SetSwapInterval(0);
slouken@1918
   479
    }
slouken@1918
   480
    if (SDL_GL_GetSwapInterval() > 0) {
slouken@1965
   481
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@1918
   482
    }
slouken@1918
   483
slouken@7194
   484
    /* Check for debug output support */
slouken@7198
   485
    if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
slouken@7198
   486
        (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
slouken@7198
   487
        data->debug_enabled = SDL_TRUE;
slouken@7198
   488
    }
slouken@7198
   489
    if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
slouken@7194
   490
        PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
slouken@7194
   491
slouken@7194
   492
        data->GL_ARB_debug_output_supported = SDL_TRUE;
slouken@7194
   493
        data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)&data->next_error_callback);
slouken@7194
   494
        data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
slouken@7194
   495
        glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
slouken@7198
   496
slouken@7198
   497
        /* Make sure our callback is called when errors actually happen */
slouken@7198
   498
        data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
slouken@7194
   499
    }
slouken@7194
   500
slouken@1926
   501
    if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
slouken@1926
   502
        || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
slouken@1926
   503
        data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
slouken@6449
   504
        data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
slouken@6449
   505
        renderer->info.max_texture_width = value;
slouken@6449
   506
        renderer->info.max_texture_height = value;
slouken@6449
   507
    } else {
slouken@6449
   508
        data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
slouken@6449
   509
        renderer->info.max_texture_width = value;
slouken@6449
   510
        renderer->info.max_texture_height = value;
slouken@1926
   511
    }
slouken@1920
   512
slouken@5228
   513
    /* Check for multitexture support */
slouken@5228
   514
    if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
slouken@5228
   515
        data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
slouken@5228
   516
        if (data->glActiveTextureARB) {
slouken@5228
   517
            data->GL_ARB_multitexture_supported = SDL_TRUE;
slouken@5228
   518
            data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
slouken@5228
   519
        }
slouken@5228
   520
    }
slouken@5228
   521
slouken@5228
   522
    /* Check for shader support */
slouken@5233
   523
    hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);
slouken@5233
   524
    if (!hint || *hint != '0') {
slouken@5233
   525
        data->shaders = GL_CreateShaderContext();
slouken@5233
   526
    }
slouken@5233
   527
    SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
slouken@5233
   528
                data->shaders ? "ENABLED" : "DISABLED");
slouken@5228
   529
slouken@5228
   530
    /* We support YV12 textures using 3 textures and a shader */
slouken@5228
   531
    if (data->shaders && data->num_texture_units >= 3) {
slouken@5228
   532
        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
slouken@5264
   533
        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
slouken@5228
   534
    }
slouken@7191
   535
slouken@7814
   536
#ifdef __MACOSX__
slouken@7814
   537
    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
slouken@7814
   538
#endif
slouken@7814
   539
slouken@6232
   540
    if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
slouken@6232
   541
        data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
slouken@6232
   542
        data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
slouken@6232
   543
            SDL_GL_GetProcAddress("glGenFramebuffersEXT");
slouken@6232
   544
        data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
slouken@6232
   545
            SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
slouken@6232
   546
        data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
slouken@6232
   547
            SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
slouken@6232
   548
        data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
slouken@6232
   549
            SDL_GL_GetProcAddress("glBindFramebufferEXT");
slouken@6246
   550
        data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
slouken@6232
   551
            SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
slouken@6246
   552
        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
slouken@6232
   553
    }
slouken@6232
   554
    data->framebuffers = NULL;
slouken@5228
   555
slouken@1918
   556
    /* Set up parameters for rendering */
slouken@5355
   557
    GL_ResetState(renderer);
slouken@1918
   558
slouken@1918
   559
    return renderer;
slouken@8906
   560
slouken@8906
   561
error:
slouken@8906
   562
    if (changed_window) {
slouken@8906
   563
        /* Uh oh, better try to put it back... */
slouken@8906
   564
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
slouken@8906
   565
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
slouken@8906
   566
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
slouken@8906
   567
        SDL_RecreateWindow(window, window_flags);
slouken@8906
   568
    }
slouken@8906
   569
    return NULL;
slouken@1918
   570
}
slouken@1918
   571
slouken@5147
   572
static void
slouken@5147
   573
GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
slouken@1970
   574
{
slouken@6260
   575
    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
slouken@6260
   576
        event->event == SDL_WINDOWEVENT_SHOWN ||
slouken@6260
   577
        event->event == SDL_WINDOWEVENT_HIDDEN) {
slouken@5147
   578
        /* Rebind the context to the window area and update matrices */
slouken@5147
   579
        SDL_CurrentContext = NULL;
slouken@5147
   580
    }
slouken@1923
   581
}
slouken@1923
   582
urkle@7746
   583
static int
urkle@7746
   584
GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
urkle@7746
   585
{
urkle@7746
   586
    SDL_GL_GetDrawableSize(renderer->window, w, h);
urkle@7746
   587
urkle@7746
   588
    return 0;
urkle@7746
   589
}
urkle@7746
   590
slouken@7194
   591
SDL_FORCE_INLINE int
slouken@1922
   592
power_of_2(int input)
slouken@1922
   593
{
slouken@1922
   594
    int value = 1;
slouken@1922
   595
slouken@1922
   596
    while (value < input) {
slouken@1922
   597
        value <<= 1;
slouken@1922
   598
    }
slouken@1922
   599
    return value;
slouken@1922
   600
}
slouken@1922
   601
slouken@7194
   602
SDL_FORCE_INLINE SDL_bool
slouken@3433
   603
convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
slouken@3433
   604
               GLint* internalFormat, GLenum* format, GLenum* type)
slouken@3433
   605
{
slouken@3433
   606
    switch (pixel_format) {
slouken@3433
   607
    case SDL_PIXELFORMAT_ARGB8888:
slouken@5156
   608
        *internalFormat = GL_RGBA8;
slouken@3433
   609
        *format = GL_BGRA;
slouken@3433
   610
        *type = GL_UNSIGNED_INT_8_8_8_8_REV;
slouken@3433
   611
        break;
slouken@5264
   612
    case SDL_PIXELFORMAT_YV12:
slouken@5264
   613
    case SDL_PIXELFORMAT_IYUV:
slouken@5264
   614
        *internalFormat = GL_LUMINANCE;
slouken@5264
   615
        *format = GL_LUMINANCE;
slouken@5264
   616
        *type = GL_UNSIGNED_BYTE;
slouken@5264
   617
        break;
slouken@7814
   618
#ifdef __MACOSX__
slouken@7814
   619
    case SDL_PIXELFORMAT_UYVY:
slouken@7814
   620
		*internalFormat = GL_RGB8;
slouken@7814
   621
		*format = GL_YCBCR_422_APPLE;
slouken@7814
   622
		*type = GL_UNSIGNED_SHORT_8_8_APPLE;
slouken@7814
   623
		break;
slouken@7814
   624
#endif
slouken@3433
   625
    default:
slouken@3433
   626
        return SDL_FALSE;
slouken@3433
   627
    }
slouken@3433
   628
    return SDL_TRUE;
slouken@3433
   629
}
icculus@2835
   630
slouken@5484
   631
static GLenum
slouken@5484
   632
GetScaleQuality(void)
slouken@5484
   633
{
slouken@5484
   634
    const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
slouken@5484
   635
slouken@5484
   636
    if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
slouken@5484
   637
        return GL_NEAREST;
slouken@5484
   638
    } else {
slouken@5484
   639
        return GL_LINEAR;
slouken@5484
   640
    }
slouken@5484
   641
}
slouken@5484
   642
slouken@1918
   643
static int
slouken@1918
   644
GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
   645
{
slouken@1918
   646
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
   647
    GL_TextureData *data;
slouken@1920
   648
    GLint internalFormat;
slouken@1920
   649
    GLenum format, type;
slouken@1922
   650
    int texture_w, texture_h;
slouken@5503
   651
    GLenum scaleMode;
slouken@1918
   652
slouken@5147
   653
    GL_ActivateRenderer(renderer);
slouken@5147
   654
slouken@3433
   655
    if (!convert_format(renderdata, texture->format, &internalFormat,
slouken@3433
   656
                        &format, &type)) {
icculus@7037
   657
        return SDL_SetError("Texture format %s not supported by OpenGL",
icculus@7037
   658
                            SDL_GetPixelFormatName(texture->format));
slouken@1920
   659
    }
slouken@1920
   660
slouken@1920
   661
    data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
slouken@1918
   662
    if (!data) {
icculus@7037
   663
        return SDL_OutOfMemory();
slouken@1918
   664
    }
slouken@1918
   665
slouken@2222
   666
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5264
   667
        size_t size;
slouken@5156
   668
        data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
slouken@5264
   669
        size = texture->h * data->pitch;
slouken@5264
   670
        if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@5264
   671
            texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@5264
   672
            /* Need to add size for the U and V planes */
slouken@5264
   673
            size += (2 * (texture->h * data->pitch) / 4);
slouken@5264
   674
        }
slouken@5402
   675
        data->pixels = SDL_calloc(1, size);
slouken@2222
   676
        if (!data->pixels) {
slouken@2222
   677
            SDL_free(data);
icculus@7037
   678
            return SDL_OutOfMemory();
slouken@2222
   679
        }
slouken@2222
   680
    }
slouken@2222
   681
slouken@6232
   682
    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
slouken@6232
   683
        data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
slouken@6232
   684
    } else {
slouken@6232
   685
        data->fbo = NULL;
slouken@6232
   686
    }
slouken@1918
   687
slouken@6494
   688
    GL_CheckError("", renderer);
slouken@1927
   689
    renderdata->glGenTextures(1, &data->texture);
slouken@7624
   690
    if (GL_CheckError("glGenTexures()", renderer) < 0) {
slouken@7624
   691
        SDL_free(data);
slouken@7624
   692
        return -1;
slouken@7624
   693
    }
slouken@7779
   694
    texture->driverdata = data;
slouken@7779
   695
slouken@6232
   696
    if ((renderdata->GL_ARB_texture_rectangle_supported)
gabomdq@7678
   697
        /* && texture->access != SDL_TEXTUREACCESS_TARGET */){
slouken@1926
   698
        data->type = GL_TEXTURE_RECTANGLE_ARB;
slouken@1926
   699
        texture_w = texture->w;
slouken@1926
   700
        texture_h = texture->h;
icculus@2835
   701
        data->texw = (GLfloat) texture_w;
icculus@2835
   702
        data->texh = (GLfloat) texture_h;
slouken@1926
   703
    } else {
slouken@1926
   704
        data->type = GL_TEXTURE_2D;
slouken@1926
   705
        texture_w = power_of_2(texture->w);
slouken@1926
   706
        texture_h = power_of_2(texture->h);
icculus@2835
   707
        data->texw = (GLfloat) (texture->w) / texture_w;
slouken@1926
   708
        data->texh = (GLfloat) texture->h / texture_h;
slouken@1926
   709
    }
icculus@2835
   710
slouken@1920
   711
    data->format = format;
slouken@1920
   712
    data->formattype = type;
slouken@5503
   713
    scaleMode = GetScaleQuality();
slouken@2884
   714
    renderdata->glEnable(data->type);
slouken@1927
   715
    renderdata->glBindTexture(data->type, data->texture);
slouken@5503
   716
    renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
slouken@5503
   717
    renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
slouken@6207
   718
    /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
slouken@6207
   719
       and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
slouken@6207
   720
    */
slouken@6207
   721
    if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
slouken@6207
   722
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
slouken@6207
   723
                                    GL_CLAMP_TO_EDGE);
slouken@6207
   724
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
slouken@6207
   725
                                    GL_CLAMP_TO_EDGE);
slouken@6207
   726
    }
slouken@2840
   727
#ifdef __MACOSX__
slouken@2230
   728
#ifndef GL_TEXTURE_STORAGE_HINT_APPLE
slouken@2230
   729
#define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
slouken@2230
   730
#endif
slouken@2230
   731
#ifndef STORAGE_CACHED_APPLE
slouken@2230
   732
#define STORAGE_CACHED_APPLE                0x85BE
slouken@2230
   733
#endif
slouken@2230
   734
#ifndef STORAGE_SHARED_APPLE
slouken@2230
   735
#define STORAGE_SHARED_APPLE                0x85BF
slouken@2230
   736
#endif
slouken@2230
   737
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@2230
   738
        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
slouken@2230
   739
                                    GL_STORAGE_SHARED_APPLE);
slouken@2230
   740
    } else {
slouken@2230
   741
        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
slouken@2230
   742
                                    GL_STORAGE_CACHED_APPLE);
slouken@2230
   743
    }
bob@2295
   744
    if (texture->access == SDL_TEXTUREACCESS_STREAMING
slouken@5397
   745
        && texture->format == SDL_PIXELFORMAT_ARGB8888
slouken@5397
   746
        && (texture->w % 8) == 0) {
slouken@2230
   747
        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
slouken@5397
   748
        renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@5397
   749
        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
slouken@5397
   750
                          (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
slouken@2230
   751
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
slouken@2230
   752
                                 texture_h, 0, format, type, data->pixels);
slouken@5397
   753
        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
slouken@5156
   754
    }
slouken@5156
   755
    else
slouken@2809
   756
#endif
slouken@2230
   757
    {
slouken@2230
   758
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
slouken@2230
   759
                                 texture_h, 0, format, type, NULL);
slouken@2230
   760
    }
slouken@3041
   761
    renderdata->glDisable(data->type);
slouken@7194
   762
    if (GL_CheckError("glTexImage2D()", renderer) < 0) {
slouken@1924
   763
        return -1;
slouken@1924
   764
    }
slouken@5264
   765
slouken@5264
   766
    if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@5264
   767
        texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@5264
   768
        data->yuv = SDL_TRUE;
slouken@5264
   769
slouken@5264
   770
        renderdata->glGenTextures(1, &data->utexture);
slouken@5264
   771
        renderdata->glGenTextures(1, &data->vtexture);
slouken@5264
   772
        renderdata->glEnable(data->type);
slouken@5264
   773
slouken@5264
   774
        renderdata->glBindTexture(data->type, data->utexture);
slouken@5503
   775
        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
slouken@5503
   776
                                    scaleMode);
slouken@5503
   777
        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
slouken@5503
   778
                                    scaleMode);
slouken@5264
   779
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
slouken@5264
   780
                                    GL_CLAMP_TO_EDGE);
slouken@5264
   781
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
slouken@5264
   782
                                    GL_CLAMP_TO_EDGE);
slouken@5264
   783
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
slouken@5264
   784
                                 texture_h/2, 0, format, type, NULL);
slouken@5264
   785
slouken@5264
   786
        renderdata->glBindTexture(data->type, data->vtexture);
slouken@5503
   787
        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
slouken@5503
   788
                                    scaleMode);
slouken@5503
   789
        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
slouken@5503
   790
                                    scaleMode);
slouken@5264
   791
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
slouken@5264
   792
                                    GL_CLAMP_TO_EDGE);
slouken@5264
   793
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
slouken@5264
   794
                                    GL_CLAMP_TO_EDGE);
slouken@5264
   795
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
slouken@5264
   796
                                 texture_h/2, 0, format, type, NULL);
slouken@5264
   797
slouken@5264
   798
        renderdata->glDisable(data->type);
slouken@5264
   799
    }
slouken@6494
   800
slouken@7194
   801
    return GL_CheckError("", renderer);
slouken@1918
   802
}
slouken@1918
   803
slouken@1918
   804
static int
slouken@1918
   805
GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
   806
                 const SDL_Rect * rect, const void *pixels, int pitch)
slouken@1918
   807
{
slouken@1927
   808
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
   809
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
icculus@8650
   810
    const int texturebpp = SDL_BYTESPERPIXEL(texture->format);
icculus@8650
   811
icculus@8650
   812
    SDL_assert(texturebpp != 0);  /* otherwise, division by zero later. */
slouken@1918
   813
slouken@5147
   814
    GL_ActivateRenderer(renderer);
slouken@5147
   815
slouken@5397
   816
    renderdata->glEnable(data->type);
slouken@5397
   817
    renderdata->glBindTexture(data->type, data->texture);
slouken@5227
   818
    renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
icculus@8650
   819
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / texturebpp));
slouken@1927
   820
    renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
slouken@1927
   821
                                rect->h, data->format, data->formattype,
slouken@1927
   822
                                pixels);
slouken@5264
   823
    if (data->yuv) {
slouken@5265
   824
        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
slouken@5265
   825
slouken@5264
   826
        /* Skip to the correct offset into the next texture */
slouken@6135
   827
        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
slouken@5264
   828
        if (texture->format == SDL_PIXELFORMAT_YV12) {
slouken@5264
   829
            renderdata->glBindTexture(data->type, data->vtexture);
slouken@5264
   830
        } else {
slouken@5264
   831
            renderdata->glBindTexture(data->type, data->utexture);
slouken@5264
   832
        }
slouken@5264
   833
        renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
slouken@5264
   834
                                    rect->w/2, rect->h/2,
slouken@5264
   835
                                    data->format, data->formattype, pixels);
slouken@5264
   836
slouken@5264
   837
        /* Skip to the correct offset into the next texture */
slouken@6135
   838
        pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
slouken@5264
   839
        if (texture->format == SDL_PIXELFORMAT_YV12) {
slouken@5264
   840
            renderdata->glBindTexture(data->type, data->utexture);
slouken@5264
   841
        } else {
slouken@5264
   842
            renderdata->glBindTexture(data->type, data->vtexture);
slouken@5264
   843
        }
slouken@5264
   844
        renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
slouken@5264
   845
                                    rect->w/2, rect->h/2,
slouken@5264
   846
                                    data->format, data->formattype, pixels);
slouken@5264
   847
    }
slouken@3041
   848
    renderdata->glDisable(data->type);
slouken@7779
   849
slouken@7194
   850
    return GL_CheckError("glTexSubImage2D()", renderer);
slouken@1918
   851
}
slouken@1918
   852
slouken@1918
   853
static int
slouken@7759
   854
GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@7759
   855
                    const SDL_Rect * rect,
slouken@7759
   856
                    const Uint8 *Yplane, int Ypitch,
slouken@7759
   857
                    const Uint8 *Uplane, int Upitch,
slouken@7759
   858
                    const Uint8 *Vplane, int Vpitch)
slouken@7759
   859
{
slouken@7759
   860
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@7759
   861
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@7759
   862
slouken@7759
   863
    GL_ActivateRenderer(renderer);
slouken@7759
   864
slouken@7759
   865
    renderdata->glEnable(data->type);
slouken@7759
   866
    renderdata->glBindTexture(data->type, data->texture);
slouken@7759
   867
    renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@7759
   868
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
slouken@7759
   869
    renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
slouken@7759
   870
                                rect->h, data->format, data->formattype,
slouken@7759
   871
                                Yplane);
slouken@7759
   872
slouken@7759
   873
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
slouken@7759
   874
    renderdata->glBindTexture(data->type, data->utexture);
slouken@7759
   875
    renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
slouken@7759
   876
                                rect->w/2, rect->h/2,
slouken@7759
   877
                                data->format, data->formattype, Uplane);
slouken@7759
   878
slouken@7759
   879
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
slouken@7759
   880
    renderdata->glBindTexture(data->type, data->vtexture);
slouken@7759
   881
    renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
slouken@7759
   882
                                rect->w/2, rect->h/2,
slouken@7759
   883
                                data->format, data->formattype, Vplane);
slouken@7759
   884
    renderdata->glDisable(data->type);
slouken@7779
   885
slouken@7759
   886
    return GL_CheckError("glTexSubImage2D()", renderer);
slouken@7759
   887
}
slouken@7759
   888
slouken@7759
   889
static int
slouken@1918
   890
GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   891
               const SDL_Rect * rect, void **pixels, int *pitch)
slouken@1918
   892
{
slouken@1918
   893
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
   894
slouken@5227
   895
    data->locked_rect = *rect;
slouken@7191
   896
    *pixels =
slouken@1920
   897
        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
slouken@5156
   898
                  rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@1920
   899
    *pitch = data->pitch;
slouken@1918
   900
    return 0;
slouken@1918
   901
}
slouken@1918
   902
slouken@1918
   903
static void
slouken@1918
   904
GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
   905
{
slouken@5156
   906
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@5227
   907
    const SDL_Rect *rect;
slouken@5227
   908
    void *pixels;
slouken@1918
   909
slouken@5227
   910
    rect = &data->locked_rect;
slouken@7191
   911
    pixels =
slouken@5227
   912
        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
slouken@5227
   913
                  rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5227
   914
    GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
slouken@1918
   915
}
slouken@1918
   916
slouken@5297
   917
static int
slouken@6247
   918
GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@6246
   919
{
slouken@7191
   920
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@6246
   921
    GL_TextureData *texturedata;
slouken@6246
   922
    GLenum status;
slouken@6246
   923
slouken@6246
   924
    GL_ActivateRenderer(renderer);
slouken@7191
   925
slouken@6246
   926
    if (texture == NULL) {
slouken@6246
   927
        data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
slouken@6246
   928
        return 0;
slouken@6246
   929
    }
slouken@6246
   930
slouken@6246
   931
    texturedata = (GL_TextureData *) texture->driverdata;
slouken@6246
   932
    data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
slouken@6246
   933
    /* TODO: check if texture pixel format allows this operation */
slouken@6246
   934
    data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
slouken@6246
   935
    /* Check FBO status */
slouken@6246
   936
    status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
slouken@6246
   937
    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
icculus@7037
   938
        return SDL_SetError("glFramebufferTexture2DEXT() failed");
slouken@6246
   939
    }
slouken@6246
   940
    return 0;
slouken@6246
   941
}
slouken@6246
   942
slouken@6246
   943
static int
slouken@5297
   944
GL_UpdateViewport(SDL_Renderer * renderer)
slouken@5224
   945
{
slouken@5224
   946
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5224
   947
slouken@5297
   948
    if (SDL_CurrentContext != data->context) {
slouken@5297
   949
        /* We'll update the viewport after we rebind the context */
slouken@5297
   950
        return 0;
slouken@5297
   951
    }
slouken@5224
   952
slouken@7995
   953
    if (renderer->target) {
slouken@7995
   954
        data->glViewport(renderer->viewport.x, renderer->viewport.y,
slouken@7995
   955
                         renderer->viewport.w, renderer->viewport.h);
slouken@7995
   956
    } else {
slouken@7995
   957
        int w, h;
slouken@7995
   958
slouken@7995
   959
        SDL_GetRendererOutputSize(renderer, &w, &h);
slouken@7995
   960
        data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
slouken@7995
   961
                         renderer->viewport.w, renderer->viewport.h);
slouken@7995
   962
    }
slouken@5224
   963
slouken@5297
   964
    data->glMatrixMode(GL_PROJECTION);
slouken@5297
   965
    data->glLoadIdentity();
slouken@7239
   966
    if (renderer->viewport.w && renderer->viewport.h) {
slouken@7995
   967
        if (renderer->target) {
slouken@7239
   968
            data->glOrtho((GLdouble) 0,
slouken@7239
   969
                          (GLdouble) renderer->viewport.w,
slouken@7239
   970
                          (GLdouble) 0,
slouken@7239
   971
                          (GLdouble) renderer->viewport.h,
slouken@7239
   972
                           0.0, 1.0);
slouken@7239
   973
        } else {
slouken@7239
   974
            data->glOrtho((GLdouble) 0,
slouken@7239
   975
                          (GLdouble) renderer->viewport.w,
slouken@7239
   976
                          (GLdouble) renderer->viewport.h,
slouken@7239
   977
                          (GLdouble) 0,
slouken@7239
   978
                           0.0, 1.0);
slouken@7239
   979
        }
slouken@6246
   980
    }
slouken@7194
   981
    return GL_CheckError("", renderer);
slouken@5224
   982
}
slouken@5224
   983
slouken@7141
   984
static int
slouken@7141
   985
GL_UpdateClipRect(SDL_Renderer * renderer)
slouken@7141
   986
{
slouken@7141
   987
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@7141
   988
jorgenpt@8728
   989
    if (renderer->clipping_enabled) {
jorgenpt@8728
   990
        const SDL_Rect *rect = &renderer->clip_rect;
slouken@7141
   991
        data->glEnable(GL_SCISSOR_TEST);
philipp@7171
   992
        data->glScissor(rect->x, renderer->viewport.h - rect->y - rect->h, rect->w, rect->h);
slouken@7141
   993
    } else {
slouken@7141
   994
        data->glDisable(GL_SCISSOR_TEST);
slouken@7141
   995
    }
slouken@7141
   996
    return 0;
slouken@7141
   997
}
slouken@7141
   998
slouken@5224
   999
static void
slouken@5355
  1000
GL_SetShader(GL_RenderData * data, GL_Shader shader)
slouken@5355
  1001
{
slouken@5355
  1002
    if (data->shaders && shader != data->current.shader) {
slouken@5355
  1003
        GL_SelectShader(data->shaders, shader);
slouken@5355
  1004
        data->current.shader = shader;
slouken@5355
  1005
    }
slouken@5355
  1006
}
slouken@5355
  1007
slouken@5355
  1008
static void
slouken@5355
  1009
GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
slouken@5355
  1010
{
slouken@5355
  1011
    Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
slouken@5355
  1012
slouken@5355
  1013
    if (color != data->current.color) {
slouken@5355
  1014
        data->glColor4f((GLfloat) r * inv255f,
slouken@5355
  1015
                        (GLfloat) g * inv255f,
slouken@5355
  1016
                        (GLfloat) b * inv255f,
slouken@5355
  1017
                        (GLfloat) a * inv255f);
slouken@5355
  1018
        data->current.color = color;
slouken@5355
  1019
    }
slouken@5355
  1020
}
slouken@5355
  1021
slouken@5355
  1022
static void
slouken@5140
  1023
GL_SetBlendMode(GL_RenderData * data, int blendMode)
slouken@2936
  1024
{
slouken@5355
  1025
    if (blendMode != data->current.blendMode) {
slouken@2936
  1026
        switch (blendMode) {
slouken@2936
  1027
        case SDL_BLENDMODE_NONE:
slouken@2936
  1028
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
slouken@2936
  1029
            data->glDisable(GL_BLEND);
slouken@2936
  1030
            break;
slouken@2936
  1031
        case SDL_BLENDMODE_BLEND:
slouken@2936
  1032
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@2936
  1033
            data->glEnable(GL_BLEND);
slouken@7502
  1034
            data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
slouken@2936
  1035
            break;
slouken@2936
  1036
        case SDL_BLENDMODE_ADD:
slouken@2936
  1037
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@2936
  1038
            data->glEnable(GL_BLEND);
slouken@7502
  1039
            data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
slouken@2936
  1040
            break;
slouken@5184
  1041
        case SDL_BLENDMODE_MOD:
slouken@5184
  1042
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@5184
  1043
            data->glEnable(GL_BLEND);
slouken@7502
  1044
            data->glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE);
slouken@5184
  1045
            break;
slouken@2936
  1046
        }
slouken@5355
  1047
        data->current.blendMode = blendMode;
slouken@2936
  1048
    }
slouken@2936
  1049
}
slouken@2936
  1050
slouken@5355
  1051
static void
slouken@5355
  1052
GL_SetDrawingState(SDL_Renderer * renderer)
slouken@5355
  1053
{
slouken@5355
  1054
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5355
  1055
slouken@5355
  1056
    GL_ActivateRenderer(renderer);
slouken@5355
  1057
slouken@5381
  1058
    GL_SetColor(data, renderer->r,
slouken@5381
  1059
                      renderer->g,
slouken@5381
  1060
                      renderer->b,
slouken@5381
  1061
                      renderer->a);
slouken@5355
  1062
slouken@5355
  1063
    GL_SetBlendMode(data, renderer->blendMode);
slouken@5355
  1064
slouken@5355
  1065
    GL_SetShader(data, SHADER_SOLID);
slouken@5355
  1066
}
slouken@5355
  1067
slouken@1918
  1068
static int
slouken@3596
  1069
GL_RenderClear(SDL_Renderer * renderer)
slouken@3596
  1070
{
slouken@3596
  1071
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3596
  1072
slouken@5147
  1073
    GL_ActivateRenderer(renderer);
slouken@5147
  1074
slouken@3596
  1075
    data->glClearColor((GLfloat) renderer->r * inv255f,
slouken@3596
  1076
                       (GLfloat) renderer->g * inv255f,
slouken@3596
  1077
                       (GLfloat) renderer->b * inv255f,
slouken@3596
  1078
                       (GLfloat) renderer->a * inv255f);
slouken@3596
  1079
slouken@3596
  1080
    data->glClear(GL_COLOR_BUFFER_BIT);
slouken@3596
  1081
slouken@3596
  1082
    return 0;
slouken@3596
  1083
}
slouken@3596
  1084
slouken@3596
  1085
static int
slouken@6528
  1086
GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
slouken@3596
  1087
                    int count)
slouken@2884
  1088
{
slouken@2884
  1089
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@7908
  1090
    int i;
slouken@2884
  1091
slouken@5355
  1092
    GL_SetDrawingState(renderer);
slouken@2884
  1093
slouken@7908
  1094
    data->glBegin(GL_POINTS);
slouken@7908
  1095
    for (i = 0; i < count; ++i) {
slouken@7908
  1096
        data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
slouken@7908
  1097
    }
slouken@7908
  1098
    data->glEnd();
slouken@2901
  1099
slouken@2901
  1100
    return 0;
slouken@2901
  1101
}
slouken@2901
  1102
slouken@2901
  1103
static int
slouken@6528
  1104
GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
slouken@3596
  1105
                   int count)
slouken@2901
  1106
{
slouken@2901
  1107
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@7908
  1108
    int i;
slouken@2901
  1109
slouken@5355
  1110
    GL_SetDrawingState(renderer);
slouken@2901
  1111
slouken@7191
  1112
    if (count > 2 &&
slouken@3536
  1113
        points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
slouken@7908
  1114
        data->glBegin(GL_LINE_LOOP);
slouken@3536
  1115
        /* GL_LINE_LOOP takes care of the final segment */
slouken@7908
  1116
        --count;
slouken@7908
  1117
        for (i = 0; i < count; ++i) {
slouken@7908
  1118
            data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
slouken@7908
  1119
        }
slouken@7908
  1120
        data->glEnd();
slouken@3536
  1121
    } else {
slouken@7908
  1122
#if defined(__MACOSX__) || defined(__WIN32__)
slouken@7908
  1123
#else
slouken@7908
  1124
        int x1, y1, x2, y2;
slouken@7908
  1125
#endif
slouken@7908
  1126
slouken@7908
  1127
        data->glBegin(GL_LINE_STRIP);
slouken@7908
  1128
        for (i = 0; i < count; ++i) {
slouken@7908
  1129
            data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
slouken@7908
  1130
        }
slouken@7908
  1131
        data->glEnd();
slouken@7908
  1132
slouken@7908
  1133
        /* The line is half open, so we need one more point to complete it.
slouken@7908
  1134
         * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
slouken@7908
  1135
         * If we have to, we can use vertical line and horizontal line textures
slouken@7908
  1136
         * for vertical and horizontal lines, and then create custom textures
slouken@7908
  1137
         * for diagonal lines and software render those.  It's terrible, but at
slouken@7908
  1138
         * least it would be pixel perfect.
slouken@7908
  1139
         */
slouken@7908
  1140
        data->glBegin(GL_POINTS);
slouken@7908
  1141
#if defined(__MACOSX__) || defined(__WIN32__)
slouken@7908
  1142
        /* Mac OS X and Windows seem to always leave the last point open */
slouken@7908
  1143
        data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
slouken@7908
  1144
#else
slouken@7908
  1145
        /* Linux seems to leave the right-most or bottom-most point open */
slouken@7908
  1146
        x1 = points[0].x;
slouken@7908
  1147
        y1 = points[0].y;
slouken@7908
  1148
        x2 = points[count-1].x;
slouken@7908
  1149
        y2 = points[count-1].y;
slouken@7908
  1150
slouken@7908
  1151
        if (x1 > x2) {
slouken@7908
  1152
            data->glVertex2f(0.5f + x1, 0.5f + y1);
slouken@7908
  1153
        } else if (x2 > x1) {
slouken@7908
  1154
            data->glVertex2f(0.5f + x2, 0.5f + y2);
slouken@7908
  1155
        }
slouken@7908
  1156
        if (y1 > y2) {
slouken@7908
  1157
            data->glVertex2f(0.5f + x1, 0.5f + y1);
slouken@7908
  1158
        } else if (y2 > y1) {
slouken@7908
  1159
            data->glVertex2f(0.5f + x2, 0.5f + y2);
slouken@7908
  1160
        }
slouken@7908
  1161
#endif
slouken@7908
  1162
        data->glEnd();
slouken@7840
  1163
    }
slouken@7194
  1164
    return GL_CheckError("", renderer);
slouken@1918
  1165
}
slouken@1918
  1166
slouken@1918
  1167
static int
slouken@6528
  1168
GL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
slouken@2925
  1169
{
slouken@2925
  1170
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3536
  1171
    int i;
slouken@2925
  1172
slouken@5355
  1173
    GL_SetDrawingState(renderer);
slouken@2936
  1174
slouken@3536
  1175
    for (i = 0; i < count; ++i) {
slouken@6528
  1176
        const SDL_FRect *rect = &rects[i];
slouken@3536
  1177
slouken@6528
  1178
        data->glRectf(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
slouken@3536
  1179
    }
slouken@7194
  1180
    return GL_CheckError("", renderer);
slouken@2925
  1181
}
slouken@2925
  1182
slouken@2925
  1183
static int
slouken@1918
  1184
GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
  1185
              const SDL_Rect * srcrect, const SDL_FRect * dstrect)
slouken@1918
  1186
{
slouken@1918
  1187
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1188
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
slouken@6528
  1189
    GLfloat minx, miny, maxx, maxy;
slouken@1918
  1190
    GLfloat minu, maxu, minv, maxv;
slouken@1918
  1191
slouken@5147
  1192
    GL_ActivateRenderer(renderer);
slouken@5147
  1193
slouken@5355
  1194
    data->glEnable(texturedata->type);
slouken@5355
  1195
    if (texturedata->yuv) {
slouken@5355
  1196
        data->glActiveTextureARB(GL_TEXTURE2_ARB);
slouken@5355
  1197
        data->glBindTexture(texturedata->type, texturedata->vtexture);
slouken@5355
  1198
slouken@5355
  1199
        data->glActiveTextureARB(GL_TEXTURE1_ARB);
slouken@5355
  1200
        data->glBindTexture(texturedata->type, texturedata->utexture);
slouken@5355
  1201
slouken@5355
  1202
        data->glActiveTextureARB(GL_TEXTURE0_ARB);
slouken@5355
  1203
    }
slouken@5355
  1204
    data->glBindTexture(texturedata->type, texturedata->texture);
slouken@5355
  1205
slouken@5355
  1206
    if (texture->modMode) {
slouken@5355
  1207
        GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
slouken@5355
  1208
    } else {
slouken@5355
  1209
        GL_SetColor(data, 255, 255, 255, 255);
slouken@5355
  1210
    }
slouken@5355
  1211
slouken@5355
  1212
    GL_SetBlendMode(data, texture->blendMode);
slouken@5355
  1213
slouken@5355
  1214
    if (texturedata->yuv) {
slouken@5355
  1215
        GL_SetShader(data, SHADER_YV12);
slouken@5355
  1216
    } else {
slouken@5355
  1217
        GL_SetShader(data, SHADER_RGB);
slouken@5355
  1218
    }
slouken@5355
  1219
slouken@1918
  1220
    minx = dstrect->x;
slouken@1918
  1221
    miny = dstrect->y;
slouken@1918
  1222
    maxx = dstrect->x + dstrect->w;
slouken@1918
  1223
    maxy = dstrect->y + dstrect->h;
slouken@1918
  1224
slouken@1918
  1225
    minu = (GLfloat) srcrect->x / texture->w;
slouken@1920
  1226
    minu *= texturedata->texw;
slouken@1918
  1227
    maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
slouken@1920
  1228
    maxu *= texturedata->texw;
slouken@1918
  1229
    minv = (GLfloat) srcrect->y / texture->h;
slouken@1920
  1230
    minv *= texturedata->texh;
slouken@1918
  1231
    maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
slouken@1920
  1232
    maxv *= texturedata->texh;
slouken@1918
  1233
slouken@1927
  1234
    data->glBegin(GL_TRIANGLE_STRIP);
slouken@1927
  1235
    data->glTexCoord2f(minu, minv);
slouken@6528
  1236
    data->glVertex2f(minx, miny);
slouken@1927
  1237
    data->glTexCoord2f(maxu, minv);
slouken@6528
  1238
    data->glVertex2f(maxx, miny);
slouken@1927
  1239
    data->glTexCoord2f(minu, maxv);
slouken@6528
  1240
    data->glVertex2f(minx, maxy);
slouken@1927
  1241
    data->glTexCoord2f(maxu, maxv);
slouken@6528
  1242
    data->glVertex2f(maxx, maxy);
slouken@1927
  1243
    data->glEnd();
slouken@1918
  1244
slouken@2884
  1245
    data->glDisable(texturedata->type);
slouken@2884
  1246
slouken@7194
  1247
    return GL_CheckError("", renderer);
slouken@1918
  1248
}
slouken@1918
  1249
slouken@3431
  1250
static int
gabomdq@6320
  1251
GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
  1252
              const SDL_Rect * srcrect, const SDL_FRect * dstrect,
slouken@6528
  1253
              const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
gabomdq@6320
  1254
{
gabomdq@6320
  1255
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
gabomdq@6320
  1256
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
gabomdq@6320
  1257
    GLfloat minx, miny, maxx, maxy;
gabomdq@6320
  1258
    GLfloat centerx, centery;
gabomdq@6320
  1259
    GLfloat minu, maxu, minv, maxv;
slouken@7194
  1260
gabomdq@6320
  1261
    GL_ActivateRenderer(renderer);
gabomdq@6320
  1262
gabomdq@6320
  1263
    data->glEnable(texturedata->type);
gabomdq@6320
  1264
    if (texturedata->yuv) {
gabomdq@6320
  1265
        data->glActiveTextureARB(GL_TEXTURE2_ARB);
gabomdq@6320
  1266
        data->glBindTexture(texturedata->type, texturedata->vtexture);
gabomdq@6320
  1267
gabomdq@6320
  1268
        data->glActiveTextureARB(GL_TEXTURE1_ARB);
gabomdq@6320
  1269
        data->glBindTexture(texturedata->type, texturedata->utexture);
gabomdq@6320
  1270
gabomdq@6320
  1271
        data->glActiveTextureARB(GL_TEXTURE0_ARB);
gabomdq@6320
  1272
    }
gabomdq@6320
  1273
    data->glBindTexture(texturedata->type, texturedata->texture);
gabomdq@6320
  1274
gabomdq@6320
  1275
    if (texture->modMode) {
gabomdq@6320
  1276
        GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
gabomdq@6320
  1277
    } else {
gabomdq@6320
  1278
        GL_SetColor(data, 255, 255, 255, 255);
gabomdq@6320
  1279
    }
gabomdq@6320
  1280
gabomdq@6320
  1281
    GL_SetBlendMode(data, texture->blendMode);
gabomdq@6320
  1282
gabomdq@6320
  1283
    if (texturedata->yuv) {
gabomdq@6320
  1284
        GL_SetShader(data, SHADER_YV12);
gabomdq@6320
  1285
    } else {
gabomdq@6320
  1286
        GL_SetShader(data, SHADER_RGB);
gabomdq@6320
  1287
    }
gabomdq@6320
  1288
slouken@6528
  1289
    centerx = center->x;
slouken@6528
  1290
    centery = center->y;
gabomdq@6320
  1291
slouken@7989
  1292
    if (flip & SDL_FLIP_HORIZONTAL) {
slouken@7989
  1293
        minx =  dstrect->w - centerx;
slouken@7989
  1294
        maxx = -centerx;
slouken@7989
  1295
    }
slouken@7989
  1296
    else {
slouken@7989
  1297
        minx = -centerx;
slouken@7989
  1298
        maxx =  dstrect->w - centerx;
slouken@7989
  1299
    }
slouken@7989
  1300
slouken@7989
  1301
    if (flip & SDL_FLIP_VERTICAL) {
slouken@7989
  1302
        miny =  dstrect->h - centery;
slouken@7976
  1303
        maxy = -centery;
slouken@7989
  1304
    }
slouken@7989
  1305
    else {
slouken@7976
  1306
        miny = -centery;
slouken@7989
  1307
        maxy =  dstrect->h - centery;
gabomdq@6320
  1308
    }
gabomdq@6320
  1309
gabomdq@6320
  1310
    minu = (GLfloat) srcrect->x / texture->w;
gabomdq@6320
  1311
    minu *= texturedata->texw;
gabomdq@6320
  1312
    maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
gabomdq@6320
  1313
    maxu *= texturedata->texw;
gabomdq@6320
  1314
    minv = (GLfloat) srcrect->y / texture->h;
gabomdq@6320
  1315
    minv *= texturedata->texh;
gabomdq@6320
  1316
    maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
gabomdq@6320
  1317
    maxv *= texturedata->texh;
gabomdq@6320
  1318
slouken@7191
  1319
    /* Translate to flip, rotate, translate to position */
gabomdq@6320
  1320
    data->glPushMatrix();
slouken@7191
  1321
    data->glTranslatef((GLfloat)dstrect->x + centerx, (GLfloat)dstrect->y + centery, (GLfloat)0.0);
gabomdq@6320
  1322
    data->glRotated(angle, (GLdouble)0.0, (GLdouble)0.0, (GLdouble)1.0);
slouken@7191
  1323
gabomdq@6320
  1324
    data->glBegin(GL_TRIANGLE_STRIP);
gabomdq@6320
  1325
    data->glTexCoord2f(minu, minv);
gabomdq@6320
  1326
    data->glVertex2f(minx, miny);
gabomdq@6320
  1327
    data->glTexCoord2f(maxu, minv);
gabomdq@6320
  1328
    data->glVertex2f(maxx, miny);
gabomdq@6320
  1329
    data->glTexCoord2f(minu, maxv);
gabomdq@6320
  1330
    data->glVertex2f(minx, maxy);
gabomdq@6320
  1331
    data->glTexCoord2f(maxu, maxv);
gabomdq@6320
  1332
    data->glVertex2f(maxx, maxy);
gabomdq@6320
  1333
    data->glEnd();
gabomdq@6320
  1334
    data->glPopMatrix();
slouken@7191
  1335
gabomdq@6320
  1336
    data->glDisable(texturedata->type);
gabomdq@6320
  1337
slouken@7194
  1338
    return GL_CheckError("", renderer);
gabomdq@6320
  1339
}
gabomdq@6320
  1340
gabomdq@6320
  1341
static int
slouken@3431
  1342
GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
  1343
                    Uint32 pixel_format, void * pixels, int pitch)
slouken@3431
  1344
{
slouken@3433
  1345
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5465
  1346
    Uint32 temp_format = SDL_PIXELFORMAT_ARGB8888;
slouken@5465
  1347
    void *temp_pixels;
slouken@5465
  1348
    int temp_pitch;
slouken@3433
  1349
    GLint internalFormat;
slouken@3433
  1350
    GLenum format, type;
slouken@3435
  1351
    Uint8 *src, *dst, *tmp;
slouken@5154
  1352
    int w, h, length, rows;
slouken@5465
  1353
    int status;
slouken@3433
  1354
slouken@5147
  1355
    GL_ActivateRenderer(renderer);
slouken@5147
  1356
slouken@5465
  1357
    temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@5465
  1358
    temp_pixels = SDL_malloc(rect->h * temp_pitch);
slouken@5465
  1359
    if (!temp_pixels) {
icculus@7037
  1360
        return SDL_OutOfMemory();
slouken@3433
  1361
    }
slouken@3433
  1362
slouken@5465
  1363
    convert_format(data, temp_format, &internalFormat, &format, &type);
slouken@5465
  1364
slouken@7420
  1365
    SDL_GetRendererOutputSize(renderer, &w, &h);
slouken@5154
  1366
slouken@3446
  1367
    data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
slouken@3446
  1368
    data->glPixelStorei(GL_PACK_ROW_LENGTH,
slouken@5465
  1369
                        (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
slouken@3433
  1370
slouken@5154
  1371
    data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
slouken@5465
  1372
                       format, type, temp_pixels);
slouken@3435
  1373
slouken@7779
  1374
    if (GL_CheckError("glReadPixels()", renderer) < 0) {
slouken@7779
  1375
        return -1;
slouken@7779
  1376
    }
slouken@6494
  1377
slouken@3435
  1378
    /* Flip the rows to be top-down */
slouken@5465
  1379
    length = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@5465
  1380
    src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
slouken@5465
  1381
    dst = (Uint8*)temp_pixels;
slouken@3435
  1382
    tmp = SDL_stack_alloc(Uint8, length);
slouken@3435
  1383
    rows = rect->h / 2;
slouken@3435
  1384
    while (rows--) {
slouken@3435
  1385
        SDL_memcpy(tmp, dst, length);
slouken@3435
  1386
        SDL_memcpy(dst, src, length);
slouken@3435
  1387
        SDL_memcpy(src, tmp, length);
slouken@5465
  1388
        dst += temp_pitch;
slouken@5465
  1389
        src -= temp_pitch;
slouken@3435
  1390
    }
slouken@3435
  1391
    SDL_stack_free(tmp);
slouken@3440
  1392
slouken@5465
  1393
    status = SDL_ConvertPixels(rect->w, rect->h,
slouken@5465
  1394
                               temp_format, temp_pixels, temp_pitch,
slouken@5465
  1395
                               pixel_format, pixels, pitch);
slouken@5465
  1396
    SDL_free(temp_pixels);
slouken@5465
  1397
slouken@5465
  1398
    return status;
slouken@3431
  1399
}
slouken@3431
  1400
slouken@1918
  1401
static void
slouken@1918
  1402
GL_RenderPresent(SDL_Renderer * renderer)
slouken@1918
  1403
{
slouken@5147
  1404
    GL_ActivateRenderer(renderer);
slouken@5147
  1405
slouken@1918
  1406
    SDL_GL_SwapWindow(renderer->window);
slouken@1918
  1407
}
slouken@1918
  1408
slouken@1918
  1409
static void
slouken@1918
  1410
GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
  1411
{
slouken@1927
  1412
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1413
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
  1414
slouken@5147
  1415
    GL_ActivateRenderer(renderer);
slouken@5147
  1416
slouken@1918
  1417
    if (!data) {
slouken@1918
  1418
        return;
slouken@1918
  1419
    }
slouken@1918
  1420
    if (data->texture) {
slouken@1927
  1421
        renderdata->glDeleteTextures(1, &data->texture);
slouken@1918
  1422
    }
slouken@5264
  1423
    if (data->yuv) {
slouken@5264
  1424
        renderdata->glDeleteTextures(1, &data->utexture);
slouken@5264
  1425
        renderdata->glDeleteTextures(1, &data->vtexture);
slouken@5264
  1426
    }
slouken@7719
  1427
    SDL_free(data->pixels);
slouken@1918
  1428
    SDL_free(data);
slouken@1918
  1429
    texture->driverdata = NULL;
slouken@1918
  1430
}
slouken@1918
  1431
slouken@1975
  1432
static void
slouken@1918
  1433
GL_DestroyRenderer(SDL_Renderer * renderer)
slouken@1918
  1434
{
slouken@1918
  1435
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1436
slouken@1918
  1437
    if (data) {
slouken@7194
  1438
        GL_ClearErrors(renderer);
slouken@7194
  1439
        if (data->GL_ARB_debug_output_supported) {
slouken@7194
  1440
            PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
slouken@7194
  1441
slouken@7194
  1442
            /* Uh oh, we don't have a safe way of removing ourselves from the callback chain, if it changed after we set our callback. */
slouken@7194
  1443
            /* For now, just always replace the callback with the original one */
slouken@7194
  1444
            glDebugMessageCallbackARBFunc(data->next_error_callback, data->next_error_userparam);
slouken@7194
  1445
        }
icculus@5566
  1446
        if (data->shaders) {
icculus@5566
  1447
            GL_DestroyShaderContext(data->shaders);
icculus@5566
  1448
        }
slouken@1920
  1449
        if (data->context) {
slouken@6232
  1450
            while (data->framebuffers) {
slouken@6232
  1451
                GL_FBOList *nextnode = data->framebuffers->next;
slouken@6232
  1452
                /* delete the framebuffer object */
slouken@6232
  1453
                data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
slouken@6494
  1454
                GL_CheckError("", renderer);
slouken@6232
  1455
                SDL_free(data->framebuffers);
slouken@6232
  1456
                data->framebuffers = nextnode;
jorgen@7091
  1457
            }
slouken@1920
  1458
            SDL_GL_DeleteContext(data->context);
slouken@1918
  1459
        }
slouken@1918
  1460
        SDL_free(data);
slouken@1918
  1461
    }
slouken@1918
  1462
    SDL_free(renderer);
slouken@1918
  1463
}
slouken@1918
  1464
slouken@7194
  1465
static int
slouken@7194
  1466
GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
slouken@7194
  1467
{
gabomdq@6414
  1468
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
gabomdq@6414
  1469
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
gabomdq@6414
  1470
    GL_ActivateRenderer(renderer);
gabomdq@6414
  1471
gabomdq@6414
  1472
    data->glEnable(texturedata->type);
gabomdq@6414
  1473
    if (texturedata->yuv) {
gabomdq@6414
  1474
        data->glActiveTextureARB(GL_TEXTURE2_ARB);
gabomdq@6414
  1475
        data->glBindTexture(texturedata->type, texturedata->vtexture);
gabomdq@6414
  1476
gabomdq@6414
  1477
        data->glActiveTextureARB(GL_TEXTURE1_ARB);
gabomdq@6414
  1478
        data->glBindTexture(texturedata->type, texturedata->utexture);
gabomdq@6414
  1479
gabomdq@6414
  1480
        data->glActiveTextureARB(GL_TEXTURE0_ARB);
gabomdq@6414
  1481
    }
gabomdq@6414
  1482
    data->glBindTexture(texturedata->type, texturedata->texture);
gabomdq@6414
  1483
gabomdq@6414
  1484
    if(texw) *texw = (float)texturedata->texw;
gabomdq@6414
  1485
    if(texh) *texh = (float)texturedata->texh;
gabomdq@6414
  1486
gabomdq@6414
  1487
    return 0;
gabomdq@6414
  1488
}
gabomdq@6414
  1489
slouken@7194
  1490
static int
slouken@7194
  1491
GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
slouken@7194
  1492
{
gabomdq@6414
  1493
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
gabomdq@6414
  1494
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
gabomdq@6414
  1495
    GL_ActivateRenderer(renderer);
gabomdq@6414
  1496
gabomdq@6414
  1497
    if (texturedata->yuv) {
gabomdq@6414
  1498
        data->glActiveTextureARB(GL_TEXTURE2_ARB);
gabomdq@6414
  1499
        data->glDisable(texturedata->type);
gabomdq@6414
  1500
gabomdq@6414
  1501
        data->glActiveTextureARB(GL_TEXTURE1_ARB);
gabomdq@6414
  1502
        data->glDisable(texturedata->type);
gabomdq@6414
  1503
gabomdq@6414
  1504
        data->glActiveTextureARB(GL_TEXTURE0_ARB);
gabomdq@6414
  1505
    }
slouken@7191
  1506
gabomdq@6414
  1507
    data->glDisable(texturedata->type);
gabomdq@6414
  1508
gabomdq@6414
  1509
    return 0;
gabomdq@6414
  1510
}
gabomdq@6414
  1511
slouken@5226
  1512
#endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
slouken@1918
  1513
slouken@1918
  1514
/* vi: set ts=4 sw=4 expandtab: */