OSDN Git Service

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