comparison src/render/opengl/SDL_render_gl.c @ 5198:bb45ecd958d8

Renamed files for consistency
author Sam Lantinga <slouken@libsdl.org>
date Sat, 05 Feb 2011 12:01:11 -0800
parents src/render/opengl/SDL_renderer_gl.c@d976b67150c5
children 25ffd4e5255c
comparison
equal deleted inserted replaced
5197:69f47f2c1856 5198:bb45ecd958d8
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: */