2 Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "SDL_config.h"
23 #if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
25 #include "SDL_hints.h"
27 #include "SDL_opengl.h"
28 #include "../SDL_sysrender.h"
29 #include "SDL_shaders_gl.h"
32 #include <OpenGL/OpenGL.h>
36 /* OpenGL renderer implementation */
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
42 /* Used to re-create the window with OpenGL capability */
43 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
45 static const float inv255f = 1.0f / 255.0f;
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,
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);
74 SDL_RenderDriver GL_RenderDriver = {
78 (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
80 {SDL_PIXELFORMAT_ARGB8888},
87 SDL_GLContext context;
88 SDL_bool GL_ARB_texture_rectangle_supported;
95 /* OpenGL functions */
96 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
97 #include "SDL_glfuncs.h"
100 /* Multitexture support */
101 SDL_bool GL_ARB_multitexture_supported;
102 PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
103 GLint num_texture_units;
106 GL_ShaderContext *shaders;
120 SDL_Rect locked_rect;
122 /* YV12 texture support */
130 GL_SetError(const char *prefix, GLenum result)
136 error = "GL_NO_ERROR";
138 case GL_INVALID_ENUM:
139 error = "GL_INVALID_ENUM";
141 case GL_INVALID_VALUE:
142 error = "GL_INVALID_VALUE";
144 case GL_INVALID_OPERATION:
145 error = "GL_INVALID_OPERATION";
147 case GL_STACK_OVERFLOW:
148 error = "GL_STACK_OVERFLOW";
150 case GL_STACK_UNDERFLOW:
151 error = "GL_STACK_UNDERFLOW";
153 case GL_OUT_OF_MEMORY:
154 error = "GL_OUT_OF_MEMORY";
156 case GL_TABLE_TOO_LARGE:
157 error = "GL_TABLE_TOO_LARGE";
163 SDL_SetError("%s: %s", prefix, error);
167 GL_LoadFunctions(GL_RenderData * data)
169 #ifdef __SDL_NOGETPROCADDR__
170 #define SDL_PROC(ret,func,params) data->func=func;
172 #define SDL_PROC(ret,func,params) \
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()); \
180 #endif /* __SDL_NOGETPROCADDR__ */
182 #include "SDL_glfuncs.h"
187 static SDL_GLContext SDL_CurrentContext = NULL;
190 GL_ActivateRenderer(SDL_Renderer * renderer)
192 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
194 if (SDL_CurrentContext != data->context) {
195 if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
198 SDL_CurrentContext = data->context;
200 GL_UpdateViewport(renderer);
205 /* This is called if we need to invalidate all of the SDL OpenGL state */
207 GL_ResetState(SDL_Renderer *renderer)
209 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
211 if (SDL_CurrentContext == data->context) {
212 GL_UpdateViewport(renderer);
214 GL_ActivateRenderer(renderer);
217 data->current.shader = SHADER_NONE;
218 data->current.color = 0;
219 data->current.blendMode = -1;
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);*/
226 data->glMatrixMode(GL_MODELVIEW);
227 data->glLoadIdentity();
231 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
233 SDL_Renderer *renderer;
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);
248 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
254 data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
256 GL_DestroyRenderer(renderer);
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;
281 data->context = SDL_GL_CreateContext(window);
282 if (!data->context) {
283 GL_DestroyRenderer(renderer);
286 if (SDL_GL_MakeCurrent(window, data->context) < 0) {
287 GL_DestroyRenderer(renderer);
291 if (GL_LoadFunctions(data) < 0) {
292 GL_DestroyRenderer(renderer);
297 /* Enable multi-threaded rendering */
298 /* Disabled until Ryan finishes his VBO/PBO code...
299 CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
303 if (flags & SDL_RENDERER_PRESENTVSYNC) {
304 SDL_GL_SetSwapInterval(1);
306 SDL_GL_SetSwapInterval(0);
308 if (SDL_GL_GetSwapInterval() > 0) {
309 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
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;
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;
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);
331 /* Check for shader support */
332 hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);
333 if (!hint || *hint != '0') {
334 data->shaders = GL_CreateShaderContext();
336 SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
337 data->shaders ? "ENABLED" : "DISABLED");
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;
345 /* Set up parameters for rendering */
346 GL_ResetState(renderer);
352 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
354 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
355 /* Rebind the context to the window area and update matrices */
356 SDL_CurrentContext = NULL;
360 static __inline__ int
361 power_of_2(int input)
365 while (value < input) {
371 static __inline__ SDL_bool
372 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
373 GLint* internalFormat, GLenum* format, GLenum* type)
375 switch (pixel_format) {
376 case SDL_PIXELFORMAT_ARGB8888:
377 *internalFormat = GL_RGBA8;
379 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
381 case SDL_PIXELFORMAT_YV12:
382 case SDL_PIXELFORMAT_IYUV:
383 *internalFormat = GL_LUMINANCE;
384 *format = GL_LUMINANCE;
385 *type = GL_UNSIGNED_BYTE;
394 GetScaleQuality(void)
396 const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
398 if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
406 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
408 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
409 GL_TextureData *data;
410 GLint internalFormat;
412 int texture_w, texture_h;
416 GL_ActivateRenderer(renderer);
418 if (!convert_format(renderdata, texture->format, &internalFormat,
420 SDL_SetError("Texture format %s not supported by OpenGL",
421 SDL_GetPixelFormatName(texture->format));
425 data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
431 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
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);
440 data->pixels = SDL_calloc(1, size);
448 texture->driverdata = data;
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;
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;
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.
476 if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
477 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
479 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
483 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
484 #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC
486 #ifndef STORAGE_CACHED_APPLE
487 #define STORAGE_CACHED_APPLE 0x85BE
489 #ifndef STORAGE_SHARED_APPLE
490 #define STORAGE_SHARED_APPLE 0x85BF
492 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
493 renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
494 GL_STORAGE_SHARED_APPLE);
496 renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
497 GL_STORAGE_CACHED_APPLE);
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);
513 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
514 texture_h, 0, format, type, NULL);
516 renderdata->glDisable(data->type);
517 result = renderdata->glGetError();
518 if (result != GL_NO_ERROR) {
519 GL_SetError("glTexImage2D()", result);
523 if (texture->format == SDL_PIXELFORMAT_YV12 ||
524 texture->format == SDL_PIXELFORMAT_IYUV) {
525 data->yuv = SDL_TRUE;
527 renderdata->glGenTextures(1, &data->utexture);
528 renderdata->glGenTextures(1, &data->vtexture);
529 renderdata->glEnable(data->type);
531 renderdata->glBindTexture(data->type, data->utexture);
532 renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
534 renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
536 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
538 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
540 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
541 texture_h/2, 0, format, type, NULL);
543 renderdata->glBindTexture(data->type, data->vtexture);
544 renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
546 renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
548 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
550 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
552 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
553 texture_h/2, 0, format, type, NULL);
555 renderdata->glDisable(data->type);
561 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
562 const SDL_Rect * rect, const void *pixels, int pitch)
564 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
565 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
568 GL_ActivateRenderer(renderer);
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,
580 renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
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);
587 renderdata->glBindTexture(data->type, data->utexture);
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);
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);
598 renderdata->glBindTexture(data->type, data->vtexture);
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);
604 renderdata->glDisable(data->type);
605 result = renderdata->glGetError();
606 if (result != GL_NO_ERROR) {
607 GL_SetError("glTexSubImage2D()", result);
614 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
615 const SDL_Rect * rect, void **pixels, int *pitch)
617 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
619 data->locked_rect = *rect;
621 (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
622 rect->x * SDL_BYTESPERPIXEL(texture->format));
623 *pitch = data->pitch;
628 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
630 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
631 const SDL_Rect *rect;
634 rect = &data->locked_rect;
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);
642 GL_UpdateViewport(SDL_Renderer * renderer)
644 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
646 if (SDL_CurrentContext != data->context) {
647 /* We'll update the viewport after we rebind the context */
651 data->glViewport(renderer->viewport.x, renderer->viewport.y,
652 renderer->viewport.w, renderer->viewport.h);
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);
664 GL_SetShader(GL_RenderData * data, GL_Shader shader)
666 if (data->shaders && shader != data->current.shader) {
667 GL_SelectShader(data->shaders, shader);
668 data->current.shader = shader;
673 GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
675 Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
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;
687 GL_SetBlendMode(GL_RenderData * data, int blendMode)
689 if (blendMode != data->current.blendMode) {
691 case SDL_BLENDMODE_NONE:
692 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
693 data->glDisable(GL_BLEND);
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);
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);
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);
711 data->current.blendMode = blendMode;
716 GL_SetDrawingState(SDL_Renderer * renderer)
718 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
720 GL_ActivateRenderer(renderer);
722 GL_SetColor(data, renderer->r,
727 GL_SetBlendMode(data, renderer->blendMode);
729 GL_SetShader(data, SHADER_SOLID);
733 GL_RenderClear(SDL_Renderer * renderer)
735 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
737 GL_ActivateRenderer(renderer);
739 data->glClearColor((GLfloat) renderer->r * inv255f,
740 (GLfloat) renderer->g * inv255f,
741 (GLfloat) renderer->b * inv255f,
742 (GLfloat) renderer->a * inv255f);
744 data->glClear(GL_COLOR_BUFFER_BIT);
750 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
753 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
756 GL_SetDrawingState(renderer);
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);
768 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
771 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
774 GL_SetDrawingState(renderer);
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 */
781 for (i = 0; i < count; ++i) {
782 data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
786 #if defined(__APPLE__) || defined(__WIN32__)
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);
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.
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);
809 /* Linux seems to leave the right-most or bottom-most point open */
812 x2 = points[count-1].x;
813 y2 = points[count-1].y;
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);
832 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count)
834 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
837 GL_SetDrawingState(renderer);
839 for (i = 0; i < count; ++i) {
840 const SDL_Rect *rect = &rects[i];
842 data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
849 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
850 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
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;
857 GL_ActivateRenderer(renderer);
859 data->glEnable(texturedata->type);
860 if (texturedata->yuv) {
861 data->glActiveTextureARB(GL_TEXTURE2_ARB);
862 data->glBindTexture(texturedata->type, texturedata->vtexture);
864 data->glActiveTextureARB(GL_TEXTURE1_ARB);
865 data->glBindTexture(texturedata->type, texturedata->utexture);
867 data->glActiveTextureARB(GL_TEXTURE0_ARB);
869 data->glBindTexture(texturedata->type, texturedata->texture);
871 if (texture->modMode) {
872 GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
874 GL_SetColor(data, 255, 255, 255, 255);
877 GL_SetBlendMode(data, texture->blendMode);
879 if (texturedata->yuv) {
880 GL_SetShader(data, SHADER_YV12);
882 GL_SetShader(data, SHADER_RGB);
887 maxx = dstrect->x + dstrect->w;
888 maxy = dstrect->y + dstrect->h;
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;
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);
910 data->glDisable(texturedata->type);
916 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
917 Uint32 pixel_format, void * pixels, int pitch)
919 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
920 SDL_Window *window = renderer->window;
921 Uint32 temp_format = SDL_PIXELFORMAT_ARGB8888;
924 GLint internalFormat;
926 Uint8 *src, *dst, *tmp;
927 int w, h, length, rows;
930 GL_ActivateRenderer(renderer);
932 temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
933 temp_pixels = SDL_malloc(rect->h * temp_pitch);
939 convert_format(data, temp_format, &internalFormat, &format, &type);
941 SDL_GetWindowSize(window, &w, &h);
943 data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
944 data->glPixelStorei(GL_PACK_ROW_LENGTH,
945 (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
947 data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
948 format, type, temp_pixels);
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);
957 SDL_memcpy(tmp, dst, length);
958 SDL_memcpy(dst, src, length);
959 SDL_memcpy(src, tmp, length);
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);
974 GL_RenderPresent(SDL_Renderer * renderer)
976 GL_ActivateRenderer(renderer);
978 SDL_GL_SwapWindow(renderer->window);
982 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
984 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
985 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
987 GL_ActivateRenderer(renderer);
993 renderdata->glDeleteTextures(1, &data->texture);
996 renderdata->glDeleteTextures(1, &data->utexture);
997 renderdata->glDeleteTextures(1, &data->vtexture);
1000 SDL_free(data->pixels);
1003 texture->driverdata = NULL;
1007 GL_DestroyRenderer(SDL_Renderer * renderer)
1009 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1012 if (data->shaders) {
1013 GL_DestroyShaderContext(data->shaders);
1015 if (data->context) {
1016 /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
1017 SDL_GL_DeleteContext(data->context);
1024 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
1026 /* vi: set ts=4 sw=4 expandtab: */