src/video/SDL_renderer_gl.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 21 Nov 2009 07:22:59 +0000
changeset 3474 1edb86163d62
parent 3473 7bdc10624cba
child 3475 3bd01435287f
permissions -rw-r--r--
Of COURSE that trick wouldn't work on all renderers. Fall back to something for now, hopefully figure out a better way to do this later.

If we have to, we can use vertical line and horizontal line textures for vertical and horizontal lines, and then create custom textures for diagonal lines and software render those. It's terrible, but at least it would be pixel perfect.
slouken@1918
     1
/*
slouken@1918
     2
    SDL - Simple DirectMedia Layer
slouken@2858
     3
    Copyright (C) 1997-2009 Sam Lantinga
slouken@1918
     4
slouken@1918
     5
    This library is free software; you can redistribute it and/or
slouken@1918
     6
    modify it under the terms of the GNU Lesser General Public
slouken@1918
     7
    License as published by the Free Software Foundation; either
slouken@1918
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@1918
     9
slouken@1918
    10
    This library is distributed in the hope that it will be useful,
slouken@1918
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@1918
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1918
    13
    Lesser General Public License for more details.
slouken@1918
    14
slouken@1918
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1918
    16
    License along with this library; if not, write to the Free Software
slouken@1918
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@1918
    18
slouken@1918
    19
    Sam Lantinga
slouken@1918
    20
    slouken@libsdl.org
slouken@1918
    21
*/
slouken@1918
    22
#include "SDL_config.h"
slouken@1918
    23
slouken@1952
    24
#if SDL_VIDEO_RENDER_OGL
slouken@1920
    25
slouken@1920
    26
#include "SDL_video.h"
slouken@1920
    27
#include "SDL_opengl.h"
slouken@1920
    28
#include "SDL_sysvideo.h"
slouken@1920
    29
#include "SDL_pixels_c.h"
slouken@1920
    30
#include "SDL_rect_c.h"
slouken@1920
    31
#include "SDL_yuv_sw_c.h"
slouken@1918
    32
slouken@2246
    33
#ifdef __MACOSX__
slouken@2246
    34
#include <OpenGL/OpenGL.h>
slouken@2246
    35
#endif
slouken@2246
    36
slouken@2778
    37
slouken@1918
    38
/* OpenGL renderer implementation */
slouken@1918
    39
slouken@2230
    40
/* Details on optimizing the texture path on Mac OS X:
slouken@2230
    41
   http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html
slouken@2230
    42
*/
slouken@2230
    43
icculus@2835
    44
/* !!! FIXME: this should go in a higher level than the GL renderer. */
icculus@2835
    45
static __inline__ int
icculus@2835
    46
bytes_per_pixel(const Uint32 format)
icculus@2835
    47
{
slouken@2839
    48
    if (!SDL_ISPIXELFORMAT_FOURCC(format)) {
slouken@2839
    49
        return SDL_BYTESPERPIXEL(format);
slouken@2839
    50
    }
slouken@2839
    51
slouken@2839
    52
    /* FOURCC format */
icculus@2835
    53
    switch (format) {
slouken@2884
    54
    case SDL_PIXELFORMAT_YV12:
slouken@2884
    55
    case SDL_PIXELFORMAT_IYUV:
slouken@2884
    56
    case SDL_PIXELFORMAT_YUY2:
slouken@2884
    57
    case SDL_PIXELFORMAT_UYVY:
slouken@2884
    58
    case SDL_PIXELFORMAT_YVYU:
slouken@2884
    59
        return 2;
slouken@2884
    60
    default:
slouken@2884
    61
        return 1;               /* shouldn't ever hit this. */
icculus@2835
    62
    }
icculus@2835
    63
}
icculus@2835
    64
icculus@2835
    65
slouken@1985
    66
static const float inv255f = 1.0f / 255.0f;
slouken@1985
    67
slouken@1918
    68
static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
slouken@1923
    69
static int GL_ActivateRenderer(SDL_Renderer * renderer);
slouken@1970
    70
static int GL_DisplayModeChanged(SDL_Renderer * renderer);
slouken@1918
    71
static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@2222
    72
static int GL_QueryTexturePixels(SDL_Renderer * renderer,
slouken@2222
    73
                                 SDL_Texture * texture, void **pixels,
slouken@2222
    74
                                 int *pitch);
slouken@1918
    75
static int GL_SetTexturePalette(SDL_Renderer * renderer,
slouken@1918
    76
                                SDL_Texture * texture,
slouken@1918
    77
                                const SDL_Color * colors, int firstcolor,
slouken@1918
    78
                                int ncolors);
slouken@1918
    79
static int GL_GetTexturePalette(SDL_Renderer * renderer,
slouken@1918
    80
                                SDL_Texture * texture, SDL_Color * colors,
slouken@1918
    81
                                int firstcolor, int ncolors);
slouken@1985
    82
static int GL_SetTextureColorMod(SDL_Renderer * renderer,
slouken@1985
    83
                                 SDL_Texture * texture);
slouken@1985
    84
static int GL_SetTextureAlphaMod(SDL_Renderer * renderer,
slouken@1985
    85
                                 SDL_Texture * texture);
slouken@1985
    86
static int GL_SetTextureBlendMode(SDL_Renderer * renderer,
slouken@1985
    87
                                  SDL_Texture * texture);
slouken@1985
    88
static int GL_SetTextureScaleMode(SDL_Renderer * renderer,
slouken@1985
    89
                                  SDL_Texture * texture);
slouken@1918
    90
static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
    91
                            const SDL_Rect * rect, const void *pixels,
slouken@1918
    92
                            int pitch);
slouken@1918
    93
static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
    94
                          const SDL_Rect * rect, int markDirty, void **pixels,
slouken@1985
    95
                          int *pitch);
slouken@1918
    96
static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1918
    97
static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
    98
                            int numrects, const SDL_Rect * rects);
slouken@2901
    99
static int GL_RenderPoint(SDL_Renderer * renderer, int x, int y);
slouken@2884
   100
static int GL_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2,
slouken@2884
   101
                         int y2);
slouken@2884
   102
static int GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect);
slouken@1918
   103
static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
   104
                         const SDL_Rect * srcrect, const SDL_Rect * dstrect);
slouken@3431
   105
static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
   106
                               Uint32 pixel_format, void * pixels, int pitch);
slouken@3431
   107
static int GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
   108
                                Uint32 pixel_format, const void * pixels, int pitch);
slouken@1918
   109
static void GL_RenderPresent(SDL_Renderer * renderer);
slouken@1918
   110
static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1918
   111
static void GL_DestroyRenderer(SDL_Renderer * renderer);
slouken@1918
   112
slouken@1918
   113
slouken@1918
   114
