src/render/opengl/SDL_render_gl.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 22 Jan 2012 21:46:06 -0500
changeset 6260 fd494c5f305b
parent 6247 b6212690f78d
child 6320 6077a1310907
permissions -rwxr-xr-x
Fixed loading textures when the window starts hidden.
The viewport automatically resets to the window size when you programmatically resize the window.
slouken@1918
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 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
*/
slouken@1918
    21
#include "SDL_config.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"
slouken@1920
    27
#include "SDL_opengl.h"
slouken@5154
    28
#include "../SDL_sysrender.h"
slouken@5228
    29
#include "SDL_shaders_gl.h"
slouken@1918
    30
slouken@2246
    31
#ifdef __MACOSX__
slouken@2246
    32
#include <OpenGL/OpenGL.h>
slouken@2246
    33
#endif
slouken@2246
    34
slouken@2778
    35
slouken@1918
    36
/* OpenGL renderer implementation */
slouken@1918
    37
slouken@2230
    38
/* Details on optimizing the texture path on Mac OS X:
slouken@5203
    39
   http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
slouken@2230
    40
*/
slouken@2230
    41
slouken@5154
    42
/* Used to re-create the window with OpenGL capability */
slouken@5154
    43
extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
icculus@2835
    44
slouken@1985
    45
static const float inv255f = 1.0f / 255.0f;
slouken@1985
    46
slouken@1918
    47
static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
slouken@5147
    48
static void GL_WindowEvent(SDL_Renderer * renderer,
slouken@5147
    49
                           const SDL_WindowEvent *event);
slouken@1918
    50
static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1918
    51
static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
    52
                            const SDL_Rect * rect, const void *pixels,
slouken@1918
    53
                            int pitch);
slouken@1918
    54
static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
    55
                          const SDL_Rect * rect, void **pixels, int *pitch);
slouken@1918
    56
static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@6247
    57
static int GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@5297
    58
static int GL_UpdateViewport(SDL_Renderer * renderer);
slouken@3596
    59
static int GL_RenderClear(SDL_Renderer * renderer);
slouken@3596
    60
static int GL_RenderDrawPoints(SDL_Renderer * renderer,
slouken@3596
    61
                               const SDL_Point * points, int count);
slouken@3596
    62
static int GL_RenderDrawLines(SDL_Renderer * renderer,
slouken@3596
    63
                              const SDL_Point * points, int count);
slouken@3596
    64
static int GL_RenderFillRects(SDL_Renderer * renderer,
slouken@5297
    65
                              const SDL_Rect * rects, int count);
slouken@1918
    66
static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
    67
                         const SDL_Rect * srcrect, const SDL_Rect * dstrect);
slouken@3431
    68
static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
    69
                               Uint32 pixel_format, void * pixels, int pitch);
slouken@1918
    70
static void GL_RenderPresent(SDL_Renderer * renderer);
slouken@1918
    71
static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1918
    72
static void GL_DestroyRenderer(SDL_Renderer * renderer);
slouken@1918
    73
slouken@1918
    74
slouken@1918
    75
SDL_RenderDriver GL_RenderDriver = {
slouken@1918
    76
    GL_CreateRenderer,
slouken@1918
    77
    {
slouken@1918
    78
     "opengl",
slouken@6237
    79
     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
slouken@5156
    80
     1,
slouken@5156
    81
     {SDL_PIXELFORMAT_ARGB8888},
slouken@1918
    82
     0,
slouken@1918
    83
     0}
slouken@1918
    84
};
slouken@1918
    85
slouken@6232
    86
typedef struct GL_FBOList GL_FBOList;
slouken@6232
    87
slouken@6232
    88
struct GL_FBOList
slouken@6232
    89
{
slouken@6232
    90
    Uint32 w, h;
slouken@6232
    91
    GLuint FBO;
slouken@6232
    92
    GL_FBOList *next;
slouken@6232
    93
};
slouken@6232
    94
slouken@1918
    95
typedef struct
slouken@1918
    96
{
slouken@1918
    97
    SDL_GLContext context;
slouken@2233
    98
    SDL_bool GL_ARB_texture_rectangle_supported;
slouken@5355
    99
    struct {
slouken@5355
   100
        GL_Shader shader;
slouken@5355
   101
        Uint32 color;
slouken@5355
   102
        int blendMode;
slouken@5355
   103
    } current;
slouken@6232
   104
    
slouken@6232
   105
    SDL_bool GL_EXT_framebuffer_object_supported;
slouken@6232
   106
    GL_FBOList *framebuffers;
slouken@1927
   107
slouken@1927
   108
    /* OpenGL functions */
slouken@1927
   109
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
slouken@5204
   110
#include "SDL_glfuncs.h"
slouken@1927
   111
#undef SDL_PROC
slouken@1974
   112
slouken@5228
   113
    /* Multitexture support */
slouken@5228
   114
    SDL_bool GL_ARB_multitexture_supported;
slouken@5228
   115
    PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
slouken@5351
   116
    GLint num_texture_units;
slouken@6232
   117
    
slouken@6232
   118
    PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
slouken@6232
   119
    PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
slouken@6232
   120
    PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
slouken@6232
   121
    PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
slouken@6232
   122
    PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
slouken@5228
   123
slouken@5228
   124
    /* Shader support */
slouken@5228
   125
    GL_ShaderContext *shaders;
slouken@5228
   126
slouken@1918
   127
} GL_RenderData;
slouken@1918
   128
slouken@1918
   129
typedef struct
slouken@1918
   130
{
slouken@1918
   131
    GLuint texture;
slouken@1920
   132
    GLenum type;
slouken@1918
   133
    GLfloat texw;
slouken@1918
   134
    GLfloat texh;
slouken@1920
   135
    GLenum format;
slouken@1920
   136
    GLenum formattype;
slouken@1918
   137
    void *pixels;
slouken@1918
   138
    int pitch;
slouken@5227
   139
    SDL_Rect locked_rect;
slouken@5264
   140
slouken@5264
   141
    /* YV12 texture support */
slouken@5264
   142
    SDL_bool yuv;
slouken@5264
   143
    GLuint utexture;
slouken@5264
   144
    GLuint vtexture;
slouken@6232
   145
    
slouken@6232
   146
    GL_FBOList *fbo;
slouken@1918
   147
} GL_TextureData;
slouken@1918
   148
slouken@1918
   149
slouken@1924
   150
static void
slouken@1924
   151
