Mercurial > sdl-ios-xcode
comparison src/render/opengl/SDL_renderer_gl.c @ 5157:fb424691cfc7
Moved the rendering code out to a separate directory in the hope that it can someday be completely decoupled from the rest of the library and be expanded to an awesome 2D on 3D library.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Wed, 02 Feb 2011 14:34:54 -0800 |
parents | src/video/SDL_renderer_gl.c@1435f8a6425c |
children | 307ccc9c135e |
comparison
equal
deleted
inserted
replaced
5156:3e4086b3bcd2 | 5157:fb424691cfc7 |
---|---|
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 /* !!! FIXME: this should go in a higher level than the GL renderer. */ | |
41 static __inline__ int | |
42 bytes_per_pixel(const Uint32 format) | |
43 { | |
44 if (!SDL_ISPIXELFORMAT_FOURCC(format)) { | |
45 return SDL_BYTESPERPIXEL(format); | |
46 } | |
47 | |
48 /* FOURCC format */ | |
49 switch (format) { | |
50 case SDL_PIXELFORMAT_YV12: | |
51 case SDL_PIXELFORMAT_IYUV: | |
52 case SDL_PIXELFORMAT_YUY2: | |
53 case SDL_PIXELFORMAT_UYVY: | |
54 case SDL_PIXELFORMAT_YVYU: | |
55 return 2; | |
56 default: | |
57 return 1; /* shouldn't ever hit this. */ | |
58 } | |
59 } | |
60 | |
61 /* Used to re-create the window with OpenGL capability */ | |
62 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); | |
63 | |
64 static const float inv255f = 1.0f / 255.0f; | |
65 | |
66 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags); | |
67 static void GL_WindowEvent(SDL_Renderer * renderer, | |
68 const SDL_WindowEvent *event); | |
69 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
70 static int GL_QueryTexturePixels(SDL_Renderer * renderer, | |
71 SDL_Texture * texture, void **pixels, | |
72 int *pitch); | |
73 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
74 const SDL_Rect * rect, const void *pixels, | |
75 int pitch); | |
76 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
77 const SDL_Rect * rect, int markDirty, void **pixels, | |
78 int *pitch); | |
79 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
80 static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
81 int numrects, const SDL_Rect * rects); | |
82 static int GL_RenderClear(SDL_Renderer * renderer); | |
83 static int GL_RenderDrawPoints(SDL_Renderer * renderer, | |
84 const SDL_Point * points, int count); | |
85 static int GL_RenderDrawLines(SDL_Renderer * renderer, | |
86 const SDL_Point * points, int count); | |
87 static int GL_RenderFillRects(SDL_Renderer * renderer, | |
88 const SDL_Rect ** rects, int count); | |
89 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, | |
90 const SDL_Rect * srcrect, const SDL_Rect * dstrect); | |
91 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, | |
92 Uint32 pixel_format, void * pixels, int pitch); | |
93 static int GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, | |
94 Uint32 pixel_format, const void * pixels, int pitch); | |
95 static void GL_RenderPresent(SDL_Renderer * renderer); | |
96 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
97 static void GL_DestroyRenderer(SDL_Renderer * renderer); | |
98 | |
99 | |
100 SDL_RenderDriver GL_RenderDriver = { | |
101 GL_CreateRenderer, | |
102 { | |
103 "opengl", | |
104 (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), | |
105 13, | |
106 { | |
107 SDL_PIXELFORMAT_RGB332, | |
108 SDL_PIXELFORMAT_RGB444, | |
109 SDL_PIXELFORMAT_RGB555, | |
110 SDL_PIXELFORMAT_ARGB4444, | |
111 SDL_PIXELFORMAT_ARGB1555, | |
112 SDL_PIXELFORMAT_RGB565, | |
113 SDL_PIXELFORMAT_RGB24, | |
114 SDL_PIXELFORMAT_BGR24, | |
115 SDL_PIXELFORMAT_RGB888, | |
116 SDL_PIXELFORMAT_BGR888, | |
117 SDL_PIXELFORMAT_ARGB8888, | |
118 SDL_PIXELFORMAT_ABGR8888, | |
119 SDL_PIXELFORMAT_ARGB2101010}, | |
120 0, | |
121 0} | |
122 }; | |
123 | |
124 typedef struct | |
125 { | |
126 SDL_GLContext context; | |
127 SDL_bool updateSize; | |
128 SDL_bool GL_ARB_texture_rectangle_supported; | |
129 SDL_bool GL_EXT_paletted_texture_supported; | |
130 SDL_bool GL_APPLE_ycbcr_422_supported; | |
131 SDL_bool GL_MESA_ycbcr_texture_supported; | |
132 SDL_bool GL_ARB_fragment_program_supported; | |
133 int blendMode; | |
134 | |
135 /* OpenGL functions */ | |
136 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; | |
137 #include "../../video/SDL_glfuncs.h" | |
138 #undef SDL_PROC | |
139 | |
140 void (*glTextureRangeAPPLE) (GLenum target, GLsizei length, | |
141 const GLvoid * pointer); | |
142 | |
143 PFNGLGETPROGRAMIVARBPROC glGetProgramivARB; | |
144 PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB; | |
145 PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB; | |
146 PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB; | |
147 PFNGLGENPROGRAMSARBPROC glGenProgramsARB; | |
148 PFNGLBINDPROGRAMARBPROC glBindProgramARB; | |
149 PFNGLPROGRAMSTRINGARBPROC glProgramStringARB; | |
150 | |
151 /* (optional) fragment programs */ | |
152 GLuint fragment_program_UYVY; | |
153 } GL_RenderData; | |
154 | |
155 typedef struct | |
156 { | |
157 GLuint texture; | |
158 GLuint shader; | |
159 GLenum type; | |
160 GLfloat texw; | |
161 GLfloat texh; | |
162 GLenum format; | |
163 GLenum formattype; | |
164 Uint8 *palette; | |
165 void *pixels; | |
166 int pitch; | |
167 SDL_DirtyRectList dirty; | |
168 int HACK_RYAN_FIXME; | |
169 } GL_TextureData; | |
170 | |
171 | |
172 static void | |
173 GL_SetError(const char *prefix, GLenum result) | |
174 { | |
175 const char *error; | |
176 | |
177 switch (result) { | |
178 case GL_NO_ERROR: | |
179 error = "GL_NO_ERROR"; | |
180 break; | |
181 case GL_INVALID_ENUM: | |
182 error = "GL_INVALID_ENUM"; | |
183 break; | |
184 case GL_INVALID_VALUE: | |
185 error = "GL_INVALID_VALUE"; | |
186 break; | |
187 case GL_INVALID_OPERATION: | |
188 error = "GL_INVALID_OPERATION"; | |
189 break; | |
190 case GL_STACK_OVERFLOW: | |
191 error = "GL_STACK_OVERFLOW"; | |
192 break; | |
193 case GL_STACK_UNDERFLOW: | |
194 error = "GL_STACK_UNDERFLOW"; | |
195 break; | |
196 case GL_OUT_OF_MEMORY: | |
197 error = "GL_OUT_OF_MEMORY"; | |
198 break; | |
199 case GL_TABLE_TOO_LARGE: | |
200 error = "GL_TABLE_TOO_LARGE"; | |
201 break; | |
202 default: | |
203 error = "UNKNOWN"; | |
204 break; | |
205 } | |
206 SDL_SetError("%s: %s", prefix, error); | |
207 } | |
208 | |
209 static int | |
210 GL_LoadFunctions(GL_RenderData * data) | |
211 { | |
212 #ifdef __SDL_NOGETPROCADDR__ | |
213 #define SDL_PROC(ret,func,params) data->func=func; | |
214 #else | |
215 #define SDL_PROC(ret,func,params) \ | |
216 do { \ | |
217 data->func = SDL_GL_GetProcAddress(#func); \ | |
218 if ( ! data->func ) { \ | |
219 SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \ | |
220 return -1; \ | |
221 } \ | |
222 } while ( 0 ); | |
223 #endif /* __SDL_NOGETPROCADDR__ */ | |
224 | |
225 #include "../../video/SDL_glfuncs.h" | |
226 #undef SDL_PROC | |
227 return 0; | |
228 } | |
229 | |
230 SDL_Renderer * | |
231 GL_CreateRenderer(SDL_Window * window, Uint32 flags) | |
232 { | |
233 SDL_Renderer *renderer; | |
234 GL_RenderData *data; | |
235 GLint value; | |
236 Uint32 window_flags; | |
237 | |
238 window_flags = SDL_GetWindowFlags(window); | |
239 if (!(window_flags & SDL_WINDOW_OPENGL)) { | |
240 if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) { | |
241 return NULL; | |
242 } | |
243 } | |
244 | |
245 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); | |
246 if (!renderer) { | |
247 SDL_OutOfMemory(); | |
248 return NULL; | |
249 } | |
250 | |
251 data = (GL_RenderData *) SDL_calloc(1, sizeof(*data)); | |
252 if (!data) { | |
253 GL_DestroyRenderer(renderer); | |
254 SDL_OutOfMemory(); | |
255 return NULL; | |
256 } | |
257 | |
258 renderer->WindowEvent = GL_WindowEvent; | |
259 renderer->CreateTexture = GL_CreateTexture; | |
260 renderer->QueryTexturePixels = GL_QueryTexturePixels; | |
261 renderer->UpdateTexture = GL_UpdateTexture; | |
262 renderer->LockTexture = GL_LockTexture; | |
263 renderer->UnlockTexture = GL_UnlockTexture; | |
264 renderer->DirtyTexture = GL_DirtyTexture; | |
265 renderer->RenderClear = GL_RenderClear; | |
266 renderer->RenderDrawPoints = GL_RenderDrawPoints; | |
267 renderer->RenderDrawLines = GL_RenderDrawLines; | |
268 renderer->RenderFillRects = GL_RenderFillRects; | |
269 renderer->RenderCopy = GL_RenderCopy; | |
270 renderer->RenderReadPixels = GL_RenderReadPixels; | |
271 renderer->RenderWritePixels = GL_RenderWritePixels; | |
272 renderer->RenderPresent = GL_RenderPresent; | |
273 renderer->DestroyTexture = GL_DestroyTexture; | |
274 renderer->DestroyRenderer = GL_DestroyRenderer; | |
275 renderer->info = GL_RenderDriver.info; | |
276 renderer->window = window; | |
277 renderer->driverdata = data; | |
278 | |
279 renderer->info.flags = SDL_RENDERER_ACCELERATED; | |
280 | |
281 if (GL_LoadFunctions(data) < 0) { | |
282 GL_DestroyRenderer(renderer); | |
283 return NULL; | |
284 } | |
285 | |
286 data->context = SDL_GL_CreateContext(window); | |
287 if (!data->context) { | |
288 GL_DestroyRenderer(renderer); | |
289 return NULL; | |
290 } | |
291 if (SDL_GL_MakeCurrent(window, data->context) < 0) { | |
292 GL_DestroyRenderer(renderer); | |
293 return NULL; | |
294 } | |
295 #ifdef __MACOSX__ | |
296 /* Enable multi-threaded rendering */ | |
297 /* Disabled until Ryan finishes his VBO/PBO code... | |
298 CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine); | |
299 */ | |
300 #endif | |
301 | |
302 if (flags & SDL_RENDERER_PRESENTVSYNC) { | |
303 SDL_GL_SetSwapInterval(1); | |
304 } else { | |
305 SDL_GL_SetSwapInterval(0); | |
306 } | |
307 if (SDL_GL_GetSwapInterval() > 0) { | |
308 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; | |
309 } | |
310 | |
311 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); | |
312 renderer->info.max_texture_width = value; | |
313 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); | |
314 renderer->info.max_texture_height = value; | |
315 | |
316 if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") | |
317 || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) { | |
318 data->GL_ARB_texture_rectangle_supported = SDL_TRUE; | |
319 } | |
320 if (SDL_GL_ExtensionSupported("GL_APPLE_ycbcr_422")) { | |
321 data->GL_APPLE_ycbcr_422_supported = SDL_TRUE; | |
322 } | |
323 if (SDL_GL_ExtensionSupported("GL_MESA_ycbcr_texture")) { | |
324 data->GL_MESA_ycbcr_texture_supported = SDL_TRUE; | |
325 } | |
326 if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) { | |
327 data->glTextureRangeAPPLE = | |
328 (void (*)(GLenum, GLsizei, const GLvoid *)) | |
329 SDL_GL_GetProcAddress("glTextureRangeAPPLE"); | |
330 } | |
331 | |
332 /* we might use fragment programs for YUV data, etc. */ | |
333 if (SDL_GL_ExtensionSupported("GL_ARB_fragment_program")) { | |
334 /* !!! FIXME: this doesn't check for errors. */ | |
335 /* !!! FIXME: this should really reuse the glfuncs.h stuff. */ | |
336 data->glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) | |
337 SDL_GL_GetProcAddress("glGetProgramivARB"); | |
338 data->glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) | |
339 SDL_GL_GetProcAddress("glGetProgramStringARB"); | |
340 data->glProgramLocalParameter4fvARB = | |
341 (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) | |
342 SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB"); | |
343 data->glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) | |
344 SDL_GL_GetProcAddress("glDeleteProgramsARB"); | |
345 data->glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) | |
346 SDL_GL_GetProcAddress("glGenProgramsARB"); | |
347 data->glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) | |
348 SDL_GL_GetProcAddress("glBindProgramARB"); | |
349 data->glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) | |
350 SDL_GL_GetProcAddress("glProgramStringARB"); | |
351 data->GL_ARB_fragment_program_supported = SDL_TRUE; | |
352 } | |
353 | |
354 /* Set up parameters for rendering */ | |
355 data->blendMode = -1; | |
356 data->glDisable(GL_DEPTH_TEST); | |
357 data->glDisable(GL_CULL_FACE); | |
358 /* This ended up causing video discrepancies between OpenGL and Direct3D */ | |
359 /*data->glEnable(GL_LINE_SMOOTH);*/ | |
360 if (data->GL_ARB_texture_rectangle_supported) { | |
361 data->glEnable(GL_TEXTURE_RECTANGLE_ARB); | |
362 } else { | |
363 data->glEnable(GL_TEXTURE_2D); | |
364 } | |
365 data->updateSize = SDL_TRUE; | |
366 | |
367 return renderer; | |
368 } | |
369 | |
370 static SDL_GLContext SDL_CurrentContext = NULL; | |
371 | |
372 static int | |
373 GL_ActivateRenderer(SDL_Renderer * renderer) | |
374 { | |
375 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
376 SDL_Window *window = renderer->window; | |
377 | |
378 if (SDL_CurrentContext != data->context) { | |
379 if (SDL_GL_MakeCurrent(window, data->context) < 0) { | |
380 return -1; | |
381 } | |
382 SDL_CurrentContext = data->context; | |
383 } | |
384 if (data->updateSize) { | |
385 int w, h; | |
386 | |
387 SDL_GetWindowSize(window, &w, &h); | |
388 data->glMatrixMode(GL_PROJECTION); | |
389 data->glLoadIdentity(); | |
390 data->glMatrixMode(GL_MODELVIEW); | |
391 data->glLoadIdentity(); | |
392 data->glViewport(0, 0, w, h); | |
393 data->glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 1.0); | |
394 data->updateSize = SDL_FALSE; | |
395 } | |
396 return 0; | |
397 } | |
398 | |
399 static void | |
400 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) | |
401 { | |
402 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
403 | |
404 if (event->event == SDL_WINDOWEVENT_RESIZED) { | |
405 /* Rebind the context to the window area and update matrices */ | |
406 SDL_CurrentContext = NULL; | |
407 data->updateSize = SDL_TRUE; | |
408 } | |
409 } | |
410 | |
411 static __inline__ int | |
412 power_of_2(int input) | |
413 { | |
414 int value = 1; | |
415 | |
416 while (value < input) { | |
417 value <<= 1; | |
418 } | |
419 return value; | |
420 } | |
421 | |
422 | |
423 //#define DEBUG_PROGRAM_COMPILE 1 | |
424 | |
425 static void | |
426 set_shader_error(GL_RenderData * data, const char *prefix) | |
427 { | |
428 GLint pos = 0; | |
429 const GLubyte *errstr; | |
430 data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); | |
431 errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB); | |
432 SDL_SetError("%s: shader compile error at position %d: %s", | |
433 prefix, (int) pos, (const char *) errstr); | |
434 } | |
435 | |
436 static GLuint | |
437 compile_shader(GL_RenderData * data, GLenum shader_type, const char *_code) | |
438 { | |
439 const int have_texture_rects = data->GL_ARB_texture_rectangle_supported; | |
440 const char *replacement = have_texture_rects ? "RECT" : "2D"; | |
441 const size_t replacementlen = SDL_strlen(replacement); | |
442 const char *token = "%TEXTURETARGET%"; | |
443 const size_t tokenlen = SDL_strlen(token); | |
444 char *code = NULL; | |
445 char *ptr = NULL; | |
446 GLuint program = 0; | |
447 | |
448 /* | |
449 * The TEX instruction needs a different target depending on what we use. | |
450 * To handle this, we use "%TEXTURETARGET%" and replace the string before | |
451 * compiling the shader. | |
452 */ | |
453 code = SDL_strdup(_code); | |
454 if (code == NULL) | |
455 return 0; | |
456 | |
457 for (ptr = SDL_strstr(code, token); ptr; ptr = SDL_strstr(ptr + 1, token)) { | |
458 SDL_memcpy(ptr, replacement, replacementlen); | |
459 SDL_memmove(ptr + replacementlen, ptr + tokenlen, | |
460 SDL_strlen(ptr + tokenlen) + 1); | |
461 } | |
462 | |
463 #if DEBUG_PROGRAM_COMPILE | |
464 printf("compiling shader:\n%s\n\n", code); | |
465 #endif | |
466 | |
467 data->glGetError(); /* flush any existing error state. */ | |
468 data->glGenProgramsARB(1, &program); | |
469 data->glBindProgramARB(shader_type, program); | |
470 data->glProgramStringARB(shader_type, GL_PROGRAM_FORMAT_ASCII_ARB, | |
471 (GLsizei)SDL_strlen(code), code); | |
472 | |
473 SDL_free(code); | |
474 | |
475 if (data->glGetError() == GL_INVALID_OPERATION) { | |
476 #if DEBUG_PROGRAM_COMPILE | |
477 GLint pos = 0; | |
478 const GLubyte *errstr; | |
479 data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); | |
480 errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB); | |
481 printf("program compile error at position %d: %s\n\n", | |
482 (int) pos, (const char *) errstr); | |
483 #endif | |
484 data->glBindProgramARB(shader_type, 0); | |
485 data->glDeleteProgramsARB(1, &program); | |
486 return 0; | |
487 } | |
488 | |
489 return program; | |
490 } | |
491 | |
492 | |
493 /* | |
494 * Fragment program that renders from UYVY textures. | |
495 * The UYVY to RGB equasion is: | |
496 * R = 1.164(Y-16) + 1.596(Cr-128) | |
497 * G = 1.164(Y-16) - 0.813(Cr-128) - 0.391(Cb-128) | |
498 * B = 1.164(Y-16) + 2.018(Cb-128) | |
499 * Byte layout is Cb, Y1, Cr, Y2, stored in the R, G, B, A channels. | |
500 * 4 bytes == 2 pixels: Y1/Cb/Cr, Y2/Cb/Cr | |
501 * | |
502 * !!! FIXME: this ignores blendmodes, etc. | |
503 * !!! FIXME: this could be more efficient...use a dot product for green, etc. | |
504 */ | |
505 static const char *fragment_program_UYVY_source_code = "!!ARBfp1.0\n" | |
506 /* outputs... */ | |
507 "OUTPUT outcolor = result.color;\n" | |
508 /* scratch registers... */ | |
509 "TEMP uyvy;\n" "TEMP luminance;\n" "TEMP work;\n" | |
510 /* Halve the coordinates to grab the correct 32 bits for the fragment. */ | |
511 "MUL work, fragment.texcoord, { 0.5, 1.0, 1.0, 1.0 };\n" | |
512 /* Sample the YUV texture. Cb, Y1, Cr, Y2, are stored in x, y, z, w. */ | |
513 "TEX uyvy, work, texture[0], %TEXTURETARGET%;\n" | |
514 /* Do subtractions (128/255, 16/255, 128/255, 16/255) */ | |
515 "SUB uyvy, uyvy, { 0.501960784313726, 0.06274509803922, 0.501960784313726, 0.06274509803922 };\n" | |
516 /* Choose the luminance component by texcoord. */ | |
517 /* !!! FIXME: laziness wins out for now... just average Y1 and Y2. */ | |
518 "ADD luminance, uyvy.yyyy, uyvy.wwww;\n" | |
519 "MUL luminance, luminance, { 0.5, 0.5, 0.5, 0.5 };\n" | |
520 /* Multiply luminance by its magic value. */ | |
521 "MUL luminance, luminance, { 1.164, 1.164, 1.164, 1.164 };\n" | |
522 /* uyvy.xyzw becomes Cr/Cr/Cb/Cb, with multiplications. */ | |
523 "MUL uyvy, uyvy.zzxx, { 1.596, -0.813, 2.018, -0.391 };\n" | |
524 /* Add luminance to Cr and Cb, store to RGB channels. */ | |
525 "ADD work.rgb, luminance, uyvy;\n" | |
526 /* Do final addition for Green channel. (!!! FIXME: this should be a DPH?) */ | |
527 "ADD work.g, work.g, uyvy.w;\n" | |
528 /* Make sure alpha channel is fully opaque. (!!! FIXME: blend modes!) */ | |
529 "MOV work.a, { 1.0 };\n" | |
530 /* Store out the final fragment color... */ | |
531 "MOV outcolor, work;\n" | |
532 /* ...and we're done! */ | |
533 "END\n"; | |
534 | |
535 static __inline__ SDL_bool | |
536 convert_format(GL_RenderData *renderdata, Uint32 pixel_format, | |
537 GLint* internalFormat, GLenum* format, GLenum* type) | |
538 { | |
539 switch (pixel_format) { | |
540 case SDL_PIXELFORMAT_RGB332: | |
541 *internalFormat = GL_R3_G3_B2; | |
542 *format = GL_RGB; | |
543 *type = GL_UNSIGNED_BYTE_3_3_2; | |
544 break; | |
545 case SDL_PIXELFORMAT_RGB444: | |
546 *internalFormat = GL_RGB4; | |
547 *format = GL_RGB; | |
548 *type = GL_UNSIGNED_SHORT_4_4_4_4; | |
549 break; | |
550 case SDL_PIXELFORMAT_RGB555: | |
551 *internalFormat = GL_RGB5; | |
552 *format = GL_RGB; | |
553 *type = GL_UNSIGNED_SHORT_5_5_5_1; | |
554 break; | |
555 case SDL_PIXELFORMAT_ARGB4444: | |
556 *internalFormat = GL_RGBA4; | |
557 *format = GL_BGRA; | |
558 *type = GL_UNSIGNED_SHORT_4_4_4_4_REV; | |
559 break; | |
560 case SDL_PIXELFORMAT_ARGB1555: | |
561 *internalFormat = GL_RGB5_A1; | |
562 *format = GL_BGRA; | |
563 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV; | |
564 break; | |
565 case SDL_PIXELFORMAT_RGB565: | |
566 *internalFormat = GL_RGB8; | |
567 *format = GL_RGB; | |
568 *type = GL_UNSIGNED_SHORT_5_6_5; | |
569 break; | |
570 case SDL_PIXELFORMAT_RGB24: | |
571 *internalFormat = GL_RGB8; | |
572 *format = GL_RGB; | |
573 *type = GL_UNSIGNED_BYTE; | |
574 break; | |
575 case SDL_PIXELFORMAT_RGB888: | |
576 *internalFormat = GL_RGB8; | |
577 *format = GL_BGRA; | |
578 *type = GL_UNSIGNED_BYTE; | |
579 break; | |
580 case SDL_PIXELFORMAT_BGR24: | |
581 *internalFormat = GL_RGB8; | |
582 *format = GL_BGR; | |
583 *type = GL_UNSIGNED_BYTE; | |
584 break; | |
585 case SDL_PIXELFORMAT_BGR888: | |
586 *internalFormat = GL_RGB8; | |
587 *format = GL_RGBA; | |
588 *type = GL_UNSIGNED_BYTE; | |
589 break; | |
590 case SDL_PIXELFORMAT_ARGB8888: | |
591 #ifdef __MACOSX__ | |
592 *internalFormat = GL_RGBA; | |
593 *format = GL_BGRA; | |
594 *type = GL_UNSIGNED_INT_8_8_8_8_REV; | |
595 #else | |
596 *internalFormat = GL_RGBA8; | |
597 *format = GL_BGRA; | |
598 *type = GL_UNSIGNED_BYTE; | |
599 #endif | |
600 break; | |
601 case SDL_PIXELFORMAT_ABGR8888: | |
602 *internalFormat = GL_RGBA8; | |
603 *format = GL_RGBA; | |
604 *type = GL_UNSIGNED_BYTE; | |
605 break; | |
606 case SDL_PIXELFORMAT_ARGB2101010: | |
607 *internalFormat = GL_RGB10_A2; | |
608 *format = GL_BGRA; | |
609 *type = GL_UNSIGNED_INT_2_10_10_10_REV; | |
610 break; | |
611 case SDL_PIXELFORMAT_UYVY: | |
612 if (renderdata->GL_APPLE_ycbcr_422_supported) { | |
613 *internalFormat = GL_RGB; | |
614 *format = GL_YCBCR_422_APPLE; | |
615 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
616 *type = GL_UNSIGNED_SHORT_8_8_APPLE; | |
617 #else | |
618 *type = GL_UNSIGNED_SHORT_8_8_REV_APPLE; | |
619 #endif | |
620 } else if (renderdata->GL_MESA_ycbcr_texture_supported) { | |
621 *internalFormat = GL_YCBCR_MESA; | |
622 *format = GL_YCBCR_MESA; | |
623 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
624 *type = GL_UNSIGNED_SHORT_8_8_MESA; | |
625 #else | |
626 *type = GL_UNSIGNED_SHORT_8_8_REV_MESA; | |
627 #endif | |
628 } else if (renderdata->GL_ARB_fragment_program_supported) { | |
629 *internalFormat = GL_RGBA; | |
630 *format = GL_RGBA; | |
631 *type = GL_UNSIGNED_BYTE; | |
632 } else { | |
633 return SDL_FALSE; | |
634 } | |
635 break; | |
636 case SDL_PIXELFORMAT_YUY2: | |
637 if (renderdata->GL_APPLE_ycbcr_422_supported) { | |
638 *internalFormat = GL_RGB; | |
639 *format = GL_YCBCR_422_APPLE; | |
640 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
641 *type = GL_UNSIGNED_SHORT_8_8_REV_APPLE; | |
642 #else | |
643 *type = GL_UNSIGNED_SHORT_8_8_APPLE; | |
644 #endif | |
645 } else if (renderdata->GL_MESA_ycbcr_texture_supported) { | |
646 *internalFormat = GL_YCBCR_MESA; | |
647 *format = GL_YCBCR_MESA; | |
648 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
649 *type = GL_UNSIGNED_SHORT_8_8_REV_MESA; | |
650 #else | |
651 *type = GL_UNSIGNED_SHORT_8_8_MESA; | |
652 #endif | |
653 } else { | |
654 return SDL_FALSE; | |
655 } | |
656 break; | |
657 default: | |
658 return SDL_FALSE; | |
659 } | |
660 return SDL_TRUE; | |
661 } | |
662 | |
663 static int | |
664 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
665 { | |
666 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; | |
667 GL_TextureData *data; | |
668 GLint internalFormat; | |
669 GLenum format, type; | |
670 int texture_w, texture_h; | |
671 GLuint shader = 0; | |
672 GLenum result; | |
673 | |
674 GL_ActivateRenderer(renderer); | |
675 | |
676 if (!convert_format(renderdata, texture->format, &internalFormat, | |
677 &format, &type)) { | |
678 SDL_SetError("Texture format %s not supported by OpenGL", | |
679 SDL_GetPixelFormatName(texture->format)); | |
680 return -1; | |
681 } | |
682 if (texture->format == SDL_PIXELFORMAT_UYVY && | |
683 !renderdata->GL_APPLE_ycbcr_422_supported && | |
684 !renderdata->GL_MESA_ycbcr_texture_supported && | |
685 renderdata->GL_ARB_fragment_program_supported) { | |
686 if (renderdata->fragment_program_UYVY == 0) { | |
687 renderdata->fragment_program_UYVY = | |
688 compile_shader(renderdata, GL_FRAGMENT_PROGRAM_ARB, | |
689 fragment_program_UYVY_source_code); | |
690 if (renderdata->fragment_program_UYVY == 0) { | |
691 set_shader_error(renderdata, "UYVY"); | |
692 return -1; | |
693 } | |
694 } | |
695 shader = renderdata->fragment_program_UYVY; | |
696 } | |
697 | |
698 data = (GL_TextureData *) SDL_calloc(1, sizeof(*data)); | |
699 if (!data) { | |
700 SDL_OutOfMemory(); | |
701 return -1; | |
702 } | |
703 | |
704 data->shader = shader; | |
705 | |
706 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { | |
707 data->pitch = texture->w * bytes_per_pixel(texture->format); | |
708 data->pixels = SDL_malloc(texture->h * data->pitch); | |
709 if (!data->pixels) { | |
710 SDL_OutOfMemory(); | |
711 SDL_free(data); | |
712 return -1; | |
713 } | |
714 } | |
715 | |
716 texture->driverdata = data; | |
717 | |
718 renderdata->glGetError(); | |
719 renderdata->glGenTextures(1, &data->texture); | |
720 if (renderdata->GL_ARB_texture_rectangle_supported) { | |
721 data->type = GL_TEXTURE_RECTANGLE_ARB; | |
722 texture_w = texture->w; | |
723 texture_h = texture->h; | |
724 data->texw = (GLfloat) texture_w; | |
725 data->texh = (GLfloat) texture_h; | |
726 } else { | |
727 data->type = GL_TEXTURE_2D; | |
728 texture_w = power_of_2(texture->w); | |
729 texture_h = power_of_2(texture->h); | |
730 data->texw = (GLfloat) (texture->w) / texture_w; | |
731 data->texh = (GLfloat) texture->h / texture_h; | |
732 } | |
733 | |
734 /* YUV formats use RGBA but are really two bytes per pixel */ | |
735 if (internalFormat == GL_RGBA && bytes_per_pixel(texture->format) < 4) { | |
736 texture_w /= 2; | |
737 if (data->type == GL_TEXTURE_2D) { | |
738 data->texw *= 2.0f; | |
739 } | |
740 data->HACK_RYAN_FIXME = 2; | |
741 } else { | |
742 data->HACK_RYAN_FIXME = 1; | |
743 } | |
744 | |
745 data->format = format; | |
746 data->formattype = type; | |
747 renderdata->glEnable(data->type); | |
748 renderdata->glBindTexture(data->type, data->texture); | |
749 renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, | |
750 GL_LINEAR); | |
751 renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, | |
752 GL_LINEAR); | |
753 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, | |
754 GL_CLAMP_TO_EDGE); | |
755 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, | |
756 GL_CLAMP_TO_EDGE); | |
757 #ifdef __MACOSX__ | |
758 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE | |
759 #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC | |
760 #endif | |
761 #ifndef STORAGE_CACHED_APPLE | |
762 #define STORAGE_CACHED_APPLE 0x85BE | |
763 #endif | |
764 #ifndef STORAGE_SHARED_APPLE | |
765 #define STORAGE_SHARED_APPLE 0x85BF | |
766 #endif | |
767 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { | |
768 renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE, | |
769 GL_STORAGE_SHARED_APPLE); | |
770 } else { | |
771 renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE, | |
772 GL_STORAGE_CACHED_APPLE); | |
773 } | |
774 /* This causes a crash in testoverlay for some reason. Apple bug? */ | |
775 #if 0 | |
776 if (texture->access == SDL_TEXTUREACCESS_STREAMING | |
777 && texture->format == SDL_PIXELFORMAT_ARGB8888) { | |
778 /* | |
779 if (renderdata->glTextureRangeAPPLE) { | |
780 renderdata->glTextureRangeAPPLE(data->type, | |
781 texture->h * data->pitch, | |
782 data->pixels); | |
783 } | |
784 */ | |
785 renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); | |
786 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, | |
787 texture_h, 0, format, type, data->pixels); | |
788 } else | |
789 #endif | |
790 #endif | |
791 { | |
792 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, | |
793 texture_h, 0, format, type, NULL); | |
794 } | |
795 renderdata->glDisable(data->type); | |
796 result = renderdata->glGetError(); | |
797 if (result != GL_NO_ERROR) { | |
798 GL_SetError("glTexImage2D()", result); | |
799 return -1; | |
800 } | |
801 return 0; | |
802 } | |
803 | |
804 static int | |
805 GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, | |
806 void **pixels, int *pitch) | |
807 { | |
808 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
809 | |
810 *pixels = data->pixels; | |
811 *pitch = data->pitch; | |
812 return 0; | |
813 } | |
814 | |
815 static void | |
816 SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture, | |
817 int pitch) | |
818 { | |
819 renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
820 renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, | |
821 (pitch / bytes_per_pixel(texture->format)) / | |
822 ((GL_TextureData *) texture->driverdata)-> | |
823 HACK_RYAN_FIXME); | |
824 } | |
825 | |
826 static int | |
827 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
828 const SDL_Rect * rect, const void *pixels, int pitch) | |
829 { | |
830 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; | |
831 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
832 GLenum result; | |
833 | |
834 GL_ActivateRenderer(renderer); | |
835 | |
836 renderdata->glGetError(); | |
837 SetupTextureUpdate(renderdata, texture, pitch); | |
838 renderdata->glEnable(data->type); | |
839 renderdata->glBindTexture(data->type, data->texture); | |
840 renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, | |
841 rect->h, data->format, data->formattype, | |
842 pixels); | |
843 renderdata->glDisable(data->type); | |
844 result = renderdata->glGetError(); | |
845 if (result != GL_NO_ERROR) { | |
846 GL_SetError("glTexSubImage2D()", result); | |
847 return -1; | |
848 } | |
849 return 0; | |
850 } | |
851 | |
852 static int | |
853 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
854 const SDL_Rect * rect, int markDirty, void **pixels, | |
855 int *pitch) | |
856 { | |
857 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
858 | |
859 if (markDirty) { | |
860 SDL_AddDirtyRect(&data->dirty, rect); | |
861 } | |
862 | |
863 *pixels = | |
864 (void *) ((Uint8 *) data->pixels + rect->y * data->pitch + | |
865 rect->x * bytes_per_pixel(texture->format)); | |
866 *pitch = data->pitch; | |
867 return 0; | |
868 } | |
869 | |
870 static void | |
871 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
872 { | |
873 } | |
874 | |
875 static void | |
876 GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects, | |
877 const SDL_Rect * rects) | |
878 { | |
879 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
880 int i; | |
881 | |
882 for (i = 0; i < numrects; ++i) { | |
883 SDL_AddDirtyRect(&data->dirty, &rects[i]); | |
884 } | |
885 } | |
886 | |
887 static void | |
888 GL_SetBlendMode(GL_RenderData * data, int blendMode) | |
889 { | |
890 if (blendMode != data->blendMode) { | |
891 switch (blendMode) { | |
892 case SDL_BLENDMODE_NONE: | |
893 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
894 data->glDisable(GL_BLEND); | |
895 break; | |
896 case SDL_BLENDMODE_BLEND: | |
897 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | |
898 data->glEnable(GL_BLEND); | |
899 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
900 break; | |
901 case SDL_BLENDMODE_ADD: | |
902 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | |
903 data->glEnable(GL_BLEND); | |
904 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE); | |
905 break; | |
906 } | |
907 data->blendMode = blendMode; | |
908 } | |
909 } | |
910 | |
911 static int | |
912 GL_RenderClear(SDL_Renderer * renderer) | |
913 { | |
914 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
915 | |
916 GL_ActivateRenderer(renderer); | |
917 | |
918 data->glClearColor((GLfloat) renderer->r * inv255f, | |
919 (GLfloat) renderer->g * inv255f, | |
920 (GLfloat) renderer->b * inv255f, | |
921 (GLfloat) renderer->a * inv255f); | |
922 | |
923 data->glClear(GL_COLOR_BUFFER_BIT); | |
924 | |
925 return 0; | |
926 } | |
927 | |
928 static int | |
929 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, | |
930 int count) | |
931 { | |
932 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
933 int i; | |
934 | |
935 GL_ActivateRenderer(renderer); | |
936 | |
937 GL_SetBlendMode(data, renderer->blendMode); | |
938 | |
939 data->glColor4f((GLfloat) renderer->r * inv255f, | |
940 (GLfloat) renderer->g * inv255f, | |
941 (GLfloat) renderer->b * inv255f, | |
942 (GLfloat) renderer->a * inv255f); | |
943 | |
944 data->glBegin(GL_POINTS); | |
945 for (i = 0; i < count; ++i) { | |
946 data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); | |
947 } | |
948 data->glEnd(); | |
949 | |
950 return 0; | |
951 } | |
952 | |
953 static int | |
954 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, | |
955 int count) | |
956 { | |
957 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
958 int i; | |
959 | |
960 GL_ActivateRenderer(renderer); | |
961 | |
962 GL_SetBlendMode(data, renderer->blendMode); | |
963 | |
964 data->glColor4f((GLfloat) renderer->r * inv255f, | |
965 (GLfloat) renderer->g * inv255f, | |
966 (GLfloat) renderer->b * inv255f, | |
967 (GLfloat) renderer->a * inv255f); | |
968 | |
969 if (count > 2 && | |
970 points[0].x == points[count-1].x && points[0].y == points[count-1].y) { | |
971 data->glBegin(GL_LINE_LOOP); | |
972 /* GL_LINE_LOOP takes care of the final segment */ | |
973 --count; | |
974 for (i = 0; i < count; ++i) { | |
975 data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); | |
976 } | |
977 data->glEnd(); | |
978 } else { | |
979 #if defined(__APPLE__) || defined(__WIN32__) | |
980 #else | |
981 int x1, y1, x2, y2; | |
982 #endif | |
983 | |
984 data->glBegin(GL_LINE_STRIP); | |
985 for (i = 0; i < count; ++i) { | |
986 data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y); | |
987 } | |
988 data->glEnd(); | |
989 | |
990 /* The line is half open, so we need one more point to complete it. | |
991 * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html | |
992 * If we have to, we can use vertical line and horizontal line textures | |
993 * for vertical and horizontal lines, and then create custom textures | |
994 * for diagonal lines and software render those. It's terrible, but at | |
995 * least it would be pixel perfect. | |
996 */ | |
997 data->glBegin(GL_POINTS); | |
998 #if defined(__APPLE__) || defined(__WIN32__) | |
999 /* Mac OS X and Windows seem to always leave the second point open */ | |
1000 data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y); | |
1001 #else | |
1002 /* Linux seems to leave the right-most or bottom-most point open */ | |
1003 x1 = points[0].x; | |
1004 y1 = points[0].y; | |
1005 x2 = points[count-1].x; | |
1006 y2 = points[count-1].y; | |
1007 | |
1008 if (x1 > x2) { | |
1009 data->glVertex2f(0.5f + x1, 0.5f + y1); | |
1010 } else if (x2 > x1) { | |
1011 data->glVertex2f(0.5f + x2, 0.5f + y2); | |
1012 } else if (y1 > y2) { | |
1013 data->glVertex2f(0.5f + x1, 0.5f + y1); | |
1014 } else if (y2 > y1) { | |
1015 data->glVertex2f(0.5f + x2, 0.5f + y2); | |
1016 } | |
1017 #endif | |
1018 data->glEnd(); | |
1019 } | |
1020 | |
1021 return 0; | |
1022 } | |
1023 | |
1024 static int | |
1025 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count) | |
1026 { | |
1027 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
1028 int i; | |
1029 | |
1030 GL_ActivateRenderer(renderer); | |
1031 | |
1032 GL_SetBlendMode(data, renderer->blendMode); | |
1033 | |
1034 data->glColor4f((GLfloat) renderer->r * inv255f, | |
1035 (GLfloat) renderer->g * inv255f, | |
1036 (GLfloat) renderer->b * inv255f, | |
1037 (GLfloat) renderer->a * inv255f); | |
1038 | |
1039 for (i = 0; i < count; ++i) { | |
1040 const SDL_Rect *rect = rects[i]; | |
1041 | |
1042 data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h); | |
1043 } | |
1044 | |
1045 return 0; | |
1046 } | |
1047 | |
1048 static int | |
1049 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, | |
1050 const SDL_Rect * srcrect, const SDL_Rect * dstrect) | |
1051 { | |
1052 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
1053 GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata; | |
1054 int minx, miny, maxx, maxy; | |
1055 GLfloat minu, maxu, minv, maxv; | |
1056 | |
1057 GL_ActivateRenderer(renderer); | |
1058 | |
1059 if (texturedata->dirty.list) { | |
1060 SDL_DirtyRect *dirty; | |
1061 void *pixels; | |
1062 int bpp = bytes_per_pixel(texture->format); | |
1063 int pitch = texturedata->pitch; | |
1064 | |
1065 SetupTextureUpdate(data, texture, pitch); | |
1066 data->glEnable(texturedata->type); | |
1067 data->glBindTexture(texturedata->type, texturedata->texture); | |
1068 for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) { | |
1069 SDL_Rect *rect = &dirty->rect; | |
1070 pixels = | |
1071 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch + | |
1072 rect->x * bpp); | |
1073 data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y, | |
1074 rect->w / texturedata->HACK_RYAN_FIXME, | |
1075 rect->h, texturedata->format, | |
1076 texturedata->formattype, pixels); | |
1077 } | |
1078 SDL_ClearDirtyRects(&texturedata->dirty); | |
1079 } | |
1080 | |
1081 minx = dstrect->x; | |
1082 miny = dstrect->y; | |
1083 maxx = dstrect->x + dstrect->w; | |
1084 maxy = dstrect->y + dstrect->h; | |
1085 | |
1086 minu = (GLfloat) srcrect->x / texture->w; | |
1087 minu *= texturedata->texw; | |
1088 maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; | |
1089 maxu *= texturedata->texw; | |
1090 minv = (GLfloat) srcrect->y / texture->h; | |
1091 minv *= texturedata->texh; | |
1092 maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; | |
1093 maxv *= texturedata->texh; | |
1094 | |
1095 data->glEnable(texturedata->type); | |
1096 data->glBindTexture(texturedata->type, texturedata->texture); | |
1097 | |
1098 if (texture->modMode) { | |
1099 data->glColor4f((GLfloat) texture->r * inv255f, | |
1100 (GLfloat) texture->g * inv255f, | |
1101 (GLfloat) texture->b * inv255f, | |
1102 (GLfloat) texture->a * inv255f); | |
1103 } else { | |
1104 data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
1105 } | |
1106 | |
1107 GL_SetBlendMode(data, texture->blendMode); | |
1108 | |
1109 /* Set up the shader for the copy, if any */ | |
1110 if (texturedata->shader) { | |
1111 data->glEnable(GL_FRAGMENT_PROGRAM_ARB); | |
1112 data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, texturedata->shader); | |
1113 } | |
1114 | |
1115 data->glBegin(GL_TRIANGLE_STRIP); | |
1116 data->glTexCoord2f(minu, minv); | |
1117 data->glVertex2f((GLfloat) minx, (GLfloat) miny); | |
1118 data->glTexCoord2f(maxu, minv); | |
1119 data->glVertex2f((GLfloat) maxx, (GLfloat) miny); | |
1120 data->glTexCoord2f(minu, maxv); | |
1121 data->glVertex2f((GLfloat) minx, (GLfloat) maxy); | |
1122 data->glTexCoord2f(maxu, maxv); | |
1123 data->glVertex2f((GLfloat) maxx, (GLfloat) maxy); | |
1124 data->glEnd(); | |
1125 | |
1126 if (texturedata->shader) { | |
1127 data->glDisable(GL_FRAGMENT_PROGRAM_ARB); | |
1128 } | |
1129 | |
1130 data->glDisable(texturedata->type); | |
1131 | |
1132 return 0; | |
1133 } | |
1134 | |
1135 static int | |
1136 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, | |
1137 Uint32 pixel_format, void * pixels, int pitch) | |
1138 { | |
1139 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
1140 SDL_Window *window = renderer->window; | |
1141 GLint internalFormat; | |
1142 GLenum format, type; | |
1143 Uint8 *src, *dst, *tmp; | |
1144 int w, h, length, rows; | |
1145 | |
1146 GL_ActivateRenderer(renderer); | |
1147 | |
1148 if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) { | |
1149 /* FIXME: Do a temp copy to a format that is supported */ | |
1150 SDL_SetError("Unsupported pixel format"); | |
1151 return -1; | |
1152 } | |
1153 | |
1154 SDL_GetWindowSize(window, &w, &h); | |
1155 | |
1156 data->glPixelStorei(GL_PACK_ALIGNMENT, 1); | |
1157 data->glPixelStorei(GL_PACK_ROW_LENGTH, | |
1158 (pitch / bytes_per_pixel(pixel_format))); | |
1159 | |
1160 data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h, | |
1161 format, type, pixels); | |
1162 | |
1163 /* Flip the rows to be top-down */ | |
1164 length = rect->w * bytes_per_pixel(pixel_format); | |
1165 src = (Uint8*)pixels + (rect->h-1)*pitch; | |
1166 dst = (Uint8*)pixels; | |
1167 tmp = SDL_stack_alloc(Uint8, length); | |
1168 rows = rect->h / 2; | |
1169 while (rows--) { | |
1170 SDL_memcpy(tmp, dst, length); | |
1171 SDL_memcpy(dst, src, length); | |
1172 SDL_memcpy(src, tmp, length); | |
1173 dst += pitch; | |
1174 src -= pitch; | |
1175 } | |
1176 SDL_stack_free(tmp); | |
1177 | |
1178 return 0; | |
1179 } | |
1180 | |
1181 static int | |
1182 GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, | |
1183 Uint32 pixel_format, const void * pixels, int pitch) | |
1184 { | |
1185 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
1186 SDL_Window *window = renderer->window; | |
1187 GLint internalFormat; | |
1188 GLenum format, type; | |
1189 Uint8 *src, *dst, *tmp; | |
1190 int w, h, length, rows; | |
1191 | |
1192 GL_ActivateRenderer(renderer); | |
1193 | |
1194 if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) { | |
1195 /* FIXME: Do a temp copy to a format that is supported */ | |
1196 SDL_SetError("Unsupported pixel format"); | |
1197 return -1; | |
1198 } | |
1199 | |
1200 SDL_GetWindowSize(window, &w, &h); | |
1201 | |
1202 data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
1203 data->glPixelStorei(GL_UNPACK_ROW_LENGTH, | |
1204 (pitch / bytes_per_pixel(pixel_format))); | |
1205 | |
1206 /* Flip the rows to be bottom-up */ | |
1207 length = rect->h * rect->w * pitch; | |
1208 tmp = SDL_stack_alloc(Uint8, length); | |
1209 src = (Uint8*)pixels + (rect->h-1)*pitch; | |
1210 dst = (Uint8*)tmp; | |
1211 rows = rect->h; | |
1212 while (rows--) { | |
1213 SDL_memcpy(dst, src, pitch); | |
1214 dst += pitch; | |
1215 src -= pitch; | |
1216 } | |
1217 | |
1218 data->glRasterPos2i(rect->x, (h-rect->y)); | |
1219 data->glDrawPixels(rect->w, rect->h, format, type, tmp); | |
1220 SDL_stack_free(tmp); | |
1221 | |
1222 return 0; | |
1223 } | |
1224 | |
1225 static void | |
1226 GL_RenderPresent(SDL_Renderer * renderer) | |
1227 { | |
1228 GL_ActivateRenderer(renderer); | |
1229 | |
1230 SDL_GL_SwapWindow(renderer->window); | |
1231 } | |
1232 | |
1233 static void | |
1234 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
1235 { | |
1236 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; | |
1237 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
1238 | |
1239 GL_ActivateRenderer(renderer); | |
1240 | |
1241 if (!data) { | |
1242 return; | |
1243 } | |
1244 if (data->texture) { | |
1245 renderdata->glDeleteTextures(1, &data->texture); | |
1246 } | |
1247 if (data->palette) { | |
1248 SDL_free(data->palette); | |
1249 } | |
1250 if (data->pixels) { | |
1251 SDL_free(data->pixels); | |
1252 } | |
1253 SDL_FreeDirtyRects(&data->dirty); | |
1254 SDL_free(data); | |
1255 texture->driverdata = NULL; | |
1256 } | |
1257 | |
1258 static void | |
1259 GL_DestroyRenderer(SDL_Renderer * renderer) | |
1260 { | |
1261 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
1262 | |
1263 if (data) { | |
1264 if (data->context) { | |
1265 if (data->GL_ARB_fragment_program_supported) { | |
1266 data->glDisable(GL_FRAGMENT_PROGRAM_ARB); | |
1267 data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); | |
1268 if (data->fragment_program_UYVY && | |
1269 data->fragment_program_UYVY != ~0) { | |
1270 data->glDeleteProgramsARB(1, | |
1271 &data->fragment_program_UYVY); | |
1272 } | |
1273 } | |
1274 | |
1275 /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */ | |
1276 SDL_GL_DeleteContext(data->context); | |
1277 } | |
1278 SDL_free(data); | |
1279 } | |
1280 SDL_free(renderer); | |
1281 } | |
1282 | |
1283 #endif /* SDL_VIDEO_RENDER_OGL */ | |
1284 | |
1285 /* vi: set ts=4 sw=4 expandtab: */ |