SDL_RenderDriver GL_RenderDriver = {
slouken@1918
   115
    GL_CreateRenderer,
slouken@1918
   116
    {
slouken@1918
   117
     "opengl",
slouken@1974
   118
     (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD |
slouken@1974
   119
      SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
slouken@1985
   120
     (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
slouken@1985
   121
      SDL_TEXTUREMODULATE_ALPHA),
slouken@2884
   122
     (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK |
slouken@2884
   123
      SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
slouken@1965
   124
     (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST |
slouken@1965
   125
      SDL_TEXTURESCALEMODE_SLOW),
slouken@2813
   126
     15,
slouken@1918
   127
     {
slouken@1965
   128
      SDL_PIXELFORMAT_INDEX1LSB,
slouken@1965
   129
      SDL_PIXELFORMAT_INDEX1MSB,
slouken@1965
   130
      SDL_PIXELFORMAT_INDEX8,
slouken@1965
   131
      SDL_PIXELFORMAT_RGB332,
slouken@1965
   132
      SDL_PIXELFORMAT_RGB444,
slouken@1965
   133
      SDL_PIXELFORMAT_RGB555,
slouken@1965
   134
      SDL_PIXELFORMAT_ARGB4444,
slouken@1965
   135
      SDL_PIXELFORMAT_ARGB1555,
slouken@1965
   136
      SDL_PIXELFORMAT_RGB565,
slouken@1965
   137
      SDL_PIXELFORMAT_RGB24,
slouken@1965
   138
      SDL_PIXELFORMAT_BGR24,
slouken@1965
   139
      SDL_PIXELFORMAT_RGB888,
slouken@1965
   140
      SDL_PIXELFORMAT_BGR888,
slouken@1965
   141
      SDL_PIXELFORMAT_ARGB8888,
slouken@1965
   142
      SDL_PIXELFORMAT_ABGR8888,
slouken@2813
   143
      SDL_PIXELFORMAT_ARGB2101010},
slouken@1918
   144
     0,
slouken@1918
   145
     0}
slouken@1918
   146
};
slouken@1918
   147
slouken@1918
   148
typedef struct
slouken@1918
   149
{
slouken@1918
   150
    SDL_GLContext context;
slouken@2833
   151
    SDL_bool updateSize;
slouken@2233
   152
    SDL_bool GL_ARB_texture_rectangle_supported;
slouken@1974
   153
    SDL_bool GL_EXT_paletted_texture_supported;
slouken@2845
   154
    SDL_bool GL_APPLE_ycbcr_422_supported;
slouken@2845
   155
    SDL_bool GL_MESA_ycbcr_texture_supported;
icculus@2835
   156
    SDL_bool GL_ARB_fragment_program_supported;
slouken@1927
   157
    int blendMode;
slouken@1927
   158
    int scaleMode;
slouken@1927
   159
slouken@1927
   160
    /* OpenGL functions */
slouken@1927
   161
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
slouken@1927
   162
#include "SDL_glfuncs.h"
slouken@1927
   163
#undef SDL_PROC
slouken@1974
   164
slouken@1974
   165
    PFNGLCOLORTABLEEXTPROC glColorTableEXT;
slouken@2233
   166
    void (*glTextureRangeAPPLE) (GLenum target, GLsizei length,
slouken@2233
   167
                                 const GLvoid * pointer);
icculus@2835
   168
icculus@2835
   169
    PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
icculus@2835
   170
    PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
icculus@2835
   171
    PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
icculus@2835
   172
    PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
icculus@2835
   173
    PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
icculus@2835
   174
    PFNGLBINDPROGRAMARBPROC glBindProgramARB;
icculus@2835
   175
    PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
icculus@2835
   176
icculus@2835
   177
    /* (optional) fragment programs */
slouken@3468
   178
    GLuint fragment_program_mask;
icculus@2835
   179
    GLuint fragment_program_UYVY;
slouken@1918
   180
} GL_RenderData;
slouken@1918
   181
slouken@1918
   182
typedef struct
slouken@1918
   183
{
slouken@1918
   184
    GLuint texture;
icculus@2835
   185
    GLuint shader;
slouken@1920
   186
    GLenum type;
slouken@1918
   187
    GLfloat texw;
slouken@1918
   188
    GLfloat texh;
slouken@1920
   189
    GLenum format;
slouken@1920
   190
    GLenum formattype;
slouken@1974
   191
    Uint8 *palette;
slouken@1918
   192
    void *pixels;
slouken@1918
   193
    int pitch;
slouken@1920
   194
    SDL_DirtyRectList dirty;
slouken@2884
   195
    int HACK_RYAN_FIXME;
slouken@1918
   196
} GL_TextureData;
slouken@1918
   197
slouken@1918
   198
slouken@1924
   199
static void
slouken@1924
   200
GL_SetError(const char *prefix, GLenum result)
slouken@1924
   201
{
slouken@1924
   202
    const char *error;
slouken@1924
   203
slouken@1924
   204
    switch (result) {
slouken@1924
   205
    case GL_NO_ERROR:
slouken@1924
   206
        error = "GL_NO_ERROR";
slouken@1924
   207
        break;
slouken@1924
   208
    case GL_INVALID_ENUM:
slouken@1924
   209
        error = "GL_INVALID_ENUM";
slouken@1924
   210
        break;
slouken@1924
   211
    case GL_INVALID_VALUE:
slouken@1924
   212
        error = "GL_INVALID_VALUE";
slouken@1924
   213
        break;
slouken@1924
   214
    case GL_INVALID_OPERATION:
slouken@1924
   215
        error = "GL_INVALID_OPERATION";
slouken@1924
   216
        break;
slouken@1924
   217
    case GL_STACK_OVERFLOW:
slouken@1924
   218
        error = "GL_STACK_OVERFLOW";
slouken@1924
   219
        break;
slouken@1924
   220
    case GL_STACK_UNDERFLOW:
slouken@1924
   221
        error = "GL_STACK_UNDERFLOW";
slouken@1924
   222
        break;
slouken@1924
   223
    case GL_OUT_OF_MEMORY:
slouken@1924
   224
        error = "GL_OUT_OF_MEMORY";
slouken@1924
   225
        break;
slouken@1924
   226
    case GL_TABLE_TOO_LARGE:
slouken@1924
   227
        error = "GL_TABLE_TOO_LARGE";
slouken@1924
   228
        break;
slouken@1924
   229
    default:
slouken@1924
   230
        error = "UNKNOWN";
slouken@1924
   231
        break;
slouken@1924
   232
    }
slouken@1924
   233
    SDL_SetError("%s: %s", prefix, error);
slouken@1924
   234
}
slouken@1924
   235
slouken@1927
   236
static int
slouken@1927
   237
GL_LoadFunctions(GL_RenderData * data)
slouken@1927
   238
{
slouken@1927
   239
#if defined(__QNXNTO__) && (_NTO_VERSION < 630)
slouken@1927
   240
#define __SDL_NOGETPROCADDR__
slouken@1927
   241
#endif
slouken@1927
   242
#ifdef __SDL_NOGETPROCADDR__
slouken@1927
   243
#define SDL_PROC(ret,func,params) data->func=func;
slouken@1927
   244
#else
slouken@1927
   245
#define SDL_PROC(ret,func,params) \
slouken@1927
   246
    do { \
slouken@1927
   247
        data->func = SDL_GL_GetProcAddress(#func); \
slouken@1927
   248
        if ( ! data->func ) { \
slouken@1927
   249
            SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
slouken@1927
   250
            return -1; \
slouken@1927
   251
        } \
slouken@1927
   252
    } while ( 0 );
slouken@1927
   253
#endif /* __SDL_NOGETPROCADDR__ */
slouken@1927
   254
slouken@1927
   255
#include "SDL_glfuncs.h"
slouken@1927
   256
#undef SDL_PROC
slouken@1927
   257
    return 0;
slouken@1927
   258
}
slouken@1927
   259
slouken@1918
   260
void
slouken@1918
   261
GL_AddRenderDriver(_THIS)
slouken@1918
   262
{
slouken@1920
   263
    if (_this->GL_CreateContext) {
slouken@1918
   264
        SDL_AddRenderDriver(0, &GL_RenderDriver);
slouken@1918
   265
    }
slouken@1918
   266
}
slouken@1918
   267
slouken@1918
   268
SDL_Renderer *
slouken@1918
   269
GL_CreateRenderer(SDL_Window * window, Uint32 flags)
slouken@1918
   270
{
slouken@1918
   271
    SDL_Renderer *renderer;
slouken@1918
   272
    GL_RenderData *data;
slouken@1952
   273
    GLint value;
slouken@1974
   274
    int doublebuffer;
slouken@1918
   275
slouken@1974
   276
    /* Render directly to the window, unless we're compositing */
slouken@1974
   277
#ifndef __MACOSX__
slouken@1974
   278
    if (flags & SDL_RENDERER_SINGLEBUFFER) {
slouken@1974
   279
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
slouken@1974
   280
    }
slouken@1974
   281
#endif
slouken@1918
   282
    if (!(window->flags & SDL_WINDOW_OPENGL)) {
slouken@1928
   283
        if (SDL_RecreateWindow(window, window->flags | SDL_WINDOW_OPENGL) < 0) {
slouken@1924
   284
            return NULL;
slouken@1924
   285
        }
slouken@1918
   286
    }
slouken@1918
   287
slouken@1920
   288
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
slouken@1918
   289
    if (!renderer) {
slouken@1918
   290
        SDL_OutOfMemory();
slouken@1918
   291
        return NULL;
slouken@1918
   292
    }
slouken@1918
   293
slouken@1920
   294
    data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
slouken@1918
   295
    if (!data) {
slouken@1918
   296
        GL_DestroyRenderer(renderer);
slouken@1918
   297
        SDL_OutOfMemory();
slouken@1918
   298
        return NULL;
slouken@1918
   299
    }
slouken@1918
   300
slouken@1923
   301
    renderer->ActivateRenderer = GL_ActivateRenderer;
slouken@1970
   302
    renderer->DisplayModeChanged = GL_DisplayModeChanged;
slouken@1918
   303
    renderer->CreateTexture = GL_CreateTexture;
slouken@2222
   304
    renderer->QueryTexturePixels = GL_QueryTexturePixels;
slouken@1918
   305
    renderer->SetTexturePalette = GL_SetTexturePalette;
slouken@1918
   306
    renderer->GetTexturePalette = GL_GetTexturePalette;
slouken@1985
   307
    renderer->SetTextureColorMod = GL_SetTextureColorMod;
slouken@1985
   308
    renderer->SetTextureAlphaMod = GL_SetTextureAlphaMod;
slouken@1985
   309
    renderer->SetTextureBlendMode = GL_SetTextureBlendMode;
slouken@1985
   310
    renderer->SetTextureScaleMode = GL_SetTextureScaleMode;
slouken@1918
   311
    renderer->UpdateTexture = GL_UpdateTexture;
slouken@1918
   312
    renderer->LockTexture = GL_LockTexture;
slouken@1918
   313
    renderer->UnlockTexture = GL_UnlockTexture;
slouken@1918
   314
    renderer->DirtyTexture = GL_DirtyTexture;
slouken@2901
   315
    renderer->RenderPoint = GL_RenderPoint;
slouken@2884
   316
    renderer->RenderLine = GL_RenderLine;
slouken@1918
   317
    renderer->RenderFill = GL_RenderFill;
slouken@1918
   318
    renderer->RenderCopy = GL_RenderCopy;
slouken@3431
   319
    renderer->RenderReadPixels = GL_RenderReadPixels;
slouken@3431
   320
    renderer->RenderWritePixels = GL_RenderWritePixels;
slouken@1918
   321
    renderer->RenderPresent = GL_RenderPresent;
slouken@1918
   322
    renderer->DestroyTexture = GL_DestroyTexture;
slouken@1918
   323
    renderer->DestroyRenderer = GL_DestroyRenderer;
slouken@1918
   324
    renderer->info = GL_RenderDriver.info;
slouken@1918
   325
    renderer->window = window->id;
slouken@1918
   326
    renderer->driverdata = data;
slouken@1918
   327
slouken@1918
   328
    renderer->info.flags =
slouken@1965
   329
        (SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED);
slouken@1918
   330
slouken@1927
   331
    if (GL_LoadFunctions(data) < 0) {
slouken@1927
   332
        GL_DestroyRenderer(renderer);
slouken@1927
   333
        return NULL;
slouken@1927
   334
    }
slouken@1927
   335
slouken@1918
   336
    data->context = SDL_GL_CreateContext(window->id);
slouken@1918
   337
    if (!data->context) {
slouken@1918
   338
        GL_DestroyRenderer(renderer);
slouken@1918
   339
        return NULL;
slouken@1918
   340
    }
slouken@1918
   341
    if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
slouken@1918
   342
        GL_DestroyRenderer(renderer);
slouken@1918
   343
        return NULL;
slouken@1918
   344
    }
slouken@2246
   345
#ifdef __MACOSX__
slouken@2246
   346
    /* Enable multi-threaded rendering */
slouken@2246
   347
    /* Disabled until Ryan finishes his VBO/PBO code...
bob@2295
   348
       CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
bob@2295
   349
     */
slouken@2246
   350
#endif
slouken@2246
   351
slouken@1965
   352
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
slouken@1918
   353
        SDL_GL_SetSwapInterval(1);
slouken@1918
   354
    } else {
slouken@1918
   355
        SDL_GL_SetSwapInterval(0);
slouken@1918
   356
    }
slouken@1918
   357
    if (SDL_GL_GetSwapInterval() > 0) {
slouken@1965
   358
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@1918
   359
    }
slouken@1918
   360
slouken@1974
   361
    if (SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doublebuffer) == 0) {
slouken@1974
   362
        if (!doublebuffer) {
slouken@1974
   363
            renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER;
slouken@1974
   364
        }
slouken@1974
   365
    }
slouken@1974
   366
slouken@1952
   367
    data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
slouken@1952
   368
    renderer->info.max_texture_width = value;
slouken@1952
   369
    data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
slouken@1952
   370
    renderer->info.max_texture_height = value;
slouken@1920
   371
slouken@1926
   372
    if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
slouken@1926
   373
        || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
slouken@1926
   374
        data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
slouken@1926
   375
    }