GL_SetError(const char *prefix, GLenum result)
slouken@1924
   152
{
slouken@1924
   153
    const char *error;
slouken@1924
   154
slouken@1924
   155
    switch (result) {
slouken@1924
   156
    case GL_NO_ERROR:
slouken@1924
   157
        error = "GL_NO_ERROR";
slouken@1924
   158
        break;
slouken@1924
   159
    case GL_INVALID_ENUM:
slouken@1924
   160
        error = "GL_INVALID_ENUM";
slouken@1924
   161
        break;
slouken@1924
   162
    case GL_INVALID_VALUE:
slouken@1924
   163
        error = "GL_INVALID_VALUE";
slouken@1924
   164
        break;
slouken@1924
   165
    case GL_INVALID_OPERATION:
slouken@1924
   166
        error = "GL_INVALID_OPERATION";
slouken@1924
   167
        break;
slouken@1924
   168
    case GL_STACK_OVERFLOW:
slouken@1924
   169
        error = "GL_STACK_OVERFLOW";
slouken@1924
   170
        break;
slouken@1924
   171
    case GL_STACK_UNDERFLOW:
slouken@1924
   172
        error = "GL_STACK_UNDERFLOW";
slouken@1924
   173
        break;
slouken@1924
   174
    case GL_OUT_OF_MEMORY:
slouken@1924
   175
        error = "GL_OUT_OF_MEMORY";
slouken@1924
   176
        break;
slouken@1924
   177
    case GL_TABLE_TOO_LARGE:
slouken@1924
   178
        error = "GL_TABLE_TOO_LARGE";
slouken@1924
   179
        break;
slouken@1924
   180
    default:
slouken@1924
   181
        error = "UNKNOWN";
slouken@1924
   182
        break;
slouken@1924
   183
    }
slouken@1924
   184
    SDL_SetError("%s: %s", prefix, error);
slouken@1924
   185
}
slouken@1924
   186
slouken@1927
   187
static int
slouken@1927
   188
GL_LoadFunctions(GL_RenderData * data)
slouken@1927
   189
{
slouken@1927
   190
#ifdef __SDL_NOGETPROCADDR__
slouken@1927
   191
#define SDL_PROC(ret,func,params) data->func=func;
slouken@1927
   192
#else
slouken@1927
   193
#define SDL_PROC(ret,func,params) \
slouken@1927
   194
    do { \
slouken@1927
   195
        data->func = SDL_GL_GetProcAddress(#func); \
slouken@1927
   196
        if ( ! data->func ) { \
slouken@1927
   197
            SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
slouken@1927
   198
            return -1; \
slouken@1927
   199
        } \
slouken@1927
   200
    } while ( 0 );
slouken@1927
   201
#endif /* __SDL_NOGETPROCADDR__ */
slouken@1927
   202
slouken@5204
   203
#include "SDL_glfuncs.h"
slouken@1927
   204
#undef SDL_PROC
slouken@1927
   205
    return 0;
slouken@1927
   206
}
slouken@1927
   207
slouken@5297
   208
static SDL_GLContext SDL_CurrentContext = NULL;
slouken@5297
   209
slouken@5297
   210
static int
slouken@5297
   211
GL_ActivateRenderer(SDL_Renderer * renderer)
slouken@5297
   212
{
slouken@5297
   213
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5297
   214
slouken@5297
   215
    if (SDL_CurrentContext != data->context) {
slouken@5297
   216
        if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
slouken@5297
   217
            return -1;
slouken@5297
   218
        }
slouken@5297
   219
        SDL_CurrentContext = data->context;
slouken@5297
   220
slouken@5297
   221
        GL_UpdateViewport(renderer);
slouken@5297
   222
    }
slouken@5297
   223
    return 0;
slouken@5297
   224
}
slouken@5297
   225
slouken@5355
   226
/* This is called if we need to invalidate all of the SDL OpenGL state */
slouken@5355
   227
static void
slouken@5355
   228
GL_ResetState(SDL_Renderer *renderer)
slouken@5355
   229
{
slouken@5355
   230
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5355
   231
slouken@5355
   232
    if (SDL_CurrentContext == data->context) {
slouken@5355
   233
        GL_UpdateViewport(renderer);
slouken@5355
   234
    } else {
slouken@5355
   235
        GL_ActivateRenderer(renderer);
slouken@5355
   236
    }
slouken@5355
   237
slouken@5355
   238
    data->current.shader = SHADER_NONE;
slouken@5355
   239
    data->current.color = 0;
slouken@5355
   240
    data->current.blendMode = -1;
slouken@5355
   241
slouken@5355
   242
    data->glDisable(GL_DEPTH_TEST);
slouken@5355
   243
    data->glDisable(GL_CULL_FACE);
slouken@5355
   244
    /* This ended up causing video discrepancies between OpenGL and Direct3D */
slouken@5355
   245
    /*data->glEnable(GL_LINE_SMOOTH);*/
slouken@5355
   246
slouken@5355
   247
    data->glMatrixMode(GL_MODELVIEW);
slouken@5355
   248
    data->glLoadIdentity();
slouken@5355
   249
}
slouken@5355
   250
slouken@6232
   251
slouken@6232
   252
GL_FBOList *
slouken@6232
   253
GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
slouken@6232
   254
{
slouken@6232
   255
    GL_FBOList *result = data->framebuffers;
slouken@6232
   256
slouken@6232
   257
    while (result && ((result->w != w) || (result->h != h))) {
slouken@6232
   258
        result = result->next;
slouken@6232
   259
    }
slouken@6232
   260
slouken@6232
   261
    if (!result) {
slouken@6232
   262
        result = SDL_malloc(sizeof(GL_FBOList));
slouken@6232
   263
        if (result) {
slouken@6232
   264
            result->w = w;
slouken@6232
   265
            result->h = h;
slouken@6232
   266
            data->glGenFramebuffersEXT(1, &result->FBO);
slouken@6232
   267
            result->next = data->framebuffers;
slouken@6232
   268
            data->framebuffers = result;
slouken@6232
   269
        }
slouken@6232
   270
    }
slouken@6232
   271
    return result;
slouken@6232
   272
}
slouken@6232
   273
slouken@1918
   274
SDL_Renderer *
slouken@1918
   275
GL_CreateRenderer(SDL_Window * window, Uint32 flags)
slouken@1918
   276
{
slouken@1918
   277
    SDL_Renderer *renderer;
slouken@1918
   278
    GL_RenderData *data;
slouken@5233
   279
    const char *hint;
slouken@1952
   280
    GLint value;
slouken@5154
   281
    Uint32 window_flags;
slouken@1918
   282
slouken@5154
   283
    window_flags = SDL_GetWindowFlags(window);
slouken@5154
   284
    if (!(window_flags & SDL_WINDOW_OPENGL)) {
slouken@5154
   285
        if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
slouken@6182
   286
            /* Uh oh, better try to put it back... */
slouken@6182
   287
            SDL_RecreateWindow(window, window_flags);
slouken@1924
   288
            return NULL;
slouken@1924
   289
        }
slouken@1918
   290
    }
slouken@1918
   291
slouken@1920
   292
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
slouken@1918
   293
    if (!renderer) {
slouken@1918
   294
        SDL_OutOfMemory();
slouken@1918
   295
        return NULL;
slouken@1918
   296
    }
slouken@1918
   297
slouken@1920
   298
    data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
