Mercurial > sdl-ios-xcode
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: */ |