slouken@1974
   376
    if (SDL_GL_ExtensionSupported("GL_EXT_paletted_texture")) {
slouken@1974
   377
        data->GL_EXT_paletted_texture_supported = SDL_TRUE;
slouken@1974
   378
        data->glColorTableEXT =
slouken@1974
   379
            (PFNGLCOLORTABLEEXTPROC) SDL_GL_GetProcAddress("glColorTableEXT");
slouken@1974
   380
    } else {
slouken@1974
   381
        /* Don't advertise support for 8-bit indexed texture format */
slouken@1974
   382
        Uint32 i, j;
slouken@1974
   383
        SDL_RendererInfo *info = &renderer->info;
slouken@1974
   384
        for (i = 0, j = 0; i < info->num_texture_formats; ++i) {
slouken@1974
   385
            if (info->texture_formats[i] != SDL_PIXELFORMAT_INDEX8) {
slouken@1974
   386
                info->texture_formats[j++] = info->texture_formats[i];
slouken@1974
   387
            }
slouken@1974
   388
        }
slouken@1974
   389
        --info->num_texture_formats;
slouken@1974
   390
    }
slouken@2845
   391
    if (SDL_GL_ExtensionSupported("GL_APPLE_ycbcr_422")) {
slouken@2845
   392
        data->GL_APPLE_ycbcr_422_supported = SDL_TRUE;
slouken@2845
   393
    }
slouken@2845
   394
    if (SDL_GL_ExtensionSupported("GL_MESA_ycbcr_texture")) {
slouken@2845
   395
        data->GL_MESA_ycbcr_texture_supported = SDL_TRUE;
slouken@2845
   396
    }
slouken@2233
   397
    if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) {
slouken@2233
   398
        data->glTextureRangeAPPLE =
slouken@2233
   399
            (void (*)(GLenum, GLsizei, const GLvoid *))
slouken@2233
   400
            SDL_GL_GetProcAddress("glTextureRangeAPPLE");
slouken@2233
   401
    }
slouken@1920
   402
icculus@2835
   403
    /* we might use fragment programs for YUV data, etc. */
icculus@2835
   404
    if (SDL_GL_ExtensionSupported("GL_ARB_fragment_program")) {
icculus@2835
   405
        /* !!! FIXME: this doesn't check for errors. */
icculus@2835
   406
        /* !!! FIXME: this should really reuse the glfuncs.h stuff. */
icculus@2835
   407
        data->glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)
icculus@2835
   408
            SDL_GL_GetProcAddress("glGetProgramivARB");
icculus@2835
   409
        data->glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)
icculus@2835
   410
            SDL_GL_GetProcAddress("glGetProgramStringARB");
icculus@2835
   411
        data->glProgramLocalParameter4fvARB =
icculus@2835
   412
            (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)
icculus@2835
   413
            SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB");
icculus@2835
   414
        data->glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)
icculus@2835
   415
            SDL_GL_GetProcAddress("glDeleteProgramsARB");
icculus@2835
   416
        data->glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)
icculus@2835
   417
            SDL_GL_GetProcAddress("glGenProgramsARB");
icculus@2835
   418
        data->glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)
icculus@2835
   419
            SDL_GL_GetProcAddress("glBindProgramARB");
icculus@2835
   420
        data->glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)
icculus@2835
   421
            SDL_GL_GetProcAddress("glProgramStringARB");
icculus@2835
   422
        data->GL_ARB_fragment_program_supported = SDL_TRUE;
icculus@2835
   423
    }
icculus@2835
   424
slouken@1918
   425
    /* Set up parameters for rendering */
slouken@1927
   426
    data->blendMode = -1;
slouken@1927
   427
    data->scaleMode = -1;
slouken@1927
   428
    data->glDisable(GL_DEPTH_TEST);
slouken@1927
   429
    data->glDisable(GL_CULL_FACE);
slouken@3262
   430
    /* This ended up causing video discrepancies between OpenGL and Direct3D */
slouken@3262
   431
    /*data->glEnable(GL_LINE_SMOOTH);*/
slouken@1926
   432
    if (data->GL_ARB_texture_rectangle_supported) {
slouken@1927
   433
        data->glEnable(GL_TEXTURE_RECTANGLE_ARB);
slouken@1926
   434
    } else {
slouken@1927
   435
        data->glEnable(GL_TEXTURE_2D);
slouken@1926
   436
    }
slouken@2833
   437
    data->updateSize = SDL_TRUE;
slouken@1918
   438
slouken@1918
   439
    return renderer;
slouken@1918
   440
}
slouken@1918
   441
slouken@1923
   442
static int
slouken@1923
   443
GL_ActivateRenderer(SDL_Renderer * renderer)
slouken@1923
   444
{
slouken@1923
   445
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1923
   446
    SDL_Window *window = SDL_GetWindowFromID(renderer->window);
slouken@1923
   447
slouken@1970
   448
    if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
slouken@1970
   449
        return -1;
slouken@1970
   450
    }
slouken@2833
   451
    if (data->updateSize) {
slouken@2836
   452
        data->glMatrixMode(GL_PROJECTION);
slouken@2836
   453
        data->glLoadIdentity();
slouken@2836
   454
        data->glMatrixMode(GL_MODELVIEW);
slouken@2836
   455
        data->glLoadIdentity();
slouken@2836
   456
        data->glViewport(0, 0, window->w, window->h);
slouken@3324
   457
        data->glOrtho(0.0, (GLdouble) window->w,
slouken@3324
   458
                      (GLdouble) window->h, 0.0, 0.0, 1.0);
slouken@2833
   459
        data->updateSize = SDL_FALSE;
slouken@2833
   460
    }
slouken@1970
   461
    return 0;
slouken@1970
   462
}
slouken@1970
   463
slouken@1970
   464
static int
slouken@1970
   465
GL_DisplayModeChanged(SDL_Renderer * renderer)
slouken@1970
   466
{
slouken@1970
   467
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1970
   468
slouken@2836
   469
    /* Rebind the context to the window area and update matrices */
slouken@2836
   470
    data->updateSize = SDL_TRUE;
slouken@2836
   471
    return GL_ActivateRenderer(renderer);
slouken@1923
   472
}
slouken@1923
   473
slouken@1922
   474
static __inline__ int
slouken@1922
   475
power_of_2(int input)
slouken@1922
   476
{
slouken@1922
   477
    int value = 1;
slouken@1922
   478
slouken@1922
   479
    while (value < input) {
slouken@1922
   480
        value <<= 1;
slouken@1922
   481
    }
slouken@1922
   482
    return value;
slouken@1922
   483
}
slouken@1922
   484
icculus@2835
   485
slouken@2858
   486
//#define DEBUG_PROGRAM_COMPILE 1
icculus@2835
   487
slouken@3468
   488
static void
slouken@3468
   489
set_shader_error(GL_RenderData * data, const char *prefix)
slouken@3468
   490
{
slouken@3468
   491
    GLint pos = 0;
slouken@3468
   492
    const GLubyte *errstr;
slouken@3468
   493
    data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
slouken@3468
   494
    errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
slouken@3468
   495
    printf("%s: shader compile error at position %d: %s",
slouken@3468
   496
           prefix, (int) pos, (const char *) errstr);
slouken@3468
   497
}
slouken@3468
   498
icculus@2835
   499
static GLuint
slouken@2884
   500
compile_shader(GL_RenderData * data, GLenum shader_type, const char *_code)
icculus@2835
   501
{
icculus@2847
   502
    const int have_texture_rects = data->GL_ARB_texture_rectangle_supported;
icculus@2847
   503
    const char *replacement = have_texture_rects ? "RECT" : "2D";
slouken@2918
   504
    const size_t replacementlen = SDL_strlen(replacement);
icculus@2847
   505
    const char *token = "%TEXTURETARGET%";
slouken@2918
   506
    const size_t tokenlen = SDL_strlen(token);
icculus@2847
   507
    char *code = NULL;
icculus@2847
   508
    char *ptr = NULL;
icculus@2847
   509
    GLuint program = 0;
icculus@2847
   510
icculus@2847
   511
    /*
icculus@2847
   512
     * The TEX instruction needs a different target depending on what we use.
icculus@2847
   513
     *  To handle this, we use "%TEXTURETARGET%" and replace the string before
icculus@2847
   514
     *  compiling the shader.
icculus@2847
   515
     */
icculus@2847
   516
    code = SDL_strdup(_code);
icculus@2847
   517
    if (code == NULL)
icculus@2847
   518
        return 0;
icculus@2847
   519
slouken@2884
   520
    for (ptr = SDL_strstr(code, token); ptr; ptr = SDL_strstr(ptr + 1, token)) {
slouken@2918
   521
        SDL_memcpy(ptr, replacement, replacementlen);
slouken@2918
   522
        SDL_memmove(ptr + replacementlen, ptr + tokenlen,
slouken@2918
   523
                    SDL_strlen(ptr + tokenlen) + 1);
icculus@2847
   524
    }
icculus@2847
   525
icculus@2835
   526
#if DEBUG_PROGRAM_COMPILE
icculus@2847
   527
    printf("compiling shader:\n%s\n\n", code);
icculus@2835
   528
#endif
icculus@2835
   529
slouken@2884
   530
    data->glGetError();         /* flush any existing error state. */
icculus@2835
   531
    data->glGenProgramsARB(1, &program);
icculus@2835
   532
    data->glBindProgramARB(shader_type, program);
icculus@2835
   533
    data->glProgramStringARB(shader_type, GL_PROGRAM_FORMAT_ASCII_ARB,
slouken@3253
   534
                             (GLsizei)SDL_strlen(code), code);
icculus@2847
   535
icculus@2847
   536
    SDL_free(code);
icculus@2835
   537
slouken@2884
   538
    if (data->glGetError() == GL_INVALID_OPERATION) {
icculus@2835
   539
#if DEBUG_PROGRAM_COMPILE
icculus@2835
   540
        GLint pos = 0;
icculus@2835
   541
        const GLubyte *errstr;
icculus@2835
   542
        data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
icculus@2835
   543
        errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
icculus@2835
   544
        printf("program compile error at position %d: %s\n\n",
slouken@2884
   545
               (int) pos, (const char *) errstr);
icculus@2835
   546
#endif
icculus@2835
   547
        data->glBindProgramARB(shader_type, 0);
icculus@2835
   548
        data->glDeleteProgramsARB(1, &program);
icculus@2835
   549
        return 0;
icculus@2848
   550
    }
icculus@2835
   551
icculus@2835
   552
    return program;
icculus@2835
   553
}
icculus@2835
   554