slouken@1918
   299
    if (!data) {
slouken@1918
   300
        GL_DestroyRenderer(renderer);
slouken@1918
   301
        SDL_OutOfMemory();
slouken@1918
   302
        return NULL;
slouken@1918
   303
    }
slouken@1918
   304
slouken@5147
   305
    renderer->WindowEvent = GL_WindowEvent;
slouken@1918
   306
    renderer->CreateTexture = GL_CreateTexture;
slouken@1918
   307
    renderer->UpdateTexture = GL_UpdateTexture;
slouken@1918
   308
    renderer->LockTexture = GL_LockTexture;
slouken@1918
   309
    renderer->UnlockTexture = GL_UnlockTexture;
slouken@6247
   310
    renderer->SetRenderTarget = GL_SetRenderTarget;
slouken@5297
   311
    renderer->UpdateViewport = GL_UpdateViewport;
slouken@3596
   312
    renderer->RenderClear = GL_RenderClear;
slouken@3596
   313
    renderer->RenderDrawPoints = GL_RenderDrawPoints;
slouken@3596
   314
    renderer->RenderDrawLines = GL_RenderDrawLines;
slouken@3596
   315
    renderer->RenderFillRects = GL_RenderFillRects;
slouken@1918
   316
    renderer->RenderCopy = GL_RenderCopy;
slouken@3431
   317
    renderer->RenderReadPixels = GL_RenderReadPixels;
slouken@1918
   318
    renderer->RenderPresent = GL_RenderPresent;
slouken@1918
   319
    renderer->DestroyTexture = GL_DestroyTexture;
slouken@1918
   320
    renderer->DestroyRenderer = GL_DestroyRenderer;
slouken@1918
   321
    renderer->info = GL_RenderDriver.info;
slouken@6246
   322
    renderer->info.flags = SDL_RENDERER_ACCELERATED;
slouken@1918
   323
    renderer->driverdata = data;
slouken@6171
   324
    renderer->window = window;
slouken@1918
   325
slouken@3685
   326
    data->context = SDL_GL_CreateContext(window);
slouken@1918
   327
    if (!data->context) {
slouken@1918
   328
        GL_DestroyRenderer(renderer);
slouken@1918
   329
        return NULL;
slouken@1918
   330
    }
slouken@3685
   331
    if (SDL_GL_MakeCurrent(window, data->context) < 0) {
slouken@1918
   332
        GL_DestroyRenderer(renderer);
slouken@1918
   333
        return NULL;
slouken@1918
   334
    }
slouken@5204
   335
slouken@5204
   336
    if (GL_LoadFunctions(data) < 0) {
slouken@5204
   337
        GL_DestroyRenderer(renderer);
slouken@5204
   338
        return NULL;
slouken@5204
   339
    }
slouken@5204
   340
slouken@2246
   341
#ifdef __MACOSX__
slouken@2246
   342
    /* Enable multi-threaded rendering */
slouken@2246
   343
    /* Disabled until Ryan finishes his VBO/PBO code...
bob@2295
   344
       CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
bob@2295
   345
     */
slouken@2246
   346
#endif
slouken@2246
   347
slouken@1965
   348
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
slouken@1918
   349
        SDL_GL_SetSwapInterval(1);
slouken@1918
   350
    } else {
slouken@1918
   351
        SDL_GL_SetSwapInterval(0);
slouken@1918
   352
    }
slouken@1918
   353
    if (SDL_GL_GetSwapInterval() > 0) {
slouken@1965
   354
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@1918
   355
    }
slouken@1918
   356
slouken@1952
   357
    data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
slouken@1952
   358
    renderer->info.max_texture_width = value;
slouken@1952
   359
    data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
slouken@1952
   360
    renderer->info.max_texture_height = value;
slouken@1920
   361
slouken@1926
   362
    if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
slouken@1926
   363
        || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
slouken@1926
   364
        data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
slouken@1926
   365
    }
slouken@1920
   366
slouken@5228
   367
    /* Check for multitexture support */
slouken@5228
   368
    if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
slouken@5228
   369
        data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
slouken@5228
   370
        if (data->glActiveTextureARB) {
slouken@5228
   371
            data->GL_ARB_multitexture_supported = SDL_TRUE;
slouken@5228
   372
            data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
slouken@5228
   373
        }
slouken@5228
   374
    }
slouken@5228
   375
slouken@5228
   376
    /* Check for shader support */
slouken@5233
   377
    hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);
slouken@5233
   378
    if (!hint || *hint != '0') {
slouken@5233
   379
        data->shaders = GL_CreateShaderContext();
slouken@5233
   380
    }
slouken@5233
   381
    SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
slouken@5233
   382
                data->shaders ? "ENABLED" : "DISABLED");
slouken@5228
   383
slouken@5228
   384
    /* We support YV12 textures using 3 textures and a shader */
slouken@5228
   385
    if (data->shaders && data->num_texture_units >= 3) {
slouken@5228
   386
        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
slouken@5264
   387
        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
slouken@5228
   388
    }
slouken@6232
   389
    
slouken@6232
   390
    if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
slouken@6232
   391
        data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
slouken@6232
   392
        data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
slouken@6232
   393
            SDL_GL_GetProcAddress("glGenFramebuffersEXT");
slouken@6232
   394
        data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
slouken@6232
   395
            SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
slouken@6232
   396
        data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
slouken@6232
   397
            SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
slouken@6232
   398
        data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
slouken@6232
   399
            SDL_GL_GetProcAddress("glBindFramebufferEXT");
slouken@6246
   400
        data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
slouken@6232
   401
            SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
slouken@6246
   402
        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
slouken@6232
   403
    }
slouken@6232
   404
    data->framebuffers = NULL;
slouken@5228
   405
slouken@1918
   406
    /* Set up parameters for rendering */
slouken@5355
   407
    GL_ResetState(renderer);
slouken@1918
   408
slouken@1918
   409
    return renderer;
slouken@1918
   410
}
slouken@1918
   411
slouken@5147
   412
static void
slouken@5147
   413
GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
slouken@1970
   414
{
slouken@6260
   415
    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
slouken@6260
   416
        event->event == SDL_WINDOWEVENT_SHOWN ||
slouken@6260
   417
        event->event == SDL_WINDOWEVENT_HIDDEN) {
slouken@5147
   418
        /* Rebind the context to the window area and update matrices */
slouken@5147
   419
        SDL_CurrentContext = NULL;
slouken@5147
   420
    }
slouken@1923
   421
}
slouken@1923
   422
slouken@1922
   423
static __inline__ int
slouken@1922
   424
power_of_2(int input)
slouken@1922
   425
{
slouken@1922
   426
    int value = 1;
slouken@1922
   427
slouken@1922
   428
    while (value < input) {
slouken@1922
   429
        value <<= 1;
slouken@1922
   430
    }
slouken@1922
   431
    return value;
slouken@1922
   432
}
slouken@1922
   433
slouken@3433
   434
static __inline__ SDL_bool
slouken@3433
   435
convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
slouken@3433
   436
               GLint* internalFormat, GLenum* format, GLenum* type)
slouken@3433
   437
{
slouken@3433
   438
    switch (pixel_format) {
slouken@3433
   439
    case SDL_PIXELFORMAT_ARGB8888:
slouken@5156
   440
        *internalFormat = GL_RGBA8;
slouken@3433
   441
        *format = GL_BGRA;
slouken@3433
   442
        *type = GL_UNSIGNED_INT_8_8_8_8_REV;
slouken@3433
   443
        break;
slouken@5264
   444
    case SDL_PIXELFORMAT_YV12:
slouken@5264
   445
    case SDL_PIXELFORMAT_IYUV:
slouken@5264
   446
        *internalFormat = GL_LUMINANCE;
slouken@5264
   447
        *format = GL_LUMINANCE;
slouken@5264
   448
        *type = GL_UNSIGNED_BYTE;
slouken@5264
   449
        break;
slouken@3433
   450
    default:
slouken@3433
   451
        return SDL_FALSE;
slouken@3433
   452
    }
slouken@3433
   453
    return SDL_TRUE;
slouken@3433
   454
}
icculus@2835
   455
slouken@5484
   456
static GLenum
slouken@5484
   457
GetScaleQuality(void)
slouken@5484
   458
{
slouken@5484
   459
    const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
slouken@5484
   460
slouken@5484
   461
    if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
slouken@5484
   462
        return GL_NEAREST;
slouken@5484
   463
    } else {
slouken@5484
   464
        return GL_LINEAR;
slouken@5484
   465
    }
slouken@5484
   466
}
slouken@5484
   467
slouken@1918
   468
static int
slouken@1918
   469
GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
   470
{
slouken@1918
   471
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
   472
    GL_TextureData *data;
slouken@1920
   473
    GLint internalFormat;
slouken@1920
   474
    GLenum format, type;
slouken@1922
   475
    int texture_w, texture_h;
slouken@5503
   476
    GLenum scaleMode;
slouken@1924
   477
    GLenum result;
slouken@1918
   478
slouken@5147
   479
    GL_ActivateRenderer(renderer);
slouken@5147
   480
slouken@3433
   481
    if (!convert_format(renderdata, texture->format, &internalFormat,
slouken@3433
   482
                        &format, &type)) {
slouken@4990
   483
        SDL_SetError("Texture format %s not supported by OpenGL",
slouken@4990
   484
                     SDL_GetPixelFormatName(texture->format));
slouken@1920
   485
        return -1;
slouken@1920
   486
    }
slouken@1920
   487
slouken@1920
   488
    data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
slouken@1918
   489
    if (!data) {
slouken@1918
   490
        SDL_OutOfMemory();
slouken@1918
   491
        return -1;
slouken@1918
   492
    }
slouken@1918
   493
slouken@2222
   494
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5264
   495
        size_t size;
slouken@5156
   496
        data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
slouken@5264
   497
        size = texture->h * data->pitch;
slouken@5264
   498
        if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@5264
   499
            texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@5264
   500
            /* Need to add size for the U and V planes */
slouken@5264
   501
            size += (2 * (texture->h * data->pitch) / 4);
slouken@5264
   502
        }
slouken@5402
   503
        data->pixels = SDL_calloc(1, size);
slouken@2222
   504
        if (!data->pixels) {
slouken@2222
   505
            SDL_OutOfMemory();
slouken@2222
   506
            SDL_free(data);
slouken@2222
   507
            return -1;
slouken@2222
   508
        }
slouken@2222
   509
    }
slouken@2222
   510
slouken@1918
   511
    texture->driverdata = data;
slouken@6232
   512
    
slouken@6232
   513
    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
slouken@6232
   514
        data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
slouken@6232
   515
    } else {
slouken@6232
   516
        data->fbo = NULL;
slouken@6232
   517
    }
slouken@1918
   518
slouken@1927
   519
    renderdata->glGetError();
slouken@1927
   520
    renderdata->glGenTextures(1, &data->texture);
slouken@6232
   521
    if ((renderdata->GL_ARB_texture_rectangle_supported)
slouken@6232
   522
        /*&& texture->access != SDL_TEXTUREACCESS_TARGET*/){
slouken@1926
   523
        data->type = GL_TEXTURE_RECTANGLE_ARB;
slouken@1926
   524
        texture_w = texture->w;
slouken@1926
   525
        texture_h = texture->h;
icculus@2835
   526
        data->texw = (GLfloat) texture_w;
icculus@2835
   527
        data->texh = (GLfloat) texture_h;
slouken@1926
   528
    } else {
slouken@1926
   529
        data->type = GL_TEXTURE_2D;
slouken@1926
   530
        texture_w = power_of_2(texture->w);
slouken@1926
   531
        texture_h = power_of_2(texture->h);
icculus@2835
   532
        data->texw = (GLfloat) (texture->w) / texture_w;
slouken@1926
   533
        data->texh = (GLfloat) texture->h / texture_h;
slouken@1926
   534
    }
icculus@2835
   535
slouken@1920
   536
    data->format = format;
slouken@1920
   537
    data->formattype = type;
slouken@5503
   538
    scaleMode = GetScaleQuality();
slouken@2884
   539
    renderdata->glEnable(data->type);
slouken@1927
   540
    renderdata->glBindTexture(data->type, data->texture);
slouken@5503
   541
    renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
slouken@5503
   542
    renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
slouken@6207
   543
    /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
slouken@6207
   544
       and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
slouken@6207
   545
    */
slouken@6207
   546
    if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
slouken@6207
   547
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
slouken@6207
   548
                                    GL_CLAMP_TO_EDGE);
slouken@6207
   549
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
slouken@6207
   550
                                    GL_CLAMP_TO_EDGE);
slouken@6207
   551
    }
slouken@2840
   552
#ifdef __MACOSX__
slouken@2230
   553
#ifndef GL_TEXTURE_STORAGE_HINT_APPLE
slouken@2230
   554
#define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
slouken@2230
   555
#endif
slouken@2230
   556
#ifndef STORAGE_CACHED_APPLE
slouken@2230
   557
#define STORAGE_CACHED_APPLE                0x85BE
slouken@2230
   558
#endif
slouken@2230
   559
#ifndef STORAGE_SHARED_APPLE
slouken@2230
   560
#define STORAGE_SHARED_APPLE                0x85BF
slouken@2230
   561
#endif
slouken@2230
   562
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@2230
   563
        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
slouken@2230
   564
                                    GL_STORAGE_SHARED_APPLE);
slouken@2230
   565
    } else {
slouken@2230
   566
        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
slouken@2230
   567
                                    GL_STORAGE_CACHED_APPLE);
slouken@2230
   568
    }
