src/render/opengl/SDL_render_gl.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 05 Feb 2011 12:01:11 -0800
changeset 5195 bb45ecd958d8
parent 5184 src/render/opengl/SDL_renderer_gl.c@d976b67150c5
child 5203 25ffd4e5255c
permissions -rw-r--r--
Renamed files for consistency
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_RENDER_OGL
    25 
    26 #include "SDL_opengl.h"
    27 #include "../SDL_sysrender.h"
    28 
    29 #ifdef __MACOSX__
    30 #include <OpenGL/OpenGL.h>
    31 #endif
    32 
    33 
    34 /* OpenGL renderer implementation */
    35 
    36 /* Details on optimizing the texture path on Mac OS X:
    37    http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html
    38 */
    39 
    40 /* Used to re-create the window with OpenGL capability */
    41 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
    42 
    43 static const float inv255f = 1.0f / 255.0f;
    44 
    45 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    46 static void GL_WindowEvent(SDL_Renderer * renderer,
    47                            const SDL_WindowEvent *event);
    48 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    49 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    50                             const SDL_Rect * rect, const void *pixels,
    51                             int pitch);
    52 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    53                           const SDL_Rect * rect, void **pixels, int *pitch);
    54 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    55 static int GL_RenderClear(SDL_Renderer * renderer);
    56 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
    57                                const SDL_Point * points, int count);
    58 static int GL_RenderDrawLines(SDL_Renderer * renderer,
    59                               const SDL_Point * points, int count);
    60 static int GL_RenderFillRects(SDL_Renderer * renderer,
    61                               const SDL_Rect ** rects, int count);
    62 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    63                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    64 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    65                                Uint32 pixel_format, void * pixels, int pitch);
    66 static void GL_RenderPresent(SDL_Renderer * renderer);
    67 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    68 static void GL_DestroyRenderer(SDL_Renderer * renderer);
    69 
    70 
    71 SDL_RenderDriver GL_RenderDriver = {
    72     GL_CreateRenderer,
    73     {
    74      "opengl",
    75      (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
    76      1,
    77      {SDL_PIXELFORMAT_ARGB8888},
    78      0,
    79      0}
    80 };
    81 
    82 typedef struct
    83 {
    84     SDL_GLContext context;
    85     SDL_bool updateSize;
    86     SDL_bool GL_ARB_texture_rectangle_supported;
    87     int blendMode;
    88 
    89     /* OpenGL functions */
    90 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
    91 #include "../../video/SDL_glfuncs.h"
    92 #undef SDL_PROC
    93 
    94     void (*glTextureRangeAPPLE) (GLenum target, GLsizei length,
    95                                  const GLvoid * pointer);
    96 } GL_RenderData;
    97 
    98 typedef struct
    99 {
   100     GLuint texture;
   101     GLenum type;
   102     GLfloat texw;
   103     GLfloat texh;
   104     GLenum format;
   105     GLenum formattype;
   106     void *pixels;
   107     int pitch;
   108 } GL_TextureData;
   109 
   110 
   111 static void
   112 GL_SetError(const char *prefix, GLenum result)
   113 {
   114     const char *error;
   115 
   116     switch (result) {
   117     case GL_NO_ERROR:
   118         error = "GL_NO_ERROR";
   119         break;
   120     case GL_INVALID_ENUM:
   121         error = "GL_INVALID_ENUM";
   122         break;
   123     case GL_INVALID_VALUE:
   124         error = "GL_INVALID_VALUE";
   125         break;
   126     case GL_INVALID_OPERATION:
   127         error = "GL_INVALID_OPERATION";
   128         break;
   129     case GL_STACK_OVERFLOW:
   130         error = "GL_STACK_OVERFLOW";
   131         break;
   132     case GL_STACK_UNDERFLOW:
   133         error = "GL_STACK_UNDERFLOW";
   134         break;
   135     case GL_OUT_OF_MEMORY:
   136         error = "GL_OUT_OF_MEMORY";
   137         break;
   138     case GL_TABLE_TOO_LARGE:
   139         error = "GL_TABLE_TOO_LARGE";
   140         break;
   141     default:
   142         error = "UNKNOWN";
   143         break;
   144     }
   145     SDL_SetError("%s: %s", prefix, error);
   146 }
   147 
   148 static int
   149 GL_LoadFunctions(GL_RenderData * data)
   150 {
   151 #ifdef __SDL_NOGETPROCADDR__
   152 #define SDL_PROC(ret,func,params) data->func=func;
   153 #else
   154 #define SDL_PROC(ret,func,params) \
   155     do { \
   156         data->func = SDL_GL_GetProcAddress(#func); \
   157         if ( ! data->func ) { \
   158             SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
   159             return -1; \
   160         } \
   161     } while ( 0 );
   162 #endif /* __SDL_NOGETPROCADDR__ */
   163 
   164 #include "../../video/SDL_glfuncs.h"
   165 #undef SDL_PROC
   166     return 0;
   167 }
   168 
   169 SDL_Renderer *
   170 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
   171 {
   172     SDL_Renderer *renderer;
   173     GL_RenderData *data;
   174     GLint value;
   175     Uint32 window_flags;
   176 
   177     window_flags = SDL_GetWindowFlags(window);
   178     if (!(window_flags & SDL_WINDOW_OPENGL)) {
   179         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
   180             return NULL;
   181         }
   182     }
   183 
   184     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   185     if (!renderer) {
   186         SDL_OutOfMemory();
   187         return NULL;
   188     }
   189 
   190     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
   191     if (!data) {
   192         GL_DestroyRenderer(renderer);
   193         SDL_OutOfMemory();
   194         return NULL;
   195     }
   196 
   197     renderer->WindowEvent = GL_WindowEvent;
   198     renderer->CreateTexture = GL_CreateTexture;
   199     renderer->UpdateTexture = GL_UpdateTexture;
   200     renderer->LockTexture = GL_LockTexture;
   201     renderer->UnlockTexture = GL_UnlockTexture;
   202     renderer->RenderClear = GL_RenderClear;
   203     renderer->RenderDrawPoints = GL_RenderDrawPoints;
   204     renderer->RenderDrawLines = GL_RenderDrawLines;
   205     renderer->RenderFillRects = GL_RenderFillRects;
   206     renderer->RenderCopy = GL_RenderCopy;
   207     renderer->RenderReadPixels = GL_RenderReadPixels;
   208     renderer->RenderPresent = GL_RenderPresent;
   209     renderer->DestroyTexture = GL_DestroyTexture;
   210     renderer->DestroyRenderer = GL_DestroyRenderer;
   211     renderer->info = GL_RenderDriver.info;
   212     renderer->driverdata = data;
   213 
   214     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   215 
   216     if (GL_LoadFunctions(data) < 0) {
   217         GL_DestroyRenderer(renderer);
   218         return NULL;
   219     }
   220 
   221     data->context = SDL_GL_CreateContext(window);
   222     if (!data->context) {
   223         GL_DestroyRenderer(renderer);
   224         return NULL;
   225     }
   226     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   227         GL_DestroyRenderer(renderer);
   228         return NULL;
   229     }
   230 #ifdef __MACOSX__
   231     /* Enable multi-threaded rendering */
   232     /* Disabled until Ryan finishes his VBO/PBO code...
   233        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
   234      */
   235 #endif
   236 
   237     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   238         SDL_GL_SetSwapInterval(1);
   239     } else {
   240         SDL_GL_SetSwapInterval(0);
   241     }
   242     if (SDL_GL_GetSwapInterval() > 0) {
   243         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   244     }
   245 
   246     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   247     renderer->info.max_texture_width = value;
   248     data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   249     renderer->info.max_texture_height = value;
   250 
   251     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
   252         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   253         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   254     }
   255     if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) {
   256         data->glTextureRangeAPPLE =
   257             (void (*)(GLenum, GLsizei, const GLvoid *))
   258             SDL_GL_GetProcAddress("glTextureRangeAPPLE");
   259     }
   260 
   261     /* Set up parameters for rendering */
   262     data->blendMode = -1;
   263     data->glDisable(GL_DEPTH_TEST);
   264     data->glDisable(GL_CULL_FACE);
   265     /* This ended up causing video discrepancies between OpenGL and Direct3D */
   266     /*data->glEnable(GL_LINE_SMOOTH);*/
   267     if (data->GL_ARB_texture_rectangle_supported) {
   268         data->glEnable(GL_TEXTURE_RECTANGLE_ARB);
   269     } else {
   270         data->glEnable(GL_TEXTURE_2D);
   271     }
   272     data->updateSize = SDL_TRUE;
   273 
   274     return renderer;
   275 }
   276 
   277 static SDL_GLContext SDL_CurrentContext = NULL;
   278 
   279 static int
   280 GL_ActivateRenderer(SDL_Renderer * renderer)
   281 {
   282     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   283     SDL_Window *window = renderer->window;
   284 
   285     if (SDL_CurrentContext != data->context) {
   286         if (SDL_GL_MakeCurrent(window, data->context) < 0) {
   287             return -1;
   288         }
   289         SDL_CurrentContext = data->context;
   290     }
   291     if (data->updateSize) {
   292         int w, h;
   293 
   294         SDL_GetWindowSize(window, &w, &h);
   295         data->glMatrixMode(GL_PROJECTION);
   296         data->glLoadIdentity();
   297         data->glMatrixMode(GL_MODELVIEW);
   298         data->glLoadIdentity();
   299         data->glViewport(0, 0, w, h);
   300         data->glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 1.0);
   301         data->updateSize = SDL_FALSE;
   302     }
   303     return 0;
   304 }
   305 
   306 static void
   307 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   308 {
   309     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   310 
   311     if (event->event == SDL_WINDOWEVENT_RESIZED) {
   312         /* Rebind the context to the window area and update matrices */
   313         SDL_CurrentContext = NULL;
   314         data->updateSize = SDL_TRUE;
   315     }
   316 }
   317 
   318 static __inline__ int
   319 power_of_2(int input)
   320 {
   321     int value = 1;
   322 
   323     while (value < input) {
   324         value <<= 1;
   325     }
   326     return value;
   327 }
   328 
   329 static __inline__ SDL_bool
   330 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
   331                GLint* internalFormat, GLenum* format, GLenum* type)
   332 {
   333     switch (pixel_format) {
   334     case SDL_PIXELFORMAT_RGB888:
   335     case SDL_PIXELFORMAT_ARGB8888:
   336         *internalFormat = GL_RGBA8;
   337         *format = GL_BGRA;
   338         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
   339         break;
   340     default:
   341         return SDL_FALSE;
   342     }
   343     return SDL_TRUE;
   344 }
   345 
   346 static int
   347 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   348 {
   349     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   350     GL_TextureData *data;
   351     GLint internalFormat;
   352     GLenum format, type;
   353     int texture_w, texture_h;
   354     GLenum result;
   355 
   356     GL_ActivateRenderer(renderer);
   357 
   358     if (!convert_format(renderdata, texture->format, &internalFormat,
   359                         &format, &type)) {
   360         SDL_SetError("Texture format %s not supported by OpenGL",
   361                      SDL_GetPixelFormatName(texture->format));
   362         return -1;
   363     }
   364 
   365     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
   366     if (!data) {
   367         SDL_OutOfMemory();
   368         return -1;
   369     }
   370 
   371     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   372         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   373         data->pixels = SDL_malloc(texture->h * data->pitch);
   374         if (!data->pixels) {
   375             SDL_OutOfMemory();
   376             SDL_free(data);
   377             return -1;
   378         }
   379     }
   380 
   381     texture->driverdata = data;
   382 
   383     renderdata->glGetError();
   384     renderdata->glGenTextures(1, &data->texture);
   385     if (renderdata->GL_ARB_texture_rectangle_supported) {
   386         data->type = GL_TEXTURE_RECTANGLE_ARB;
   387         texture_w = texture->w;
   388         texture_h = texture->h;
   389         data->texw = (GLfloat) texture_w;
   390         data->texh = (GLfloat) texture_h;
   391     } else {
   392         data->type = GL_TEXTURE_2D;
   393         texture_w = power_of_2(texture->w);
   394         texture_h = power_of_2(texture->h);
   395         data->texw = (GLfloat) (texture->w) / texture_w;
   396         data->texh = (GLfloat) texture->h / texture_h;
   397     }
   398 
   399     data->format = format;
   400     data->formattype = type;
   401     renderdata->glEnable(data->type);
   402     renderdata->glBindTexture(data->type, data->texture);
   403     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
   404                                 GL_LINEAR);
   405     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
   406                                 GL_LINEAR);
   407     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
   408                                 GL_CLAMP_TO_EDGE);
   409     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
   410                                 GL_CLAMP_TO_EDGE);
   411 #ifdef __MACOSX__
   412 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
   413 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
   414 #endif
   415 #ifndef STORAGE_CACHED_APPLE
   416 #define STORAGE_CACHED_APPLE                0x85BE
   417 #endif
   418 #ifndef STORAGE_SHARED_APPLE
   419 #define STORAGE_SHARED_APPLE                0x85BF
   420 #endif
   421     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   422         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   423                                     GL_STORAGE_SHARED_APPLE);
   424     } else {
   425         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
   426                                     GL_STORAGE_CACHED_APPLE);
   427     }
   428     if (texture->access == SDL_TEXTUREACCESS_STREAMING
   429         && texture->format == SDL_PIXELFORMAT_ARGB8888) {
   430         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
   431         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   432                                  texture_h, 0, format, type, data->pixels);
   433     }
   434     else
   435 #endif
   436     {
   437         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
   438                                  texture_h, 0, format, type, NULL);
   439     }
   440     renderdata->glDisable(data->type);
   441     result = renderdata->glGetError();
   442     if (result != GL_NO_ERROR) {
   443         GL_SetError("glTexImage2D()", result);
   444         return -1;
   445     }
   446     return 0;
   447 }
   448 
   449 static void
   450 SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture,
   451                    int pitch)
   452 {
   453     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   454     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
   455                               (pitch / SDL_BYTESPERPIXEL(texture->format)));
   456 }
   457 
   458 static int
   459 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   460                  const SDL_Rect * rect, const void *pixels, int pitch)
   461 {
   462     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   463     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   464     GLenum result;
   465 
   466     GL_ActivateRenderer(renderer);
   467 
   468     renderdata->glGetError();
   469     SetupTextureUpdate(renderdata, texture, pitch);
   470     renderdata->glEnable(data->type);
   471     renderdata->glBindTexture(data->type, data->texture);
   472     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
   473                                 rect->h, data->format, data->formattype,
   474                                 pixels);
   475     renderdata->glDisable(data->type);
   476     result = renderdata->glGetError();
   477     if (result != GL_NO_ERROR) {
   478         GL_SetError("glTexSubImage2D()", result);
   479         return -1;
   480     }
   481     return 0;
   482 }
   483 
   484 static int
   485 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   486                const SDL_Rect * rect, void **pixels, int *pitch)
   487 {
   488     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   489 
   490     *pixels =
   491         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
   492                   rect->x * SDL_BYTESPERPIXEL(texture->format));
   493     *pitch = data->pitch;
   494     return 0;
   495 }
   496 
   497 static void
   498 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   499 {
   500     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   501     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   502 
   503     GL_ActivateRenderer(renderer);
   504 
   505     SetupTextureUpdate(renderdata, texture, data->pitch);
   506     renderdata->glEnable(data->type);
   507     renderdata->glBindTexture(data->type, data->texture);
   508     renderdata->glTexSubImage2D(data->type, 0, 0, 0, texture->w, texture->h,
   509                                 data->format, data->formattype, data->pixels);
   510     renderdata->glDisable(data->type);
   511 }
   512 
   513 static void
   514 GL_SetBlendMode(GL_RenderData * data, int blendMode)
   515 {
   516     if (blendMode != data->blendMode) {
   517         switch (blendMode) {
   518         case SDL_BLENDMODE_NONE:
   519             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   520             data->glDisable(GL_BLEND);
   521             break;
   522         case SDL_BLENDMODE_BLEND:
   523             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   524             data->glEnable(GL_BLEND);
   525             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   526             break;
   527         case SDL_BLENDMODE_ADD:
   528             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   529             data->glEnable(GL_BLEND);
   530             data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   531             break;
   532         case SDL_BLENDMODE_MOD:
   533             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   534             data->glEnable(GL_BLEND);
   535             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
   536             break;
   537         }
   538         data->blendMode = blendMode;
   539     }
   540 }
   541 
   542 static int
   543 GL_RenderClear(SDL_Renderer * renderer)
   544 {
   545     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   546 
   547     GL_ActivateRenderer(renderer);
   548 
   549     data->glClearColor((GLfloat) renderer->r * inv255f,
   550                        (GLfloat) renderer->g * inv255f,
   551                        (GLfloat) renderer->b * inv255f,
   552                        (GLfloat) renderer->a * inv255f);
   553 
   554     data->glClear(GL_COLOR_BUFFER_BIT);
   555 
   556     return 0;
   557 }
   558 
   559 static int
   560 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   561                     int count)
   562 {
   563     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   564     int i;
   565 
   566     GL_ActivateRenderer(renderer);
   567 
   568     GL_SetBlendMode(data, renderer->blendMode);
   569 
   570     data->glColor4f((GLfloat) renderer->r * inv255f,
   571                     (GLfloat) renderer->g * inv255f,
   572                     (GLfloat) renderer->b * inv255f,
   573                     (GLfloat) renderer->a * inv255f);
   574 
   575     data->glBegin(GL_POINTS);
   576     for (i = 0; i < count; ++i) {
   577         data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   578     }
   579     data->glEnd();
   580 
   581     return 0;
   582 }
   583 
   584 static int
   585 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   586                    int count)
   587 {
   588     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   589     int i;
   590 
   591     GL_ActivateRenderer(renderer);
   592 
   593     GL_SetBlendMode(data, renderer->blendMode);
   594 
   595     data->glColor4f((GLfloat) renderer->r * inv255f,
   596                     (GLfloat) renderer->g * inv255f,
   597                     (GLfloat) renderer->b * inv255f,
   598                     (GLfloat) renderer->a * inv255f);
   599 
   600     if (count > 2 && 
   601         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
   602         data->glBegin(GL_LINE_LOOP);
   603         /* GL_LINE_LOOP takes care of the final segment */
   604         --count;
   605         for (i = 0; i < count; ++i) {
   606             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   607         }
   608         data->glEnd();
   609     } else {
   610 #if defined(__APPLE__) || defined(__WIN32__)
   611 #else
   612         int x1, y1, x2, y2;
   613 #endif
   614 
   615         data->glBegin(GL_LINE_STRIP);
   616         for (i = 0; i < count; ++i) {
   617             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
   618         }
   619         data->glEnd();
   620 
   621         /* The line is half open, so we need one more point to complete it.
   622          * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
   623          * If we have to, we can use vertical line and horizontal line textures
   624          * for vertical and horizontal lines, and then create custom textures
   625          * for diagonal lines and software render those.  It's terrible, but at
   626          * least it would be pixel perfect.
   627          */
   628         data->glBegin(GL_POINTS);
   629 #if defined(__APPLE__) || defined(__WIN32__)
   630         /* Mac OS X and Windows seem to always leave the second point open */
   631         data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
   632 #else
   633         /* Linux seems to leave the right-most or bottom-most point open */
   634         x1 = points[0].x;
   635         y1 = points[0].y;
   636         x2 = points[count-1].x;
   637         y2 = points[count-1].y;
   638 
   639         if (x1 > x2) {
   640             data->glVertex2f(0.5f + x1, 0.5f + y1);
   641         } else if (x2 > x1) {
   642             data->glVertex2f(0.5f + x2, 0.5f + y2);
   643         } else if (y1 > y2) {
   644             data->glVertex2f(0.5f + x1, 0.5f + y1);
   645         } else if (y2 > y1) {
   646             data->glVertex2f(0.5f + x2, 0.5f + y2);
   647         }
   648 #endif
   649         data->glEnd();
   650     }
   651 
   652     return 0;
   653 }
   654 
   655 static int
   656 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
   657 {
   658     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   659     int i;
   660 
   661     GL_ActivateRenderer(renderer);
   662 
   663     GL_SetBlendMode(data, renderer->blendMode);
   664 
   665     data->glColor4f((GLfloat) renderer->r * inv255f,
   666                     (GLfloat) renderer->g * inv255f,
   667                     (GLfloat) renderer->b * inv255f,
   668                     (GLfloat) renderer->a * inv255f);
   669 
   670     for (i = 0; i < count; ++i) {
   671         const SDL_Rect *rect = rects[i];
   672 
   673         data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
   674     }
   675 
   676     return 0;
   677 }
   678 
   679 static int
   680 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   681               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   682 {
   683     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   684     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   685     int minx, miny, maxx, maxy;
   686     GLfloat minu, maxu, minv, maxv;
   687 
   688     GL_ActivateRenderer(renderer);
   689 
   690     minx = dstrect->x;
   691     miny = dstrect->y;
   692     maxx = dstrect->x + dstrect->w;
   693     maxy = dstrect->y + dstrect->h;
   694 
   695     minu = (GLfloat) srcrect->x / texture->w;
   696     minu *= texturedata->texw;
   697     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
   698     maxu *= texturedata->texw;
   699     minv = (GLfloat) srcrect->y / texture->h;
   700     minv *= texturedata->texh;
   701     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
   702     maxv *= texturedata->texh;
   703 
   704     data->glEnable(texturedata->type);
   705     data->glBindTexture(texturedata->type, texturedata->texture);
   706 
   707     if (texture->modMode) {
   708         data->glColor4f((GLfloat) texture->r * inv255f,
   709                         (GLfloat) texture->g * inv255f,
   710                         (GLfloat) texture->b * inv255f,
   711                         (GLfloat) texture->a * inv255f);
   712     } else {
   713         data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
   714     }
   715 
   716     GL_SetBlendMode(data, texture->blendMode);
   717 
   718     data->glBegin(GL_TRIANGLE_STRIP);
   719     data->glTexCoord2f(minu, minv);
   720     data->glVertex2f((GLfloat) minx, (GLfloat) miny);
   721     data->glTexCoord2f(maxu, minv);
   722     data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
   723     data->glTexCoord2f(minu, maxv);
   724     data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
   725     data->glTexCoord2f(maxu, maxv);
   726     data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
   727     data->glEnd();
   728 
   729     data->glDisable(texturedata->type);
   730 
   731     return 0;
   732 }
   733 
   734 static int
   735 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   736                     Uint32 pixel_format, void * pixels, int pitch)
   737 {
   738     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   739     SDL_Window *window = renderer->window;
   740     GLint internalFormat;
   741     GLenum format, type;
   742     Uint8 *src, *dst, *tmp;
   743     int w, h, length, rows;
   744 
   745     GL_ActivateRenderer(renderer);
   746 
   747     if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
   748         /* FIXME: Do a temp copy to a format that is supported */
   749         SDL_SetError("Unsupported pixel format");
   750         return -1;
   751     }
   752 
   753     SDL_GetWindowSize(window, &w, &h);
   754 
   755     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
   756     data->glPixelStorei(GL_PACK_ROW_LENGTH,
   757                         (pitch / SDL_BYTESPERPIXEL(pixel_format)));
   758 
   759     data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
   760                        format, type, pixels);
   761 
   762     /* Flip the rows to be top-down */
   763     length = rect->w * SDL_BYTESPERPIXEL(pixel_format);
   764     src = (Uint8*)pixels + (rect->h-1)*pitch;
   765     dst = (Uint8*)pixels;
   766     tmp = SDL_stack_alloc(Uint8, length);
   767     rows = rect->h / 2;
   768     while (rows--) {
   769         SDL_memcpy(tmp, dst, length);
   770         SDL_memcpy(dst, src, length);
   771         SDL_memcpy(src, tmp, length);
   772         dst += pitch;
   773         src -= pitch;
   774     }
   775     SDL_stack_free(tmp);
   776 
   777     return 0;
   778 }
   779 
   780 static void
   781 GL_RenderPresent(SDL_Renderer * renderer)
   782 {
   783     GL_ActivateRenderer(renderer);
   784 
   785     SDL_GL_SwapWindow(renderer->window);
   786 }
   787 
   788 static void
   789 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   790 {
   791     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   792     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
   793 
   794     GL_ActivateRenderer(renderer);
   795 
   796     if (!data) {
   797         return;
   798     }
   799     if (data->texture) {
   800         renderdata->glDeleteTextures(1, &data->texture);
   801     }
   802     if (data->pixels) {
   803         SDL_free(data->pixels);
   804     }
   805     SDL_free(data);
   806     texture->driverdata = NULL;
   807 }
   808 
   809 static void
   810 GL_DestroyRenderer(SDL_Renderer * renderer)
   811 {
   812     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   813 
   814     if (data) {
   815         if (data->context) {
   816             /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
   817             SDL_GL_DeleteContext(data->context);
   818         }
   819         SDL_free(data);
   820     }
   821     SDL_free(renderer);
   822 }
   823 
   824 #endif /* SDL_VIDEO_RENDER_OGL */
   825 
   826 /* vi: set ts=4 sw=4 expandtab: */