icculus@2848
   555
icculus@2848
   556
/*
slouken@3468
   557
 * Fragment program that implements mask semantics
slouken@3468
   558
 */
slouken@3468
   559
static const char *fragment_program_mask_source_code = "!!ARBfp1.0\n"
slouken@3468
   560
"OUTPUT output = result.color;\n"
slouken@3468
   561
"TEMP value;\n"
slouken@3468
   562
"TEX value, fragment.texcoord[0], texture[0], %TEXTURETARGET%;\n"
slouken@3468
   563
"MUL value, fragment.color, value;\n"
slouken@3468
   564
"SGE value.a, value.a, 0.001;\n"
slouken@3468
   565
"MOV output, value;\n"
slouken@3468
   566
"END";
slouken@3468
   567
slouken@3468
   568
/*
icculus@2848
   569
 * Fragment program that renders from UYVY textures.
icculus@2848
   570
 * The UYVY to RGB equasion is:
icculus@2848
   571
 *   R = 1.164(Y-16) + 1.596(Cr-128)
icculus@2848
   572
 *   G = 1.164(Y-16) - 0.813(Cr-128) - 0.391(Cb-128)
icculus@2848
   573
 *   B = 1.164(Y-16) + 2.018(Cb-128)
icculus@2848
   574
 * Byte layout is Cb, Y1, Cr, Y2, stored in the R, G, B, A channels.
icculus@2848
   575
 * 4 bytes == 2 pixels: Y1/Cb/Cr, Y2/Cb/Cr
icculus@2848
   576
 *
icculus@2848
   577
 * !!! FIXME: this ignores blendmodes, etc.
icculus@2848
   578
 * !!! FIXME: this could be more efficient...use a dot product for green, etc.
icculus@2848
   579
 */
slouken@2884
   580
static const char *fragment_program_UYVY_source_code = "!!ARBfp1.0\n"
icculus@2848
   581
    /* outputs... */
icculus@2835
   582
    "OUTPUT outcolor = result.color;\n"
icculus@2848
   583
    /* scratch registers... */
slouken@2884
   584
    "TEMP uyvy;\n" "TEMP luminance;\n" "TEMP work;\n"
icculus@2848
   585
    /* Halve the coordinates to grab the correct 32 bits for the fragment. */
icculus@2835
   586
    "MUL work, fragment.texcoord, { 0.5, 1.0, 1.0, 1.0 };\n"
icculus@2848
   587
    /* Sample the YUV texture. Cb, Y1, Cr, Y2, are stored in x, y, z, w. */
icculus@2847
   588
    "TEX uyvy, work, texture[0], %TEXTURETARGET%;\n"
icculus@2848
   589
    /* Do subtractions (128/255, 16/255, 128/255, 16/255) */
slouken@2846
   590
    "SUB uyvy, uyvy, { 0.501960784313726, 0.06274509803922, 0.501960784313726, 0.06274509803922 };\n"
icculus@2848
   591
    /* Choose the luminance component by texcoord. */
icculus@2848
   592
    /* !!! FIXME: laziness wins out for now... just average Y1 and Y2. */
icculus@2835
   593
    "ADD luminance, uyvy.yyyy, uyvy.wwww;\n"
icculus@2835
   594
    "MUL luminance, luminance, { 0.5, 0.5, 0.5, 0.5 };\n"
icculus@2848
   595
    /* Multiply luminance by its magic value. */
icculus@2835
   596
    "MUL luminance, luminance, { 1.164, 1.164, 1.164, 1.164 };\n"
icculus@2848
   597
    /* uyvy.xyzw becomes Cr/Cr/Cb/Cb, with multiplications. */
icculus@2835
   598
    "MUL uyvy, uyvy.zzxx, { 1.596, -0.813, 2.018, -0.391 };\n"
icculus@2848
   599
    /* Add luminance to Cr and Cb, store to RGB channels. */
icculus@2835
   600
    "ADD work.rgb, luminance, uyvy;\n"
icculus@2848
   601
    /* Do final addition for Green channel.  (!!! FIXME: this should be a DPH?) */
icculus@2835
   602
    "ADD work.g, work.g, uyvy.w;\n"
icculus@2848
   603
    /* Make sure alpha channel is fully opaque.  (!!! FIXME: blend modes!) */
icculus@2835
   604
    "MOV work.a, { 1.0 };\n"
icculus@2848
   605
    /* Store out the final fragment color... */
icculus@2835
   606
    "MOV outcolor, work;\n"
icculus@2848
   607
    /* ...and we're done! */
icculus@2835
   608
    "END\n";
icculus@2835
   609
slouken@3433
   610
static __inline__ SDL_bool
slouken@3433
   611
convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
slouken@3433
   612
               GLint* internalFormat, GLenum* format, GLenum* type)
slouken@3433
   613
{
slouken@3433
   614
    switch (pixel_format) {
slouken@3433
   615
    case SDL_PIXELFORMAT_INDEX1LSB:
slouken@3433
   616
    case SDL_PIXELFORMAT_INDEX1MSB:
slouken@3433
   617
        *internalFormat = GL_RGB;
slouken@3433
   618
        *format = GL_COLOR_INDEX;
slouken@3433
   619
        *type = GL_BITMAP;
slouken@3433
   620
        break;
slouken@3433
   621
    case SDL_PIXELFORMAT_INDEX8:
slouken@3433
   622
        if (!renderdata->GL_EXT_paletted_texture_supported) {
slouken@3433
   623
            return SDL_FALSE;
slouken@3433
   624
        }
slouken@3433
   625
        *internalFormat = GL_COLOR_INDEX8_EXT;
slouken@3433
   626
        *format = GL_COLOR_INDEX;
slouken@3433
   627
        *type = GL_UNSIGNED_BYTE;
slouken@3433
   628
        break;
slouken@3433
   629
    case SDL_PIXELFORMAT_RGB332:
slouken@3433
   630
        *internalFormat = GL_R3_G3_B2;
slouken@3433
   631
        *format = GL_RGB;
slouken@3433
   632
        *type = GL_UNSIGNED_BYTE_3_3_2;
slouken@3433
   633
        break;
slouken@3433
   634
    case SDL_PIXELFORMAT_RGB444:
slouken@3433
   635
        *internalFormat = GL_RGB4;
slouken@3433
   636
        *format = GL_RGB;
slouken@3433
   637
        *type = GL_UNSIGNED_SHORT_4_4_4_4;
slouken@3433
   638
        break;
slouken@3433
   639
    case SDL_PIXELFORMAT_RGB555:
slouken@3433
   640
        *internalFormat = GL_RGB5;
slouken@3433
   641
        *format = GL_RGB;
slouken@3433
   642
        *type = GL_UNSIGNED_SHORT_5_5_5_1;
slouken@3433
   643
        break;
slouken@3433
   644
    case SDL_PIXELFORMAT_ARGB4444:
slouken@3433
   645
        *internalFormat = GL_RGBA4;
slouken@3433
   646
        *format = GL_BGRA;
slouken@3433
   647
        *type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
slouken@3433
   648
        break;
slouken@3433
   649
    case SDL_PIXELFORMAT_ARGB1555:
slouken@3433
   650
        *internalFormat = GL_RGB5_A1;
slouken@3433
   651
        *format = GL_BGRA;
slouken@3433
   652
        *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
slouken@3433
   653
        break;
slouken@3433
   654
    case SDL_PIXELFORMAT_RGB565:
slouken@3433
   655
        *internalFormat = GL_RGB8;
slouken@3433
   656
        *format = GL_RGB;
slouken@3433
   657
        *type = GL_UNSIGNED_SHORT_5_6_5;
slouken@3433
   658
        break;
slouken@3433
   659
    case SDL_PIXELFORMAT_RGB24:
slouken@3433
   660
        *internalFormat = GL_RGB8;
slouken@3433
   661
        *format = GL_RGB;
slouken@3433
   662
        *type = GL_UNSIGNED_BYTE;
slouken@3433
   663
        break;
slouken@3433
   664
    case SDL_PIXELFORMAT_RGB888:
slouken@3433
   665
        *internalFormat = GL_RGB8;
slouken@3433
   666
        *format = GL_BGRA;
slouken@3433
   667
        *type = GL_UNSIGNED_BYTE;
slouken@3433
   668
        break;
slouken@3433
   669
    case SDL_PIXELFORMAT_BGR24:
slouken@3433
   670
        *internalFormat = GL_RGB8;
slouken@3433
   671
        *format = GL_BGR;
slouken@3433
   672
        *type = GL_UNSIGNED_BYTE;
slouken@3433
   673
        break;
slouken@3433
   674
    case SDL_PIXELFORMAT_BGR888:
slouken@3433
   675
        *internalFormat = GL_RGB8;
slouken@3433
   676
        *format = GL_RGBA;
slouken@3433
   677
        *type = GL_UNSIGNED_BYTE;
slouken@3433
   678
        break;
slouken@3433
   679
    case SDL_PIXELFORMAT_ARGB8888:
slouken@3433
   680
#ifdef __MACOSX__
slouken@3433
   681
        *internalFormat = GL_RGBA;
slouken@3433
   682
        *format = GL_BGRA;
slouken@3433
   683
        *type = GL_UNSIGNED_INT_8_8_8_8_REV;
slouken@3433
   684
#else
slouken@3433
   685
        *internalFormat = GL_RGBA8;
slouken@3433
   686
        *format = GL_BGRA;
slouken@3433
   687
        *type = GL_UNSIGNED_BYTE;
slouken@3433
   688
#endif
slouken@3433
   689
        break;
slouken@3433
   690
    case SDL_PIXELFORMAT_ABGR8888:
slouken@3433
   691
        *internalFormat = GL_RGBA8;
slouken@3433
   692
        *format = GL_RGBA;
slouken@3433
   693
        *type = GL_UNSIGNED_BYTE;
slouken@3433
   694
        break;
slouken@3433
   695
    case SDL_PIXELFORMAT_ARGB2101010:
slouken@3433
   696
        *internalFormat = GL_RGB10_A2;
slouken@3433
   697
        *format = GL_BGRA;
slouken@3433
   698
        *type = GL_UNSIGNED_INT_2_10_10_10_REV;
slouken@3433
   699
        break;
slouken@3433
   700
    case SDL_PIXELFORMAT_UYVY:
slouken@3433
   701
        if (renderdata->GL_APPLE_ycbcr_422_supported) {
slouken@3433
   702
            *internalFormat = GL_RGB;
slouken@3433
   703
            *format = GL_YCBCR_422_APPLE;
slouken@3433
   704
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
slouken@3433
   705
            *type = GL_UNSIGNED_SHORT_8_8_APPLE;
slouken@3433
   706
#else
slouken@3433
   707
            *type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
slouken@3433
   708
#endif
slouken@3433
   709
        } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
slouken@3433
   710
            *internalFormat = GL_RGB;
slouken@3433
   711
            *format = GL_YCBCR_MESA;
slouken@3433
   712
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
slouken@3433
   713
            *type = GL_UNSIGNED_SHORT_8_8_MESA;
slouken@3433
   714
#else
slouken@3433
   715
            *type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
slouken@3433
   716
#endif
slouken@3433
   717
        } else if (renderdata->GL_ARB_fragment_program_supported) {
slouken@3433
   718
            *internalFormat = GL_RGBA;
slouken@3433
   719
            *format = GL_RGBA;
slouken@3433
   720
            *type = GL_UNSIGNED_BYTE;
slouken@3433
   721
        } else {
slouken@3433
   722
            return SDL_FALSE;
slouken@3433
   723
        }
slouken@3433
   724
        break;
slouken@3433
   725
    case SDL_PIXELFORMAT_YUY2:
slouken@3433
   726
        if (renderdata->GL_APPLE_ycbcr_422_supported) {
slouken@3433
   727
            *internalFormat = GL_RGB;
slouken@3433
   728
            *format = GL_YCBCR_422_APPLE;
slouken@3433
   729
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
slouken@3433
   730
            *type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
slouken@3433
   731
#else
slouken@3433
   732
            *type = GL_UNSIGNED_SHORT_8_8_APPLE;
slouken@3433
   733
#endif
slouken@3433
   734
        } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
slouken@3433
   735
            *internalFormat = GL_RGB;
slouken@3433
   736
            *format = GL_YCBCR_MESA;
slouken@3433
   737
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
slouken@3433
   738
            *type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
slouken@3433
   739
#else
slouken@3433
   740
            *type = GL_UNSIGNED_SHORT_8_8_MESA;
slouken@3433
   741
#endif
slouken@3433
   742
        } else {
slouken@3433
   743
            return SDL_FALSE;
slouken@3433
   744
        }