bob@2295
   569
    if (texture->access == SDL_TEXTUREACCESS_STREAMING
slouken@5397
   570
        && texture->format == SDL_PIXELFORMAT_ARGB8888
slouken@5397
   571
        && (texture->w % 8) == 0) {
slouken@2230
   572
        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
slouken@5397
   573
        renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@5397
   574
        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
slouken@5397
   575
                          (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
slouken@2230
   576
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
slouken@2230
   577
                                 texture_h, 0, format, type, data->pixels);
slouken@5397
   578
        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
slouken@5156
   579
    }
slouken@5156
   580
    else
slouken@2809
   581
#endif
slouken@2230
   582
    {
slouken@2230
   583
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
slouken@2230
   584
                                 texture_h, 0, format, type, NULL);
slouken@2230
   585
    }
slouken@3041
   586
    renderdata->glDisable(data->type);
slouken@1927
   587
    result = renderdata->glGetError();
slouken@1924
   588
    if (result != GL_NO_ERROR) {
slouken@1924
   589
        GL_SetError("glTexImage2D()", result);
slouken@1924
   590
        return -1;
slouken@1924
   591
    }
slouken@5264
   592
slouken@5264
   593
    if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@5264
   594
        texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@5264
   595
        data->yuv = SDL_TRUE;
slouken@5264
   596
slouken@5264
   597
        renderdata->glGenTextures(1, &data->utexture);
slouken@5264
   598
        renderdata->glGenTextures(1, &data->vtexture);
slouken@5264
   599
        renderdata->glEnable(data->type);
slouken@5264
   600
slouken@5264
   601
        renderdata->glBindTexture(data->type, data->utexture);
slouken@5503
   602
        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
slouken@5503
   603
                                    scaleMode);
slouken@5503
   604
        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
slouken@5503
   605
                                    scaleMode);
slouken@5264
   606
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
slouken@5264
   607
                                    GL_CLAMP_TO_EDGE);
slouken@5264
   608
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
slouken@5264
   609
                                    GL_CLAMP_TO_EDGE);
slouken@5264
   610
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
slouken@5264
   611
                                 texture_h/2, 0, format, type, NULL);
slouken@5264
   612
slouken@5264
   613
        renderdata->glBindTexture(data->type, data->vtexture);
slouken@5503
   614
        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
slouken@5503
   615
                                    scaleMode);
slouken@5503
   616
        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
slouken@5503
   617
                                    scaleMode);
slouken@5264
   618
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
slouken@5264
   619
                                    GL_CLAMP_TO_EDGE);
slouken@5264
   620
        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
slouken@5264
   621
                                    GL_CLAMP_TO_EDGE);
slouken@5264
   622
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
slouken@5264
   623
                                 texture_h/2, 0, format, type, NULL);
slouken@5264
   624
slouken@5264
   625
        renderdata->glDisable(data->type);
slouken@5264
   626
    }
slouken@1918
   627
    return 0;
slouken@1918
   628
}
slouken@1918
   629
slouken@1918
   630
static int
slouken@1918
   631
GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
   632
                 const SDL_Rect * rect, const void *pixels, int pitch)
slouken@1918
   633
{
slouken@1927
   634
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
   635
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1924
   636
    GLenum result;
slouken@1918
   637
slouken@5147
   638
    GL_ActivateRenderer(renderer);
slouken@5147
   639
slouken@1927
   640
    renderdata->glGetError();
slouken@5397
   641
    renderdata->glEnable(data->type);
slouken@5397
   642
    renderdata->glBindTexture(data->type, data->texture);
slouken@5227
   643
    renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@5227
   644
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
slouken@5227
   645
                              (pitch / SDL_BYTESPERPIXEL(texture->format)));
slouken@1927
   646
    renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
slouken@1927
   647
                                rect->h, data->format, data->formattype,
slouken@1927
   648
                                pixels);
slouken@5264
   649
    if (data->yuv) {
slouken@5265
   650
        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
slouken@5265
   651
slouken@5264
   652
        /* Skip to the correct offset into the next texture */
slouken@6135
   653
        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
slouken@5264
   654
        if (texture->format == SDL_PIXELFORMAT_YV12) {
slouken@5264
   655
            renderdata->glBindTexture(data->type, data->vtexture);
slouken@5264
   656
        } else {
slouken@5264
   657
            renderdata->glBindTexture(data->type, data->utexture);
slouken@5264
   658
        }
slouken@5264
   659
        renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
slouken@5264
   660
                                    rect->w/2, rect->h/2,
slouken@5264
   661
                                    data->format, data->formattype, pixels);
slouken@5264
   662
slouken@5264
   663
        /* Skip to the correct offset into the next texture */
slouken@6135
   664
        pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
slouken@5264
   665
        if (texture->format == SDL_PIXELFORMAT_YV12) {
slouken@5264
   666
            renderdata->glBindTexture(data->type, data->utexture);
slouken@5264
   667
        } else {
slouken@5264
   668
            renderdata->glBindTexture(data->type, data->vtexture);
slouken@5264
   669
        }
slouken@5264
   670
        renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
slouken@5264
   671
                                    rect->w/2, rect->h/2,
slouken@5264
   672
                                    data->format, data->formattype, pixels);
slouken@5264
   673
    }
slouken@3041
   674
    renderdata->glDisable(data->type);
slouken@1927
   675
    result = renderdata->glGetError();
slouken@1924
   676
    if (result != GL_NO_ERROR) {
slouken@1924
   677
        GL_SetError("glTexSubImage2D()", result);
slouken@1924
   678
        return -1;
slouken@1924
   679
    }
slouken@1918
   680
    return 0;
slouken@1918
   681
}
slouken@1918
   682
slouken@1918
   683
static int
slouken@1918
   684
GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   685
               const SDL_Rect * rect, void **pixels, int *pitch)
slouken@1918
   686
{
slouken@1918
   687
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
   688
slouken@5227
   689
    data->locked_rect = *rect;
slouken@5227
   690
    *pixels = 
slouken@1920
   691
        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
slouken@5156
   692
                  rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@1920
   693
    *pitch = data->pitch;
slouken@1918
   694
    return 0;
slouken@1918
   695
}
slouken@1918
   696
slouken@1918
   697
static void
slouken@1918
   698
GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
   699
{
slouken@5156
   700
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@5227
   701
    const SDL_Rect *rect;
slouken@5227
   702
    void *pixels;
slouken@1918
   703
slouken@5227
   704
    rect = &data->locked_rect;
slouken@5227
   705
    pixels = 
slouken@5227
   706
        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
slouken@5227
   707
                  rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5227
   708
    GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
slouken@1918
   709
}
slouken@1918
   710
slouken@5297
   711
static int
slouken@6247
   712
GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@6246
   713
{
slouken@6246
   714
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;    
slouken@6246
   715
    GL_TextureData *texturedata;
slouken@6246
   716
    GLenum status;
slouken@6246
   717
slouken@6246
   718
    GL_ActivateRenderer(renderer);
slouken@6246
   719
    
slouken@6246
   720
    if (texture == NULL) {
slouken@6246
   721
        data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
slouken@6246
   722
        return 0;
slouken@6246
   723
    }
slouken@6246
   724
slouken@6246
   725
    texturedata = (GL_TextureData *) texture->driverdata;
slouken@6246
   726
    data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
slouken@6246
   727
    /* TODO: check if texture pixel format allows this operation */
slouken@6246
   728
    data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
slouken@6246
   729
    /* Check FBO status */
slouken@6246
   730
    status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
slouken@6246
   731
    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
slouken@6246
   732
        SDL_SetError("glFramebufferTexture2DEXT() failed");
slouken@6246
   733
        return -1;
slouken@6246
   734
    }
slouken@6246
   735
    return 0;
slouken@6246
   736
}
slouken@6246
   737
slouken@6246
   738
static int
slouken@5297
   739
GL_UpdateViewport(SDL_Renderer * renderer)
slouken@5224
   740
{
slouken@5224
   741
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5224
   742
slouken@5297
   743
    if (SDL_CurrentContext != data->context) {
slouken@5297
   744
        /* We'll update the viewport after we rebind the context */
slouken@5297
   745
        return 0;
slouken@5297
   746
    }
slouken@5224
   747
slouken@5297
   748
    data->glViewport(renderer->viewport.x, renderer->viewport.y,
slouken@5297
   749
                     renderer->viewport.w, renderer->viewport.h);
slouken@5224
   750
slouken@5297
   751
    data->glMatrixMode(GL_PROJECTION);
slouken@5297
   752
    data->glLoadIdentity();
slouken@6246
   753
    if (renderer->target) {
slouken@6246
   754
        data->glOrtho((GLdouble) 0,
slouken@6246
   755
                      (GLdouble) renderer->viewport.w,
slouken@6246
   756
                      (GLdouble) 0,
slouken@6246
   757
                      (GLdouble) renderer->viewport.h,
slouken@6246
   758
                       0.0, 1.0);
slouken@6246
   759
    } else {
slouken@6246
   760
        data->glOrtho((GLdouble) 0,
slouken@6246
   761
                      (GLdouble) renderer->viewport.w,
slouken@6246
   762
                      (GLdouble) renderer->viewport.h,
slouken@6246
   763
                      (GLdouble) 0,
slouken@6246
   764
                       0.0, 1.0);
slouken@6246
   765
    }
slouken@5297
   766
    return 0;
slouken@5224
   767
}
slouken@5224
   768
slouken@5224
   769
static void
slouken@5355
   770
GL_SetShader(GL_RenderData * data, GL_Shader shader)
slouken@5355
   771
{
slouken@5355
   772
    if (data->shaders && shader != data->current.shader) {
slouken@5355
   773
        GL_SelectShader(data->shaders, shader);
slouken@5355
   774
        data->current.shader = shader;
slouken@5355
   775
    }
slouken@5355
   776
}
slouken@5355
   777
slouken@5355
   778
static void
slouken@5355
   779
GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
slouken@5355
   780
{
slouken@5355
   781
    Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
slouken@5355
   782
slouken@5355
   783
    if (color != data->current.color) {
slouken@5355
   784
        data->glColor4f((GLfloat) r * inv255f,
slouken@5355
   785
                        (GLfloat) g * inv255f,
slouken@5355
   786
                        (GLfloat) b * inv255f,
slouken@5355
   787
                        (GLfloat) a * inv255f);
slouken@5355
   788
        data->current.color = color;
slouken@5355
   789
    }
slouken@5355
   790
}
slouken@5355
   791
slouken@5355
   792
static void
slouken@5140
   793
GL_SetBlendMode(GL_RenderData * data, int blendMode)
slouken@2936
   794
{
slouken@5355
   795
    if (blendMode != data->current.blendMode) {
slouken@2936
   796
        switch (blendMode) {
slouken@2936
   797
        case SDL_BLENDMODE_NONE:
slouken@2936
   798
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
slouken@2936
   799
            data->glDisable(GL_BLEND);
slouken@2936
   800
            break;
slouken@2936
   801
        case SDL_BLENDMODE_BLEND:
slouken@2936
   802
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@2936
   803
            data->glEnable(GL_BLEND);
slouken@2936
   804
            data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
slouken@2936
   805
            break;
slouken@2936
   806
        case SDL_BLENDMODE_ADD:
slouken@2936
   807
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@2936
   808
            data->glEnable(GL_BLEND);
slouken@2936
   809
            data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
slouken@2936
   810
            break;
slouken@5184
   811
        case SDL_BLENDMODE_MOD:
slouken@5184
   812
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@5184
   813
            data->glEnable(GL_BLEND);
slouken@5184
   814
            data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
slouken@5184
   815
            break;
slouken@2936
   816
        }
slouken@5355
   817
        data->current.blendMode = blendMode;
slouken@2936
   818
    }
slouken@2936
   819
}
slouken@2936
   820
slouken@5355
   821
static void
slouken@5355
   822
GL_SetDrawingState(SDL_Renderer * renderer)
slouken@5355
   823
{
slouken@5355
   824
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5355
   825
slouken@5355
   826
    GL_ActivateRenderer(renderer);
slouken@5355
   827
slouken@5381
   828
    GL_SetColor(data, renderer->r,
slouken@5381
   829
                      renderer->g,
slouken@5381
   830
                      renderer->b,
slouken@5381
   831
                      renderer->a);
slouken@5355
   832
slouken@5355
   833
    GL_SetBlendMode(data, renderer->blendMode);
slouken@5355
   834
slouken@5355
   835
    GL_SetShader(data, SHADER_SOLID);
slouken@5355
   836
}
slouken@5355
   837
slouken@1918
   838
static int
slouken@3596
   839
GL_RenderClear(SDL_Renderer * renderer)
slouken@3596
   840
{
slouken@3596
   841
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3596
   842
slouken@5147
   843
    GL_ActivateRenderer(renderer);
slouken@5147
   844
slouken@3596
   845
    data->glClearColor((GLfloat) renderer->r * inv255f,
slouken@3596
   846
                       (GLfloat) renderer->g * inv255f,
slouken@3596
   847
                       (GLfloat) renderer->b * inv255f,
slouken@3596
   848
                       (GLfloat) renderer->a * inv255f);
slouken@3596
   849
slouken@3596
   850
    data->glClear(GL_COLOR_BUFFER_BIT);
slouken@3596
   851
slouken@3596
   852
    return 0;
slouken@3596
   853
}
slouken@3596
   854
slouken@3596
   855
static int
slouken@3596
   856
GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
slouken@3596
   857
                    int count)
slouken@2884
   858
{
slouken@2884
   859
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3536
   860
    int i;
slouken@2884
   861
slouken@5355
   862
    GL_SetDrawingState(renderer);
slouken@2884
   863
slouken@2901
   864
    data->glBegin(GL_POINTS);
slouken@3536
   865
    for (i = 0; i < count; ++i) {
slouken@3536
   866
        data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
slouken@3536
   867
    }
slouken@2901
   868
    data->glEnd();
slouken@2901
   869
slouken@2901
   870
    return 0;
slouken@2901
   871
}
slouken@2901
   872
