src/render/opengl/SDL_render_gl.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8257 a1563cbde7a5
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

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