slouken@3433
   745
        break;
slouken@3433
   746
    default:
slouken@3433
   747
        return SDL_FALSE;
slouken@3433
   748
    }
slouken@3433
   749
    return SDL_TRUE;
slouken@3433
   750
}
icculus@2835
   751
slouken@1918
   752
static int
slouken@1918
   753
GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
   754
{
slouken@1918
   755
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
   756
    SDL_Window *window = SDL_GetWindowFromID(renderer->window);
slouken@1918
   757
    GL_TextureData *data;
slouken@1920
   758
    GLint internalFormat;
slouken@1920
   759
    GLenum format, type;
slouken@1922
   760
    int texture_w, texture_h;
icculus@2835
   761
    GLuint shader = 0;
slouken@1924
   762
    GLenum result;
slouken@1918
   763
slouken@3433
   764
    if (!convert_format(renderdata, texture->format, &internalFormat,
slouken@3433
   765
                        &format, &type)) {
slouken@1920
   766
        SDL_SetError("Unsupported texture format");
slouken@1920
   767
        return -1;
slouken@1920
   768
    }
slouken@3433
   769
    if (texture->format == SDL_PIXELFORMAT_UYVY &&
slouken@3433
   770
        !renderdata->GL_APPLE_ycbcr_422_supported &&
slouken@3433
   771
        !renderdata->GL_MESA_ycbcr_texture_supported &&
slouken@3433
   772
        renderdata->GL_ARB_fragment_program_supported) {
slouken@3433
   773
        if (renderdata->fragment_program_UYVY == 0) {
slouken@3433
   774
            renderdata->fragment_program_UYVY =
slouken@3433
   775
                compile_shader(renderdata, GL_FRAGMENT_PROGRAM_ARB,
slouken@3433
   776
                               fragment_program_UYVY_source_code);
slouken@3433
   777
            if (renderdata->fragment_program_UYVY == 0) {
slouken@3468
   778
                set_shader_error(renderdata, "UYVY");
slouken@3433
   779
                return -1;
slouken@3433
   780
            }
slouken@3433
   781
        }
slouken@3433
   782
        shader = renderdata->fragment_program_UYVY;
slouken@3433
   783
    }
slouken@1920
   784
slouken@1920
   785
    data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
slouken@1918
   786
    if (!data) {
slouken@1918
   787
        SDL_OutOfMemory();
slouken@1918
   788
        return -1;
slouken@1918
   789
    }
slouken@1918
   790
icculus@2835
   791
    data->shader = shader;
icculus@2835
   792
slouken@1974
   793
    if (texture->format == SDL_PIXELFORMAT_INDEX8) {
slouken@1974
   794
        data->palette = (Uint8 *) SDL_malloc(3 * 256 * sizeof(Uint8));
slouken@1974
   795
        if (!data->palette) {
slouken@1974
   796
            SDL_OutOfMemory();
slouken@1974
   797
            SDL_free(data);
slouken@1974
   798
            return -1;
slouken@1974
   799
        }
slouken@1974
   800
        SDL_memset(data->palette, 0xFF, 3 * 256 * sizeof(Uint8));
slouken@1974
   801
    }
slouken@1974
   802
slouken@2222
   803
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
icculus@2835
   804
        data->pitch = texture->w * bytes_per_pixel(texture->format);
slouken@2222
   805
        data->pixels = SDL_malloc(texture->h * data->pitch);
slouken@2222
   806
        if (!data->pixels) {
slouken@2222
   807
            SDL_OutOfMemory();
slouken@2222
   808
            SDL_free(data);
slouken@2222
   809
            return -1;
slouken@2222
   810
        }
slouken@2222
   811
    }
slouken@2222
   812
slouken@1918
   813
    texture->driverdata = data;
slouken@1918
   814
slouken@1927
   815
    renderdata->glGetError();
slouken@1927
   816
    renderdata->glGenTextures(1, &data->texture);
slouken@1926
   817
    if (renderdata->GL_ARB_texture_rectangle_supported) {
slouken@1926
   818
        data->type = GL_TEXTURE_RECTANGLE_ARB;
slouken@1926
   819
        texture_w = texture->w;
slouken@1926
   820
        texture_h = texture->h;
icculus@2835
   821
        data->texw = (GLfloat) texture_w;
icculus@2835
   822
        data->texh = (GLfloat) texture_h;
slouken@1926
   823
    } else {
slouken@1926
   824
        data->type = GL_TEXTURE_2D;
slouken@1926
   825
        texture_w = power_of_2(texture->w);
slouken@1926
   826
        texture_h = power_of_2(texture->h);
icculus@2835
   827
        data->texw = (GLfloat) (texture->w) / texture_w;
slouken@1926
   828
        data->texh = (GLfloat) texture->h / texture_h;
slouken@1926
   829
    }
icculus@2835
   830
slouken@2839
   831
    /* YUV formats use RGBA but are really two bytes per pixel */
slouken@2839
   832
    if (internalFormat == GL_RGBA && bytes_per_pixel(texture->format) < 4) {
slouken@2884
   833
        data->HACK_RYAN_FIXME = 2;
slouken@2843
   834
    } else {
slouken@2884
   835
        data->HACK_RYAN_FIXME = 1;
slouken@2839
   836
    }
slouken@2843
   837
    texture_w /= data->HACK_RYAN_FIXME;
slouken@2839
   838
slouken@1920
   839
    data->format = format;
slouken@1920
   840
    data->formattype = type;
slouken@2884
   841
    renderdata->glEnable(data->type);
slouken@1927
   842
    renderdata->glBindTexture(data->type, data->texture);
slouken@2230
   843
    renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
slouken@2230
   844
                                GL_NEAREST);
slouken@2230
   845
    renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
slouken@2230
   846
                                GL_NEAREST);
slouken@2230
   847
    renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
slouken@2230
   848
                                GL_CLAMP_TO_EDGE);
slouken@2230
   849
    renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
slouken@2230
   850
                                GL_CLAMP_TO_EDGE);
slouken@2840
   851
#ifdef __MACOSX__
slouken@2230
   852
#ifndef GL_TEXTURE_STORAGE_HINT_APPLE
slouken@2230
   853
#define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
slouken@2230
   854
#endif
slouken@2230
   855
#ifndef STORAGE_CACHED_APPLE
slouken@2230
   856
#define STORAGE_CACHED_APPLE                0x85BE
slouken@2230
   857
#endif
slouken@2230
   858
#ifndef STORAGE_SHARED_APPLE
slouken@2230
   859
#define STORAGE_SHARED_APPLE                0x85BF
slouken@2230
   860
#endif
slouken@2230
   861
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@2230
   862
        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
slouken@2230
   863
                                    GL_STORAGE_SHARED_APPLE);
slouken@2230
   864
    } else {
slouken@2230
   865
        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
slouken@2230
   866
                                    GL_STORAGE_CACHED_APPLE);
slouken@2230
   867
    }
slouken@2809
   868