slouken@2901
   873
static int
slouken@3596
   874
GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
slouken@3596
   875
                   int count)
slouken@2901
   876
{
slouken@2901
   877
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3536
   878
    int i;
slouken@2901
   879
slouken@5355
   880
    GL_SetDrawingState(renderer);
slouken@2901
   881
slouken@3536
   882
    if (count > 2 && 
slouken@3536
   883
        points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
slouken@3536
   884
        data->glBegin(GL_LINE_LOOP);
slouken@3536
   885
        /* GL_LINE_LOOP takes care of the final segment */
slouken@3536
   886
        --count;
slouken@3536
   887
        for (i = 0; i < count; ++i) {
slouken@3536
   888
            data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
slouken@3536
   889
        }
slouken@3536
   890
        data->glEnd();
slouken@3536
   891
    } else {
slouken@5086
   892
#if defined(__APPLE__) || defined(__WIN32__)
aschiffler@4910
   893
#else
slouken@4905
   894
        int x1, y1, x2, y2;
aschiffler@4910
   895
#endif
slouken@4905
   896
slouken@3536
   897
        data->glBegin(GL_LINE_STRIP);
slouken@3536
   898
        for (i = 0; i < count; ++i) {
slouken@3536
   899
            data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
slouken@3536
   900
        }
slouken@3536
   901
        data->glEnd();
slouken@3474
   902
slouken@3536
   903
        /* The line is half open, so we need one more point to complete it.
slouken@3536
   904
         * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
slouken@3536
   905
         * If we have to, we can use vertical line and horizontal line textures
slouken@3536
   906
         * for vertical and horizontal lines, and then create custom textures
slouken@3536
   907
         * for diagonal lines and software render those.  It's terrible, but at
slouken@3536
   908
         * least it would be pixel perfect.
slouken@3536
   909
         */
slouken@3536
   910
        data->glBegin(GL_POINTS);
slouken@5086
   911
#if defined(__APPLE__) || defined(__WIN32__)
slouken@3536
   912
        /* Mac OS X and Windows seem to always leave the second point open */
slouken@3536
   913
        data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
slouken@3474
   914
#else
slouken@3536
   915
        /* Linux seems to leave the right-most or bottom-most point open */
slouken@4905
   916
        x1 = points[0].x;
slouken@4905
   917
        y1 = points[0].y;
slouken@4905
   918
        x2 = points[count-1].x;
slouken@4905
   919
        y2 = points[count-1].y;
slouken@3536
   920
slouken@3536
   921
        if (x1 > x2) {
slouken@3536
   922
            data->glVertex2f(0.5f + x1, 0.5f + y1);
slouken@3536
   923
        } else if (x2 > x1) {
slouken@3536
   924
            data->glVertex2f(0.5f + x2, 0.5f + y2);
slouken@3536
   925
        } else if (y1 > y2) {
slouken@3536
   926
            data->glVertex2f(0.5f + x1, 0.5f + y1);
slouken@3536
   927
        } else if (y2 > y1) {
slouken@3536
   928
            data->glVertex2f(0.5f + x2, 0.5f + y2);
slouken@3536
   929
        }
slouken@3536
   930
#endif
slouken@3536
   931
        data->glEnd();
slouken@3474
   932
    }
slouken@3455
   933
slouken@1918
   934
    return 0;
slouken@1918
   935
}
slouken@1918
   936
slouken@1918
   937
static int
slouken@5297
   938
GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count)
slouken@2925
   939
{
slouken@2925
   940
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3536
   941
    int i;
slouken@2925
   942
slouken@5355
   943
    GL_SetDrawingState(renderer);
slouken@2936
   944
slouken@3536
   945
    for (i = 0; i < count; ++i) {
slouken@5297
   946
        const SDL_Rect *rect = &rects[i];
slouken@3536
   947
slouken@3536
   948
        data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
slouken@3536
   949
    }
slouken@2925
   950
slouken@2925
   951
    return 0;
slouken@2925
   952
}
slouken@2925
   953
slouken@2925
   954
static int
slouken@1918
   955
GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
   956
              const SDL_Rect * srcrect, const SDL_Rect * dstrect)
slouken@1918
   957
{
slouken@1918
   958
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1918
   959
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
slouken@1918
   960
    int minx, miny, maxx, maxy;
slouken@1918
   961
    GLfloat minu, maxu, minv, maxv;
slouken@1918
   962
slouken@5147
   963
    GL_ActivateRenderer(renderer);
slouken@5147
   964
slouken@5355
   965
    data->glEnable(texturedata->type);
slouken@5355
   966
    if (texturedata->yuv) {
slouken@5355
   967
        data->glActiveTextureARB(GL_TEXTURE2_ARB);
slouken@5355
   968
        data->glBindTexture(texturedata->type, texturedata->vtexture);
slouken@5355
   969
slouken@5355
   970
        data->glActiveTextureARB(GL_TEXTURE1_ARB);
slouken@5355
   971
        data->glBindTexture(texturedata->type, texturedata->utexture);
slouken@5355
   972
slouken@5355
   973
        data->glActiveTextureARB(GL_TEXTURE0_ARB);
slouken@5355
   974
    }
slouken@5355
   975
    data->glBindTexture(texturedata->type, texturedata->texture);
slouken@5355
   976
slouken@5355
   977
    if (texture->modMode) {
slouken@5355
   978
        GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
slouken@5355
   979
    } else {
slouken@5355
   980
        GL_SetColor(data, 255, 255, 255, 255);
slouken@5355
   981
    }
slouken@5355
   982
slouken@5355
   983
    GL_SetBlendMode(data, texture->blendMode);
slouken@5355
   984
slouken@5355
   985
    if (texturedata->yuv) {
slouken@5355
   986
        GL_SetShader(data, SHADER_YV12);
slouken@5355
   987
    } else {
slouken@5355
   988
        GL_SetShader(data, SHADER_RGB);
slouken@5355
   989
    }
slouken@5355
   990
slouken@1918
   991
    minx = dstrect->x;
slouken@1918
   992
    miny = dstrect->y;
slouken@1918
   993
    maxx = dstrect->x + dstrect->w;
slouken@1918
   994
    maxy = dstrect->y + dstrect->h;
slouken@1918
   995
slouken@1918
   996
    minu = (GLfloat) srcrect->x / texture->w;
slouken@1920
   997
    minu *= texturedata->texw;
slouken@1918
   998
    maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
slouken@1920
   999
    maxu *= texturedata->texw;
slouken@1918
  1000
    minv = (GLfloat) srcrect->y / texture->h;
slouken@1920
  1001
    minv *= texturedata->texh;
slouken@1918
  1002
    maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
slouken@1920
  1003
    maxv *= texturedata->texh;
slouken@1918
  1004
slouken@1927
  1005
    data->glBegin(GL_TRIANGLE_STRIP);
slouken@1927
  1006
    data->glTexCoord2f(minu, minv);
slouken@3472
  1007
    data->glVertex2f((GLfloat) minx, (GLfloat) miny);
slouken@1927
  1008
    data->glTexCoord2f(maxu, minv);
slouken@3472
  1009
    data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
slouken@1927
  1010
    data->glTexCoord2f(minu, maxv);
slouken@3472
  1011
    data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
slouken@1927
  1012
    data->glTexCoord2f(maxu, maxv);
slouken@3472
  1013
    data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
slouken@1927
  1014
    data->glEnd();
slouken@1918
  1015
slouken@2884
  1016
    data->glDisable(texturedata->type);
slouken@2884
  1017
slouken@1918
  1018
    return 0;
slouken@1918
  1019
}
slouken@1918
  1020