/* This causes a crash in testoverlay for some reason.  Apple bug? */
slouken@2809
   869
#if 0
bob@2295
   870
    if (texture->access == SDL_TEXTUREACCESS_STREAMING
bob@2295
   871
        && texture->format == SDL_PIXELFORMAT_ARGB8888) {
slouken@2237
   872
        /*
bob@2295
   873
           if (renderdata->glTextureRangeAPPLE) {
bob@2295
   874
           renderdata->glTextureRangeAPPLE(data->type,
bob@2295
   875
           texture->h * data->pitch,
bob@2295
   876
           data->pixels);
bob@2295
   877
           }
bob@2295
   878
         */
slouken@2230
   879
        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
slouken@2230
   880
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
slouken@2230
   881
                                 texture_h, 0, format, type, data->pixels);
slouken@2230
   882
    } else
slouken@2230
   883
#endif
slouken@2809
   884
#endif
slouken@2230
   885
    {
slouken@2230
   886
        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
slouken@2230
   887
                                 texture_h, 0, format, type, NULL);
slouken@2230
   888
    }
slouken@3041
   889
    renderdata->glDisable(data->type);
slouken@1927
   890
    result = renderdata->glGetError();
slouken@1924
   891
    if (result != GL_NO_ERROR) {
slouken@1924
   892
        GL_SetError("glTexImage2D()", result);
slouken@1924
   893
        return -1;
slouken@1924
   894
    }
slouken@1918
   895
    return 0;
slouken@1918
   896
}
slouken@1918
   897
slouken@1918
   898
static int
slouken@2222
   899
GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@2222
   900
                      void **pixels, int *pitch)
slouken@2222
   901
{
slouken@2222
   902
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@2222
   903
slouken@2222
   904
    *pixels = data->pixels;
slouken@2222
   905
    *pitch = data->pitch;
slouken@2222
   906
    return 0;
slouken@2222
   907
}
slouken@2222
   908
slouken@2222
   909
static int
slouken@1918
   910
GL_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
   911
                     const SDL_Color * colors, int firstcolor, int ncolors)
slouken@1918
   912
{
slouken@1918
   913
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
   914
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1974
   915
    Uint8 *palette;
slouken@1918
   916
slouken@1974
   917
    if (!data->palette) {
slouken@1974
   918
        SDL_SetError("Texture doesn't have a palette");
slouken@1974
   919
        return -1;
slouken@1974
   920
    }
slouken@1974
   921
    palette = data->palette + firstcolor * 3;
slouken@1974
   922
    while (ncolors--) {
slouken@1974
   923
        *palette++ = colors->r;
slouken@1974
   924
        *palette++ = colors->g;
slouken@1974
   925
        *palette++ = colors->b;
slouken@1974
   926
        ++colors;
slouken@1974
   927
    }
slouken@2884
   928
    renderdata->glEnable(data->type);
slouken@1974
   929
    renderdata->glBindTexture(data->type, data->texture);
slouken@1974
   930
    renderdata->glColorTableEXT(data->type, GL_RGB8, 256, GL_RGB,
slouken@1974
   931
                                GL_UNSIGNED_BYTE, data->palette);
slouken@1918
   932
    return 0;
slouken@1918
   933
}
slouken@1918
   934
slouken@1918
   935
static int
slouken@1918
   936
GL_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
   937
                     SDL_Color * colors, int firstcolor, int ncolors)
slouken@1918
   938
{
slouken@1974
   939
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
   940
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1974
   941
    Uint8 *palette;
slouken@1918
   942
slouken@1974
   943
    if (!data->palette) {
slouken@1974
   944
        SDL_SetError("Texture doesn't have a palette");
slouken@1974
   945
        return -1;
slouken@1974
   946
    }
slouken@1974
   947
    palette = data->palette + firstcolor * 3;
slouken@1974
   948
    while (ncolors--) {
slouken@1974
   949
        colors->r = *palette++;
slouken@1974
   950
        colors->g = *palette++;
slouken@1974
   951
        colors->b = *palette++;
slouken@1974
   952
        colors->unused = SDL_ALPHA_OPAQUE;
slouken@1974
   953
        ++colors;
slouken@1974
   954
    }
slouken@1918
   955
    return 0;
slouken@1918
   956
}
slouken@1918
   957
slouken@1924
   958
static void
slouken@1927
   959
SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture,
slouken@1927
   960
                   int pitch)
slouken@1924
   961
{
slouken@1965
   962
    if (texture->format == SDL_PIXELFORMAT_INDEX1LSB) {
slouken@1927
   963
        renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
slouken@1965
   964
    } else if (texture->format == SDL_PIXELFORMAT_INDEX1MSB) {
slouken@1927
   965
        renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
slouken@1924
   966
    }
slouken@1927
   967
    renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@2808
   968
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
slouken@2884
   969
                              (pitch / bytes_per_pixel(texture->format)) /
slouken@3013
   970
                              ((GL_TextureData *) texture->driverdata)->
slouken@3013
   971
                              HACK_RYAN_FIXME);
slouken@1924
   972
}
slouken@1924
   973
slouken@1918
   974
static int
slouken@1985
   975
GL_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   976
{
slouken@1986
   977
    return 0;
slouken@1985
   978
}
slouken@1985
   979
slouken@1985
   980
static int
slouken@1985
   981
GL_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   982
{
slouken@1986
   983
    return 0;
slouken@1985
   984
}
slouken@1985
   985
slouken@1985
   986
static int
slouken@1985
   987
GL_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
   988
{
slouken@1985
   989
    switch (texture->blendMode) {
slouken@2884
   990
    case SDL_BLENDMODE_NONE:
slouken@2884
   991
    case SDL_BLENDMODE_MASK:
slouken@2884
   992
    case SDL_BLENDMODE_BLEND:
slouken@2884
   993
    case SDL_BLENDMODE_ADD:
slouken@2884
   994
    case SDL_BLENDMODE_MOD:
slouken@1985
   995
        return 0;
slouken@1985
   996
    default:
slouken@1985
   997
        SDL_Unsupported();
slouken@2884
   998
        texture->blendMode = SDL_BLENDMODE_NONE;
slouken@1985
   999
        return -1;
slouken@1985
  1000
    }
slouken@1985
  1001
}
slouken@1985
  1002
slouken@1985
  1003
static int
slouken@1985
  1004
GL_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1985
  1005
{
slouken@1985
  1006
    switch (texture->scaleMode) {
slouken@1985
  1007
    case SDL_TEXTURESCALEMODE_NONE:
slouken@1985
  1008
    case SDL_TEXTURESCALEMODE_FAST:
slouken@1985
  1009
    case SDL_TEXTURESCALEMODE_SLOW:
slouken@1985
  1010
        return 0;
slouken@1985
  1011
    case SDL_TEXTURESCALEMODE_BEST:
slouken@1985
  1012
        SDL_Unsupported();
slouken@1985
  1013
        texture->scaleMode = SDL_TEXTURESCALEMODE_SLOW;
slouken@1985
  1014
        return -1;
slouken@1985
  1015
    default:
slouken@1985
  1016
        SDL_Unsupported();
slouken@1985
  1017
        texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
slouken@1985
  1018
        return -1;
slouken@1985
  1019
    }
slouken@1985
  1020
}
slouken@1985
  1021
slouken@1985
  1022
static int
slouken@1918
  1023
GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
  1024
                 const SDL_Rect * rect, const void *pixels, int pitch)
slouken@1918
  1025
{
slouken@1927
  1026
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1027
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1924
  1028
    GLenum result;
slouken@1918
  1029
slouken@1927
  1030
    renderdata->glGetError();
slouken@1927
  1031
    SetupTextureUpdate(renderdata, texture, pitch);
slouken@2884
  1032
    renderdata->glEnable(data->type);
slouken@1927
  1033
    renderdata->glBindTexture(data->type, data->texture);
slouken@1927
  1034
    renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
slouken@1927
  1035
                                rect->h, data->format, data->formattype,
slouken@1927
  1036
                                pixels);
slouken@3041
  1037
    renderdata->glDisable(data->type);
slouken@1927
  1038
    result = renderdata->glGetError();
slouken@1924
  1039
    if (result != GL_NO_ERROR) {
slouken@1924
  1040
        GL_SetError("glTexSubImage2D()", result);
slouken@1924
  1041
        return -1;
slouken@1924
  1042
    }
slouken@1918
  1043
    return 0;
slouken@1918
  1044
}
slouken@1918
  1045
slouken@1918
  1046
static int
slouken@1918
  1047
GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
  1048
               const SDL_Rect * rect, int markDirty, void **pixels,
slouken@1918
  1049
               int *pitch)
slouken@1918
  1050
{
slouken@1918
  1051
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
  1052
slouken@1920
  1053
    if (markDirty) {
slouken@1920
  1054
        SDL_AddDirtyRect(&data->dirty, rect);
slouken@1920
  1055
    }
slouken@1918
  1056
slouken@1920
  1057
    *pixels =
slouken@1920
  1058
        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
icculus@2835
  1059
                  rect->x * bytes_per_pixel(texture->format));
slouken@1920
  1060
    *pitch = data->pitch;
slouken@1918
  1061
    return 0;
slouken@1918
  1062
}
slouken@1918
  1063
slouken@1918
  1064
static void
slouken@1918
  1065
GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
  1066
{
slouken@1918
  1067
}
slouken@1918
  1068
slouken@1918
  1069
static void
slouken@1918
  1070
GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
slouken@1918
  1071
                const SDL_Rect * rects)
slouken@1918
  1072
{
slouken@1918
  1073
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
  1074
    int i;
slouken@1918
  1075
slouken@1918
  1076
    for (i = 0; i < numrects; ++i) {
slouken@1920
  1077
        SDL_AddDirtyRect(&data->dirty, &rects[i]);
slouken@1918
  1078
    }
slouken@1918
  1079
}
slouken@1918
  1080
slouken@2936
  1081
static void
slouken@3458
  1082
GL_SetBlendMode(GL_RenderData * data, int blendMode, int isprimitive)
slouken@2936
  1083
{
slouken@2936
  1084
    if (blendMode != data->blendMode) {
slouken@2936
  1085
        switch (blendMode) {
slouken@2936
  1086
        case SDL_BLENDMODE_NONE:
slouken@2936
  1087
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
slouken@2936
  1088
            data->glDisable(GL_BLEND);
slouken@2936
  1089
            break;
slouken@2936
  1090
        case SDL_BLENDMODE_MASK:
slouken@3458
  1091
            if (isprimitive) {
slouken@3458
  1092
                /* The same as SDL_BLENDMODE_NONE */
slouken@3458
  1093
                blendMode = SDL_BLENDMODE_NONE;
slouken@3458
  1094
                data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
slouken@3458
  1095
                data->glDisable(GL_BLEND);
slouken@3458
  1096
            } else {
slouken@3458
  1097
                data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
slouken@3458
  1098
                data->glEnable(GL_BLEND);
slouken@3458
  1099
                data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
slouken@3458
  1100
            }
slouken@3457
  1101
            break;
slouken@2936
  1102
        case SDL_BLENDMODE_BLEND:
slouken@2936
  1103
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@2936
  1104
            data->glEnable(GL_BLEND);
slouken@2936
  1105
            data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
slouken@2936
  1106
            break;
slouken@2936
  1107
        case SDL_BLENDMODE_ADD:
slouken@2936
  1108
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@2936
  1109
            data->glEnable(GL_BLEND);
slouken@2936
  1110
            data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
slouken@2936
  1111
            break;
slouken@2936
  1112
        case SDL_BLENDMODE_MOD:
slouken@2936
  1113
            data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
slouken@2936
  1114
            data->glEnable(GL_BLEND);
slouken@2936
  1115
            data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
slouken@2936
  1116
            break;
slouken@2936
  1117
        }
slouken@2936
  1118
        data->blendMode = blendMode;
slouken@2936
  1119
    }
slouken@2936
  1120
}
slouken@2936
  1121
slouken@1918
  1122
static int
slouken@2901
  1123
GL_RenderPoint(SDL_Renderer * renderer, int x, int y)
slouken@2884
  1124
{
slouken@2884
  1125
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@2884
  1126
slouken@3458
  1127
    GL_SetBlendMode(data, renderer->blendMode, 1);
slouken@2884
  1128
slouken@2884
  1129
    data->glColor4f((GLfloat) renderer->r * inv255f,
slouken@2884
  1130
                    (GLfloat) renderer->g * inv255f,
slouken@2884
  1131
                    (GLfloat) renderer->b * inv255f,
slouken@2884
  1132
                    (GLfloat) renderer->a * inv255f);
slouken@2884
  1133
slouken@2901
  1134
    data->glBegin(GL_POINTS);
slouken@3454
  1135
    data->glVertex2f(0.5f + x, 0.5f + y);
slouken@2901
  1136
    data->glEnd();
slouken@2901
  1137
slouken@2901
  1138
    return 0;
slouken@2901
  1139
}
slouken@2901
  1140
slouken@2901
  1141
static int
slouken@2901
  1142
GL_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
slouken@2901
  1143
{
slouken@2901
  1144
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@2901
  1145
slouken@3458
  1146
    GL_SetBlendMode(data, renderer->blendMode, 1);
slouken@2901
  1147
slouken@2901
  1148
    data->glColor4f((GLfloat) renderer->r * inv255f,
slouken@2901
  1149
                    (GLfloat) renderer->g * inv255f,
slouken@2901
  1150
                    (GLfloat) renderer->b * inv255f,
slouken@2901
  1151
                    (GLfloat) renderer->a * inv255f);
slouken@2901
  1152
slouken@3474
  1153
    data->glBegin(GL_LINES);
slouken@3474
  1154
    data->glVertex2f(0.5f + x1, 0.5f + y1);
slouken@3474
  1155
    data->glVertex2f(0.5f + x2, 0.5f + y2);
slouken@3474
  1156
    data->glEnd();
slouken@3474
  1157
slouken@3474
  1158
    /* The line is half open, so we need one more point to complete the line.
slouken@3473
  1159
     * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
slouken@3473
  1160
     */
slouken@3474
  1161
    data->glBegin(GL_POINTS);
slouken@3474
  1162
#ifdef __APPLE__
slouken@3474
  1163
    /* Mac OS X seems to always leave the second point open */
slouken@3454
  1164
    data->glVertex2f(0.5f + x2, 0.5f + y2);
slouken@3474
  1165
#else
slouken@3474
  1166
    /* Linux seems to use the right-most or bottom-most point open */
slouken@3474
  1167
    if (x1 > x2) {
slouken@3474
  1168
        data->glVertex2f(0.5f + x1, 0.5f + y1);
slouken@3474
  1169
    } else if (x2 > x1) {
slouken@3474
  1170
        data->glVertex2f(0.5f + x2, 0.5f + y2);
slouken@3474
  1171
    } else if (y1 > y2) {
slouken@3474
  1172
        data->glVertex2f(0.5f + x1, 0.5f + y1);
slouken@3474
  1173
    } else if (y2 > y1) {
slouken@3474
  1174
        data->glVertex2f(0.5f + x2, 0.5f + y2);
slouken@3474
  1175
    }
slouken@3474
  1176
#endif
slouken@3455
  1177
    data->glEnd();
slouken@3455
  1178
slouken@1918
  1179
    return 0;
slouken@1918
  1180
}
slouken@1918
  1181
slouken@1918
  1182
static int
slouken@2925
  1183
GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect)
slouken@2925
  1184
{
slouken@2925
  1185
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@2925
  1186
slouken@3458
  1187
    GL_SetBlendMode(data, renderer->blendMode, 1);
slouken@2936
  1188
slouken@2925
  1189
    data->glColor4f((GLfloat) renderer->r * inv255f,
slouken@2925
  1190
                    (GLfloat) renderer->g * inv255f,
slouken@2925
  1191
                    (GLfloat) renderer->b * inv255f,
slouken@2925
  1192
                    (GLfloat) renderer->a * inv255f);
slouken@2936
  1193
slouken@2925
  1194
    data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
slouken@2925
  1195
slouken@2925
  1196
    return 0;
slouken@2925
  1197
}
slouken@2925
  1198
slouken@2925
  1199
static int
slouken@1918
  1200
GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1985
  1201
              const SDL_Rect * srcrect, const SDL_Rect * dstrect)
slouken@1918
  1202
{
slouken@1918
  1203
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1204
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
slouken@3468
  1205
    GLuint shader = 0;
slouken@1918
  1206
    int minx, miny, maxx, maxy;
slouken@1918
  1207
    GLfloat minu, maxu, minv, maxv;
slouken@1918
  1208
slouken@2275
  1209
    if (texturedata->dirty.list) {
slouken@1920
  1210
        SDL_DirtyRect *dirty;
slouken@1920
  1211
        void *pixels;
icculus@2835
  1212
        int bpp = bytes_per_pixel(texture->format);
slouken@1920
  1213
        int pitch = texturedata->pitch;
slouken@1920
  1214
slouken@1927
  1215
        SetupTextureUpdate(data, texture, pitch);
slouken@2884
  1216
        data->glEnable(texturedata->type);
slouken@1927
  1217
        data->glBindTexture(texturedata->type, texturedata->texture);
slouken@1920
  1218
        for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
slouken@1920
  1219
            SDL_Rect *rect = &dirty->rect;
slouken@1920
  1220
            pixels =
slouken@1920
  1221
                (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
slouken@1920
  1222
                          rect->x * bpp);
slouken@1927
  1223
            data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
slouken@2884
  1224
                                  rect->w / texturedata->HACK_RYAN_FIXME,
slouken@2884
  1225
                                  rect->h, texturedata->format,
slouken@1927
  1226
                                  texturedata->formattype, pixels);
slouken@1920
  1227
        }
slouken@1920
  1228
        SDL_ClearDirtyRects(&texturedata->dirty);
slouken@1920
  1229
    }
slouken@1920
  1230
slouken@1918
  1231
    minx = dstrect->x;
slouken@1918
  1232
    miny = dstrect->y;
slouken@1918
  1233
    maxx = dstrect->x + dstrect->w;
slouken@1918
  1234
    maxy = dstrect->y + dstrect->h;
slouken@1918
  1235
slouken@1918
  1236
    minu = (GLfloat) srcrect->x / texture->w;
slouken@1920
  1237
    minu *= texturedata->texw;
slouken@1918
  1238
    maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
slouken@1920
  1239
    maxu *= texturedata->texw;
slouken@1918
  1240
    minv = (GLfloat) srcrect->y / texture->h;
slouken@1920
  1241
    minv *= texturedata->texh;
slouken@1918
  1242
    maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
slouken@1920
  1243
    maxv *= texturedata->texh;
slouken@1918
  1244
slouken@2884
  1245
    data->glEnable(texturedata->type);
slouken@1927
  1246
    data->glBindTexture(texturedata->type, texturedata->texture);
slouken@1918
  1247
slouken@1985
  1248
    if (texture->modMode) {
slouken@1985
  1249
        data->glColor4f((GLfloat) texture->r * inv255f,
slouken@1985
  1250
                        (GLfloat) texture->g * inv255f,
slouken@1985
  1251
                        (GLfloat) texture->b * inv255f,
slouken@1985
  1252
                        (GLfloat) texture->a * inv255f);
slouken@1985
  1253
    } else {
slouken@1985
  1254
        data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
slouken@1985
  1255
    }
slouken@1985
  1256
slouken@3458
  1257
    GL_SetBlendMode(data, texture->blendMode, 0);
slouken@1918
  1258
slouken@3468
  1259
    /* Set up the shader for the copy, we have a special one for MASK */
slouken@3468
  1260
    shader = texturedata->shader;
slouken@3468
  1261
    if (texture->blendMode == SDL_BLENDMODE_MASK && !shader) {
slouken@3468
  1262
        if (data->fragment_program_mask == 0) {
slouken@3468
  1263
            data->fragment_program_mask =
slouken@3468
  1264
                compile_shader(data, GL_FRAGMENT_PROGRAM_ARB,
slouken@3468
  1265
                               fragment_program_mask_source_code);
slouken@3468
  1266
            if (data->fragment_program_mask == 0) {
slouken@3468
  1267
                /* That's okay, we'll just miss some of the blend semantics */
slouken@3468
  1268
                data->fragment_program_mask = ~0;
slouken@3468
  1269
            }
slouken@3468
  1270
        }
slouken@3468
  1271
        if (data->fragment_program_mask != ~0) {
slouken@3468
  1272
            shader = data->fragment_program_mask;
slouken@3468
  1273
        }
slouken@3468
  1274
    }