slouken@3431
  1021
static int
slouken@3431
  1022
GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
  1023
                    Uint32 pixel_format, void * pixels, int pitch)
slouken@3431
  1024
{
slouken@3433
  1025
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3685
  1026
    SDL_Window *window = renderer->window;
slouken@5465
  1027
    Uint32 temp_format = SDL_PIXELFORMAT_ARGB8888;
slouken@5465
  1028
    void *temp_pixels;
slouken@5465
  1029
    int temp_pitch;
slouken@3433
  1030
    GLint internalFormat;
slouken@3433
  1031
    GLenum format, type;
slouken@3435
  1032
    Uint8 *src, *dst, *tmp;
slouken@5154
  1033
    int w, h, length, rows;
slouken@5465
  1034
    int status;
slouken@3433
  1035
slouken@5147
  1036
    GL_ActivateRenderer(renderer);
slouken@5147
  1037
slouken@5465
  1038
    temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@5465
  1039
    temp_pixels = SDL_malloc(rect->h * temp_pitch);
slouken@5465
  1040
    if (!temp_pixels) {
slouken@5465
  1041
        SDL_OutOfMemory();
slouken@3433
  1042
        return -1;
slouken@3433
  1043
    }
slouken@3433
  1044
slouken@5465
  1045
    convert_format(data, temp_format, &internalFormat, &format, &type);
slouken@5465
  1046
slouken@5154
  1047
    SDL_GetWindowSize(window, &w, &h);
slouken@5154
  1048
slouken@3446
  1049
    data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
slouken@3446
  1050
    data->glPixelStorei(GL_PACK_ROW_LENGTH,
slouken@5465
  1051
                        (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
slouken@3433
  1052
slouken@5154
  1053
    data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
slouken@5465
  1054
                       format, type, temp_pixels);
slouken@3435
  1055
slouken@3435
  1056
    /* Flip the rows to be top-down */
slouken@5465
  1057
    length = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@5465
  1058
    src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
slouken@5465
  1059
    dst = (Uint8*)temp_pixels;
slouken@3435
  1060
    tmp = SDL_stack_alloc(Uint8, length);
slouken@3435
  1061
    rows = rect->h / 2;
slouken@3435
  1062
    while (rows--) {
slouken@3435
  1063
        SDL_memcpy(tmp, dst, length);
slouken@3435
  1064
        SDL_memcpy(dst, src, length);
slouken@3435
  1065
        SDL_memcpy(src, tmp, length);
slouken@5465
  1066
        dst += temp_pitch;
slouken@5465
  1067
        src -= temp_pitch;
slouken@3435
  1068
    }
slouken@3435
  1069
    SDL_stack_free(tmp);
slouken@3440
  1070
slouken@5465
  1071
    status = SDL_ConvertPixels(rect->w, rect->h,
slouken@5465
  1072
                               temp_format, temp_pixels, temp_pitch,
slouken@5465
  1073
                               pixel_format, pixels, pitch);
slouken@5465
  1074
    SDL_free(temp_pixels);
slouken@5465
  1075
slouken@5465
  1076
    return status;
slouken@3431
  1077
}
slouken@3431
  1078
slouken@1918
  1079
static void
slouken@1918
  1080
GL_RenderPresent(SDL_Renderer * renderer)
slouken@1918
  1081
{
slouken@5147
  1082
    GL_ActivateRenderer(renderer);
slouken@5147
  1083
slouken@1918
  1084
    SDL_GL_SwapWindow(renderer->window);
slouken@1918
  1085
}
slouken@1918
  1086
slouken@1918
  1087
static void
slouken@1918
  1088
GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
  1089
{
slouken@1927
  1090
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1091
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
  1092
slouken@5147
  1093
    GL_ActivateRenderer(renderer);
slouken@5147
  1094
slouken@1918
  1095
    if (!data) {
slouken@1918
  1096
        return;
slouken@1918
  1097
    }
slouken@1918
  1098
    if (data->texture) {
slouken@1927
  1099
        renderdata->glDeleteTextures(1, &data->texture);
slouken@1918
  1100
    }
slouken@5264
  1101
    if (data->yuv) {
slouken@5264
  1102
        renderdata->glDeleteTextures(1, &data->utexture);
slouken@5264
  1103
        renderdata->glDeleteTextures(1, &data->vtexture);
slouken@5264
  1104
    }
slouken@1920
  1105
    if (data->pixels) {
slouken@1920
  1106
        SDL_free(data->pixels);
slouken@1920
  1107
    }
slouken@1918
  1108
    SDL_free(data);
slouken@1918
  1109
    texture->driverdata = NULL;
slouken@1918
  1110
}
slouken@1918
  1111
slouken@1975
  1112
static void
slouken@1918
  1113
GL_DestroyRenderer(SDL_Renderer * renderer)
slouken@1918
  1114
{
slouken@1918
  1115
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1116
slouken@1918
  1117
    if (data) {
icculus@5566
  1118
        if (data->shaders) {
icculus@5566
  1119
            GL_DestroyShaderContext(data->shaders);
icculus@5566
  1120
        }
slouken@1920
  1121
        if (data->context) {
slouken@6232
  1122
            while (data->framebuffers) {
slouken@6232
  1123
                GL_FBOList *nextnode = data->framebuffers->next;
slouken@6232
  1124
                /* delete the framebuffer object */
slouken@6232
  1125
                data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
slouken@6232
  1126
                SDL_free(data->framebuffers);
slouken@6232
  1127
                data->framebuffers = nextnode;
slouken@6232
  1128
            }            
bob@2328
  1129
            /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
slouken@1920
  1130
            SDL_GL_DeleteContext(data->context);
slouken@1918
  1131
        }
slouken@1918
  1132
        SDL_free(data);
slouken@1918
  1133
    }
slouken@1918
  1134
    SDL_free(renderer);
slouken@1918
  1135
}
slouken@1918
  1136
slouken@5226
  1137
#endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
slouken@1918
  1138
slouken@1918
  1139
/* vi: set ts=4 sw=4 expandtab: */