slouken@3468
  1275
slouken@1985
  1276
    if (texture->scaleMode != data->scaleMode) {
slouken@1985
  1277
        switch (texture->scaleMode) {
slouken@1965
  1278
        case SDL_TEXTURESCALEMODE_NONE:
slouken@1965
  1279
        case SDL_TEXTURESCALEMODE_FAST:
slouken@1927
  1280
            data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
slouken@1927
  1281
                                  GL_NEAREST);
slouken@1927
  1282
            data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
slouken@1927
  1283
                                  GL_NEAREST);
slouken@1927
  1284
            break;
slouken@1965
  1285
        case SDL_TEXTURESCALEMODE_SLOW:
slouken@1965
  1286
        case SDL_TEXTURESCALEMODE_BEST:
slouken@1927
  1287
            data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
slouken@1927
  1288
                                  GL_LINEAR);
slouken@1927
  1289
            data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
slouken@1927
  1290
                                  GL_LINEAR);
slouken@1927
  1291
            break;
slouken@1927
  1292
        }
slouken@1985
  1293
        data->scaleMode = texture->scaleMode;
slouken@1918
  1294
    }
slouken@1918
  1295
slouken@3468
  1296
    if (shader) {
icculus@2835
  1297
        data->glEnable(GL_FRAGMENT_PROGRAM_ARB);
slouken@3468
  1298
        data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader);
icculus@2835
  1299
    }
icculus@2835
  1300
slouken@1927
  1301
    data->glBegin(GL_TRIANGLE_STRIP);
slouken@1927
  1302
    data->glTexCoord2f(minu, minv);
slouken@3472
  1303
    data->glVertex2f((GLfloat) minx, (GLfloat) miny);
slouken@1927
  1304
    data->glTexCoord2f(maxu, minv);
slouken@3472
  1305
    data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
slouken@1927
  1306
    data->glTexCoord2f(minu, maxv);
slouken@3472
  1307
    data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
slouken@1927
  1308
    data->glTexCoord2f(maxu, maxv);
slouken@3472
  1309
    data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
slouken@1927
  1310
    data->glEnd();
slouken@1918
  1311
slouken@3468
  1312
    if (shader) {
icculus@2835
  1313
        data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
icculus@2835
  1314
    }
slouken@2884
  1315
slouken@2884
  1316
    data->glDisable(texturedata->type);
slouken@2884
  1317
slouken@1918
  1318
    return 0;
slouken@1918
  1319
}
slouken@1918
  1320
slouken@3431
  1321
static int
slouken@3431
  1322
GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
  1323
                    Uint32 pixel_format, void * pixels, int pitch)
slouken@3431
  1324
{
slouken@3433
  1325
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3447
  1326
    SDL_Window *window = SDL_GetWindowFromID(renderer->window);
slouken@3433
  1327
    GLint internalFormat;
slouken@3433
  1328
    GLenum format, type;
slouken@3435
  1329
    Uint8 *src, *dst, *tmp;
slouken@3435
  1330
    int length, rows;
slouken@3433
  1331
slouken@3433
  1332
    if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
slouken@3435
  1333
        /* FIXME: Do a temp copy to a format that is supported */
slouken@3433
  1334
        SDL_SetError("Unsupported pixel format");
slouken@3433
  1335
        return -1;
slouken@3433
  1336
    }
slouken@3433
  1337
slouken@3433
  1338
    if (pixel_format == SDL_PIXELFORMAT_INDEX1LSB) {
slouken@3433
  1339
        data->glPixelStorei(GL_PACK_LSB_FIRST, 1);
slouken@3433
  1340
    } else if (pixel_format == SDL_PIXELFORMAT_INDEX1MSB) {
slouken@3433
  1341
        data->glPixelStorei(GL_PACK_LSB_FIRST, 0);
slouken@3433
  1342
    }
slouken@3446
  1343
    data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
slouken@3446
  1344
    data->glPixelStorei(GL_PACK_ROW_LENGTH,
slouken@3446
  1345
                        (pitch / bytes_per_pixel(pixel_format)));
slouken@3433
  1346
slouken@3447
  1347
    data->glReadPixels(rect->x, (window->h-rect->y)-rect->h, rect->w, rect->h,
slouken@3435
  1348
                       format, type, pixels);
slouken@3435
  1349
slouken@3435
  1350
    /* Flip the rows to be top-down */
slouken@3435
  1351
    length = rect->w * bytes_per_pixel(pixel_format);
slouken@3435
  1352
    src = (Uint8*)pixels + (rect->h-1)*pitch;
slouken@3435
  1353
    dst = (Uint8*)pixels;
slouken@3435
  1354
    tmp = SDL_stack_alloc(Uint8, length);
slouken@3435
  1355
    rows = rect->h / 2;
slouken@3435
  1356
    while (rows--) {
slouken@3435
  1357
        SDL_memcpy(tmp, dst, length);
slouken@3435
  1358
        SDL_memcpy(dst, src, length);
slouken@3435
  1359
        SDL_memcpy(src, tmp, length);
slouken@3447
  1360
        dst += pitch;
slouken@3447
  1361
        src -= pitch;
slouken@3435
  1362
    }
slouken@3435
  1363
    SDL_stack_free(tmp);
slouken@3440
  1364
slouken@3440
  1365
    return 0;
slouken@3431
  1366
}
slouken@3431
  1367
slouken@3431
  1368
static int
slouken@3431
  1369
GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
  1370
                     Uint32 pixel_format, const void * pixels, int pitch)
slouken@3431
  1371
{
slouken@3435
  1372
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@3435
  1373
    GLint internalFormat;
slouken@3435
  1374
    GLenum format, type;
slouken@3435
  1375
slouken@3435
  1376
    if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
slouken@3435
  1377
        /* FIXME: Do a temp copy to a format that is supported */
slouken@3435
  1378
        SDL_SetError("Unsupported pixel format");
slouken@3435
  1379
        return -1;
slouken@3435
  1380
    }
slouken@3435
  1381
slouken@3435
  1382
    /* FIXME: We need to copy the data and flip it */
slouken@3435
  1383
slouken@3435
  1384
    if (pixel_format == SDL_PIXELFORMAT_INDEX1LSB) {
slouken@3435
  1385
        data->glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
slouken@3435
  1386
    } else if (pixel_format == SDL_PIXELFORMAT_INDEX1MSB) {
slouken@3435
  1387
        data->glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
slouken@3435
  1388
    }
slouken@3435
  1389
    data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@3435
  1390
    data->glPixelStorei(GL_UNPACK_ROW_LENGTH,
slouken@3435
  1391
                        (pitch / bytes_per_pixel(pixel_format)));
slouken@3435
  1392
slouken@3446
  1393
    data->glRasterPos2i(rect->x, rect->y);
slouken@3446
  1394
    data->glDrawPixels(rect->w, rect->h, format, type, pixels);
slouken@3440
  1395
slouken@3440
  1396
    return 0;
slouken@3431
  1397
}
slouken@3431
  1398
slouken@1918
  1399
static void
slouken@1918
  1400
GL_RenderPresent(SDL_Renderer * renderer)
slouken@1918
  1401
{
slouken@1918
  1402
    SDL_GL_SwapWindow(renderer->window);
slouken@1918
  1403
}
slouken@1918
  1404
slouken@1918
  1405
static void
slouken@1918
  1406
GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
  1407
{
slouken@1927
  1408
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1409
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
  1410
slouken@1918
  1411
    if (!data) {
slouken@1918
  1412
        return;
slouken@1918
  1413
    }
slouken@1918
  1414
    if (data->texture) {
slouken@1927
  1415
        renderdata->glDeleteTextures(1, &data->texture);
slouken@1918
  1416
    }
slouken@1974
  1417
    if (data->palette) {
slouken@1974
  1418
        SDL_free(data->palette);
slouken@1974
  1419
    }
slouken@1920
  1420
    if (data->pixels) {
slouken@1920
  1421
        SDL_free(data->pixels);
slouken@1920
  1422
    }
slouken@1920
  1423
    SDL_FreeDirtyRects(&data->dirty);
slouken@1918
  1424
    SDL_free(data);
slouken@1918
  1425
    texture->driverdata = NULL;
slouken@1918
  1426
}
slouken@1918
  1427
slouken@1975
  1428
static void
slouken@1918
  1429
GL_DestroyRenderer(SDL_Renderer * renderer)
slouken@1918
  1430
{
slouken@1918
  1431
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1432
slouken@1918
  1433
    if (data) {
slouken@1920
  1434
        if (data->context) {
icculus@2835
  1435
            if (data->GL_ARB_fragment_program_supported) {
icculus@2835
  1436
                data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
icculus@2835
  1437
                data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
slouken@3468
  1438
                if (data->fragment_program_mask &&
slouken@3468
  1439
                    data->fragment_program_mask != ~0) {
slouken@3468
  1440
                    data->glDeleteProgramsARB(1,
slouken@3468
  1441
                                              &data->fragment_program_mask);
slouken@3468
  1442
                }
slouken@3468
  1443
                if (data->fragment_program_UYVY &&
slouken@3468
  1444
                    data->fragment_program_UYVY != ~0) {
slouken@2884
  1445
                    data->glDeleteProgramsARB(1,
slouken@2884
  1446
                                              &data->fragment_program_UYVY);
icculus@2835
  1447
                }
icculus@2835
  1448
            }
icculus@2835
  1449
bob@2328
  1450
            /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
slouken@1920
  1451
            SDL_GL_DeleteContext(data->context);
slouken@1918
  1452
        }
slouken@1918
  1453
        SDL_free(data);
slouken@1918
  1454
    }
slouken@1918
  1455
    SDL_free(renderer);
slouken@1918
  1456
}
slouken@1918
  1457
slouken@1952
  1458
#endif /* SDL_VIDEO_RENDER_OGL */
slouken@1918
  1459
slouken@1918
  1460
/* vi: set ts=4 sw=4 expandtab: */