Mercurial > sdl-ios-xcode
comparison src/video/SDL_renderer_gles.c @ 2739:68862734a5fd
These files are similar in purpose and structure as SDL_renderer_gl.c and SDL_renderer_gl.h, except they use OpenGL ES 1.1 for rendering.
author | Holmes Futrell <hfutrell@umail.ucsb.edu> |
---|---|
date | Tue, 02 Sep 2008 00:37:04 +0000 |
parents | |
children | 0969758c8809 |
comparison
equal
deleted
inserted
replaced
2738:79c1bd651f04 | 2739:68862734a5fd |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997-2006 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_ES | |
25 | |
26 #include "SDL_video.h" | |
27 #include "SDL_opengles.h" | |
28 #include "SDL_sysvideo.h" | |
29 #include "SDL_pixels_c.h" | |
30 #include "SDL_rect_c.h" | |
31 #include "SDL_yuv_sw_c.h" | |
32 | |
33 /* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */ | |
34 | |
35 static const float inv255f = 1.0f / 255.0f; | |
36 | |
37 static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags); | |
38 static int GLES_ActivateRenderer(SDL_Renderer * renderer); | |
39 static int GLES_DisplayModeChanged(SDL_Renderer * renderer); | |
40 static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
41 static int GLES_QueryTexturePixels(SDL_Renderer * renderer, | |
42 SDL_Texture * texture, void **pixels, | |
43 int *pitch); | |
44 static int GLES_SetTexturePalette(SDL_Renderer * renderer, | |
45 SDL_Texture * texture, | |
46 const SDL_Color * colors, int firstcolor, | |
47 int ncolors); | |
48 static int GLES_GetTexturePalette(SDL_Renderer * renderer, | |
49 SDL_Texture * texture, SDL_Color * colors, | |
50 int firstcolor, int ncolors); | |
51 static int GLES_SetTextureColorMod(SDL_Renderer * renderer, | |
52 SDL_Texture * texture); | |
53 static int GLES_SetTextureAlphaMod(SDL_Renderer * renderer, | |
54 SDL_Texture * texture); | |
55 static int GLES_SetTextureBlendMode(SDL_Renderer * renderer, | |
56 SDL_Texture * texture); | |
57 static int GLES_SetTextureScaleMode(SDL_Renderer * renderer, | |
58 SDL_Texture * texture); | |
59 static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
60 const SDL_Rect * rect, const void *pixels, | |
61 int pitch); | |
62 static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
63 const SDL_Rect * rect, int markDirty, void **pixels, | |
64 int *pitch); | |
65 static void GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
66 static void GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
67 int numrects, const SDL_Rect * rects); | |
68 static int GLES_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, | |
69 Uint8 a, const SDL_Rect * rect); | |
70 static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, | |
71 const SDL_Rect * srcrect, const SDL_Rect * dstrect); | |
72 static void GLES_RenderPresent(SDL_Renderer * renderer); | |
73 static void GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
74 static void GLES_DestroyRenderer(SDL_Renderer * renderer); | |
75 | |
76 | |
77 SDL_RenderDriver GL_ES_RenderDriver = { | |
78 GLES_CreateRenderer, | |
79 { | |
80 "opengl_es", | |
81 (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD | | |
82 SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), | |
83 (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR | | |
84 SDL_TEXTUREMODULATE_ALPHA), | |
85 (SDL_TEXTUREBLENDMODE_NONE | SDL_TEXTUREBLENDMODE_MASK | | |
86 SDL_TEXTUREBLENDMODE_BLEND | SDL_TEXTUREBLENDMODE_ADD | | |
87 SDL_TEXTUREBLENDMODE_MOD), | |
88 (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST | | |
89 SDL_TEXTURESCALEMODE_SLOW), 2, | |
90 { | |
91 SDL_PIXELFORMAT_RGB24, | |
92 SDL_PIXELFORMAT_ABGR8888, | |
93 }, | |
94 0, | |
95 0} | |
96 }; | |
97 | |
98 typedef struct | |
99 { | |
100 SDL_GLContext context; | |
101 SDL_bool updateSize; | |
102 int blendMode; | |
103 | |
104 #ifndef APIENTRY | |
105 #define APIENTRY | |
106 #endif | |
107 | |
108 SDL_bool useDrawTexture; | |
109 SDL_bool GL_OES_draw_texture_supported; | |
110 | |
111 /* OpenGL ES functions */ | |
112 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; | |
113 #include "SDL_glesfuncs.h" | |
114 #undef SDL_PROC | |
115 | |
116 } GLES_RenderData; | |
117 | |
118 typedef struct | |
119 { | |
120 GLuint texture; | |
121 GLenum type; | |
122 GLfloat texw; | |
123 GLfloat texh; | |
124 GLenum format; | |
125 GLenum formattype; | |
126 void *pixels; | |
127 int pitch; | |
128 SDL_DirtyRectList dirty; | |
129 } GLES_TextureData; | |
130 | |
131 static void | |
132 GLES_SetError(const char *prefix, GLenum result) | |
133 { | |
134 const char *error; | |
135 | |
136 switch (result) { | |
137 case GL_NO_ERROR: | |
138 error = "GL_NO_ERROR"; | |
139 break; | |
140 case GL_INVALID_ENUM: | |
141 error = "GL_INVALID_ENUM"; | |
142 break; | |
143 case GL_INVALID_VALUE: | |
144 error = "GL_INVALID_VALUE"; | |
145 break; | |
146 case GL_INVALID_OPERATION: | |
147 error = "GL_INVALID_OPERATION"; | |
148 break; | |
149 case GL_STACK_OVERFLOW: | |
150 error = "GL_STACK_OVERFLOW"; | |
151 break; | |
152 case GL_STACK_UNDERFLOW: | |
153 error = "GL_STACK_UNDERFLOW"; | |
154 break; | |
155 case GL_OUT_OF_MEMORY: | |
156 error = "GL_OUT_OF_MEMORY"; | |
157 break; | |
158 default: | |
159 error = "UNKNOWN"; | |
160 break; | |
161 } | |
162 SDL_SetError("%s: %s", prefix, error); | |
163 } | |
164 | |
165 static int | |
166 GLES_LoadFunctions(GLES_RenderData * data) | |
167 { | |
168 | |
169 #define SDL_PROC(ret,func,params) \ | |
170 data->func = func; | |
171 #include "SDL_glesfuncs.h" | |
172 #undef SDL_PROC | |
173 | |
174 return 0; | |
175 } | |
176 | |
177 void | |
178 GLES_AddRenderDriver(_THIS) | |
179 { | |
180 if (_this->GL_CreateContext) { | |
181 SDL_AddRenderDriver(0, &GL_ES_RenderDriver); | |
182 } | |
183 } | |
184 | |
185 SDL_Renderer * | |
186 GLES_CreateRenderer(SDL_Window * window, Uint32 flags) | |
187 { | |
188 | |
189 SDL_Renderer *renderer; | |
190 GLES_RenderData *data; | |
191 GLint value; | |
192 int doublebuffer; | |
193 | |
194 if (!(window->flags & SDL_WINDOW_OPENGL)) { | |
195 if (SDL_RecreateWindow(window, window->flags | SDL_WINDOW_OPENGL) < 0) { | |
196 return NULL; | |
197 } | |
198 } | |
199 | |
200 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); | |
201 if (!renderer) { | |
202 SDL_OutOfMemory(); | |
203 return NULL; | |
204 } | |
205 | |
206 data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data)); | |
207 if (!data) { | |
208 GLES_DestroyRenderer(renderer); | |
209 SDL_OutOfMemory(); | |
210 return NULL; | |
211 } | |
212 | |
213 renderer->ActivateRenderer = GLES_ActivateRenderer; | |
214 renderer->DisplayModeChanged = GLES_DisplayModeChanged; | |
215 renderer->CreateTexture = GLES_CreateTexture; | |
216 renderer->QueryTexturePixels = GLES_QueryTexturePixels; | |
217 renderer->SetTexturePalette = GLES_SetTexturePalette; | |
218 renderer->GetTexturePalette = GLES_GetTexturePalette; | |
219 renderer->SetTextureColorMod = GLES_SetTextureColorMod; | |
220 renderer->SetTextureAlphaMod = GLES_SetTextureAlphaMod; | |
221 renderer->SetTextureBlendMode = GLES_SetTextureBlendMode; | |
222 renderer->SetTextureScaleMode = GLES_SetTextureScaleMode; | |
223 renderer->UpdateTexture = GLES_UpdateTexture; | |
224 renderer->LockTexture = GLES_LockTexture; | |
225 renderer->UnlockTexture = GLES_UnlockTexture; | |
226 renderer->DirtyTexture = GLES_DirtyTexture; | |
227 renderer->RenderFill = GLES_RenderFill; | |
228 renderer->RenderCopy = GLES_RenderCopy; | |
229 renderer->RenderPresent = GLES_RenderPresent; | |
230 renderer->DestroyTexture = GLES_DestroyTexture; | |
231 renderer->DestroyRenderer = GLES_DestroyRenderer; | |
232 renderer->info = GL_ES_RenderDriver.info; | |
233 renderer->window = window->id; | |
234 renderer->driverdata = data; | |
235 | |
236 | |
237 renderer->info.flags = (SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED); | |
238 | |
239 if (GLES_LoadFunctions(data) < 0) { | |
240 GLES_DestroyRenderer(renderer); | |
241 return NULL; | |
242 } | |
243 | |
244 data->context = SDL_GL_CreateContext(window->id); | |
245 if (!data->context) { | |
246 GLES_DestroyRenderer(renderer); | |
247 return NULL; | |
248 } | |
249 if (SDL_GL_MakeCurrent(window->id, data->context) < 0) { | |
250 GLES_DestroyRenderer(renderer); | |
251 return NULL; | |
252 } | |
253 | |
254 if (flags & SDL_RENDERER_PRESENTVSYNC) { | |
255 SDL_GL_SetSwapInterval(1); | |
256 } else { | |
257 SDL_GL_SetSwapInterval(0); | |
258 } | |
259 if (SDL_GL_GetSwapInterval() > 0) { | |
260 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; | |
261 } | |
262 | |
263 if (SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doublebuffer) == 0) { | |
264 if (!doublebuffer) { | |
265 renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER; | |
266 } | |
267 } | |
268 | |
269 if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) { | |
270 data->GL_OES_draw_texture_supported = SDL_TRUE; | |
271 data->useDrawTexture = SDL_TRUE; | |
272 } | |
273 else { | |
274 data->GL_OES_draw_texture_supported = SDL_FALSE; | |
275 data->useDrawTexture = SDL_FALSE; | |
276 } | |
277 | |
278 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); | |
279 renderer->info.max_texture_width = value; | |
280 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); | |
281 renderer->info.max_texture_height = value; | |
282 | |
283 /* Set up parameters for rendering */ | |
284 data->blendMode = -1; | |
285 data->glDisable(GL_DEPTH_TEST); | |
286 data->glDisable(GL_CULL_FACE); | |
287 data->glEnable(GL_TEXTURE_2D); | |
288 data->updateSize = SDL_TRUE; | |
289 | |
290 return renderer; | |
291 } | |
292 | |
293 static int GLES_ActivateRenderer(SDL_Renderer * renderer) | |
294 { | |
295 | |
296 GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; | |
297 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | |
298 | |
299 if (SDL_GL_MakeCurrent(window->id, data->context) < 0) { | |
300 return -1; | |
301 } | |
302 if (data->updateSize) { | |
303 data->glMatrixMode(GL_PROJECTION); | |
304 data->glLoadIdentity(); | |
305 data->glMatrixMode(GL_MODELVIEW); | |
306 data->glLoadIdentity(); | |
307 data->glViewport(0, 0, window->w, window->h); | |
308 data->glOrthof(0.0, (GLfloat)window->w, (GLfloat)window->h, 0.0, | |
309 0.0, 1.0); | |
310 data->updateSize = SDL_FALSE; | |
311 } | |
312 return 0; | |
313 } | |
314 | |
315 static int | |
316 GLES_DisplayModeChanged(SDL_Renderer * renderer) | |
317 { | |
318 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; | |
319 | |
320 data->updateSize = SDL_TRUE; | |
321 return 0; | |
322 } | |
323 | |
324 static __inline__ int | |
325 power_of_2(int input) | |
326 { | |
327 int value = 1; | |
328 | |
329 while (value < input) { | |
330 value <<= 1; | |
331 } | |
332 return value; | |
333 } | |
334 | |
335 static int | |
336 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
337 { | |
338 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; | |
339 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | |
340 GLES_TextureData *data; | |
341 GLint internalFormat; | |
342 GLenum format, type; | |
343 int texture_w, texture_h; | |
344 GLenum result; | |
345 switch (texture->format) { | |
346 case SDL_PIXELFORMAT_INDEX1LSB: | |
347 case SDL_PIXELFORMAT_INDEX1MSB: | |
348 case SDL_PIXELFORMAT_INDEX8: | |
349 case SDL_PIXELFORMAT_RGB332: | |
350 case SDL_PIXELFORMAT_RGB444: | |
351 case SDL_PIXELFORMAT_RGB555: | |
352 case SDL_PIXELFORMAT_ARGB4444: | |
353 case SDL_PIXELFORMAT_ARGB1555: | |
354 case SDL_PIXELFORMAT_BGR24: | |
355 case SDL_PIXELFORMAT_BGR888: | |
356 case SDL_PIXELFORMAT_RGB888: | |
357 case SDL_PIXELFORMAT_RGBA8888: | |
358 case SDL_PIXELFORMAT_ARGB2101010: | |
359 case SDL_PIXELFORMAT_ARGB8888: | |
360 case SDL_PIXELFORMAT_RGB24: | |
361 internalFormat = GL_RGB; | |
362 format = GL_RGB; | |
363 type = GL_UNSIGNED_BYTE; | |
364 break; | |
365 case SDL_PIXELFORMAT_ABGR8888: | |
366 internalFormat = GL_RGBA; | |
367 format = GL_RGBA; | |
368 type = GL_UNSIGNED_BYTE; | |
369 break; | |
370 /* | |
371 These formats would be supported if SDL had the necessary pixel formats | |
372 case SDL_PIXELFORMAT_BGR565: | |
373 internalFormat = GL_RGB; | |
374 format = GL_RGB; | |
375 type = GL_UNSIGNED_SHORT_5_6_5; | |
376 break; | |
377 case SDL_PIXELFORMAT_ABGR5551: | |
378 internalFormat = GL_RGBA; | |
379 format = GL_RGBA; | |
380 type = GL_UNSIGNED_SHORT_5_5_5_1; | |
381 break; | |
382 case SDL_PIXELFORMAT_ABGR4444: | |
383 internalFormat = GL_RGBA; | |
384 format = GL_RGBA; | |
385 type = GL_UNSIGNED_SHORT_4_4_4_4; | |
386 break; | |
387 */ | |
388 default: | |
389 SDL_SetError("Unsupported texture format"); | |
390 return -1; | |
391 } | |
392 | |
393 data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data)); | |
394 if (!data) { | |
395 SDL_OutOfMemory(); | |
396 return -1; | |
397 } | |
398 | |
399 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { | |
400 data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); | |
401 data->pixels = SDL_malloc(texture->h * data->pitch); | |
402 if (!data->pixels) { | |
403 SDL_OutOfMemory(); | |
404 SDL_free(data); | |
405 return -1; | |
406 } | |
407 } | |
408 | |
409 texture->driverdata = data; | |
410 | |
411 renderdata->glGetError(); | |
412 renderdata->glGenTextures(1, &data->texture); | |
413 | |
414 data->type = GL_TEXTURE_2D; | |
415 /* no NPOV textures allowed in OpenGL ES (yet) */ | |
416 texture_w = power_of_2(texture->w); | |
417 texture_h = power_of_2(texture->h); | |
418 data->texw = (GLfloat) texture->w / texture_w; | |
419 data->texh = (GLfloat) texture->h / texture_h; | |
420 | |
421 data->format = format; | |
422 data->formattype = type; | |
423 renderdata->glBindTexture(data->type, data->texture); | |
424 renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, | |
425 GL_NEAREST); | |
426 renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, | |
427 GL_NEAREST); | |
428 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, | |
429 GL_CLAMP_TO_EDGE); | |
430 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, | |
431 GL_CLAMP_TO_EDGE); | |
432 | |
433 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, | |
434 texture_h, 0, format, type, NULL); | |
435 | |
436 result = renderdata->glGetError(); | |
437 if (result != GL_NO_ERROR) { | |
438 GLES_SetError("glTexImage2D()", result); | |
439 return -1; | |
440 } | |
441 return 0; | |
442 } | |
443 | |
444 static int | |
445 GLES_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, | |
446 void **pixels, int *pitch) | |
447 { | |
448 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; | |
449 | |
450 *pixels = data->pixels; | |
451 *pitch = data->pitch; | |
452 return 0; | |
453 } | |
454 | |
455 static int | |
456 GLES_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, | |
457 const SDL_Color * colors, int firstcolor, int ncolors) | |
458 { | |
459 SDL_SetError("OpenGL ES does not support paletted textures"); | |
460 return -1; | |
461 } | |
462 | |
463 static int | |
464 GLES_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, | |
465 SDL_Color * colors, int firstcolor, int ncolors) | |
466 { | |
467 SDL_SetError("OpenGL ES does not support paletted textures"); | |
468 return -1; | |
469 } | |
470 | |
471 static void | |
472 SetupTextureUpdate(GLES_RenderData * renderdata, SDL_Texture * texture, | |
473 int pitch) | |
474 { | |
475 | |
476 | |
477 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; | |
478 renderdata->glBindTexture(data->type, data->texture); | |
479 renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
480 } | |
481 | |
482 static int | |
483 GLES_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) | |
484 { | |
485 return 0; | |
486 } | |
487 | |
488 static int | |
489 GLES_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) | |
490 { | |
491 return 0; | |
492 } | |
493 | |
494 static int | |
495 GLES_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) | |
496 { | |
497 switch (texture->blendMode) { | |
498 case SDL_TEXTUREBLENDMODE_NONE: | |
499 case SDL_TEXTUREBLENDMODE_MASK: | |
500 case SDL_TEXTUREBLENDMODE_BLEND: | |
501 case SDL_TEXTUREBLENDMODE_ADD: | |
502 case SDL_TEXTUREBLENDMODE_MOD: | |
503 return 0; | |
504 default: | |
505 SDL_Unsupported(); | |
506 texture->blendMode = SDL_TEXTUREBLENDMODE_NONE; | |
507 return -1; | |
508 } | |
509 } | |
510 | |
511 static int | |
512 GLES_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) | |
513 { | |
514 switch (texture->scaleMode) { | |
515 case SDL_TEXTURESCALEMODE_NONE: | |
516 case SDL_TEXTURESCALEMODE_FAST: | |
517 case SDL_TEXTURESCALEMODE_SLOW: | |
518 return 0; | |
519 case SDL_TEXTURESCALEMODE_BEST: | |
520 SDL_Unsupported(); | |
521 texture->scaleMode = SDL_TEXTURESCALEMODE_SLOW; | |
522 return -1; | |
523 default: | |
524 SDL_Unsupported(); | |
525 texture->scaleMode = SDL_TEXTURESCALEMODE_NONE; | |
526 return -1; | |
527 } | |
528 } | |
529 | |
530 static int | |
531 GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
532 const SDL_Rect * rect, const void *pixels, int pitch) | |
533 { | |
534 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; | |
535 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; | |
536 GLenum result; | |
537 | |
538 SetupTextureUpdate(renderdata, texture, pitch); | |
539 renderdata->glGetError(); | |
540 renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, | |
541 rect->h, data->format, data->formattype, | |
542 pixels); | |
543 result = renderdata->glGetError(); | |
544 if (result != GL_NO_ERROR) { | |
545 GLES_SetError("glTexSubImage2D()", result); | |
546 return -1; | |
547 } | |
548 return 0; | |
549 } | |
550 | |
551 static int | |
552 GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
553 const SDL_Rect * rect, int markDirty, void **pixels, | |
554 int *pitch) | |
555 { | |
556 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; | |
557 | |
558 if (markDirty) { | |
559 SDL_AddDirtyRect(&data->dirty, rect); | |
560 } | |
561 | |
562 *pixels = | |
563 (void *) ((Uint8 *) data->pixels + rect->y * data->pitch + | |
564 rect->x * SDL_BYTESPERPIXEL(texture->format)); | |
565 *pitch = data->pitch; | |
566 return 0; | |
567 } | |
568 | |
569 static void | |
570 GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
571 { | |
572 } | |
573 | |
574 static void | |
575 GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects, | |
576 const SDL_Rect * rects) | |
577 { | |
578 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; | |
579 int i; | |
580 | |
581 for (i = 0; i < numrects; ++i) { | |
582 SDL_AddDirtyRect(&data->dirty, &rects[i]); | |
583 } | |
584 } | |
585 | |
586 static int | |
587 GLES_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a, | |
588 const SDL_Rect * rect) | |
589 { | |
590 | |
591 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; | |
592 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | |
593 | |
594 /* set proper drawing color */ | |
595 GLfloat oldClearColor[4]; | |
596 | |
597 data->glGetFloatv(GL_COLOR_CLEAR_VALUE, oldClearColor); | |
598 | |
599 data->glClearColor((GLclampf) r * inv255f, (GLclampf) g * inv255f, | |
600 (GLclampf) b * inv255f, (GLclampf) a * inv255f); | |
601 | |
602 data->glScissor(rect->x, window->h - rect->y - rect->h, rect->w, rect->h); | |
603 data->glEnable(GL_SCISSOR_TEST); | |
604 data->glClear(GL_COLOR_BUFFER_BIT); | |
605 data->glDisable(GL_SCISSOR_TEST); | |
606 | |
607 /* reset clear color */ | |
608 data->glClearColor(oldClearColor[0], oldClearColor[1], oldClearColor[2], oldClearColor[2]); | |
609 | |
610 return 0; | |
611 } | |
612 | |
613 static int | |
614 GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, | |
615 const SDL_Rect * srcrect, const SDL_Rect * dstrect) | |
616 { | |
617 | |
618 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; | |
619 GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata; | |
620 int minx, miny, maxx, maxy; | |
621 GLfloat minu, maxu, minv, maxv; | |
622 int i; | |
623 void *temp_buffer; /* used for reformatting dirty rect pixels */ | |
624 void *temp_ptr; | |
625 | |
626 if (texturedata->dirty.list) { | |
627 SDL_DirtyRect *dirty; | |
628 void *pixels; | |
629 int bpp = SDL_BYTESPERPIXEL(texture->format); | |
630 int pitch = texturedata->pitch; | |
631 | |
632 SetupTextureUpdate(data, texture, pitch); | |
633 | |
634 data->glBindTexture(texturedata->type, texturedata->texture); | |
635 for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) { | |
636 SDL_Rect *rect = &dirty->rect; | |
637 pixels = (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch + rect->x * bpp); | |
638 /* There is no GL_UNPACK_ROW_LENGTH in OpenGLES | |
639 we must do this reformatting ourselves(!) | |
640 | |
641 maybe it'd be a good idea to keep a temp buffer around | |
642 for this purpose rather than allocating it each time | |
643 */ | |
644 temp_buffer = SDL_malloc(rect->w * rect->h * bpp); | |
645 temp_ptr = temp_buffer; | |
646 for (i=0; i<rect->h; i++) { | |
647 SDL_memcpy(temp_ptr, pixels, rect->w * bpp); | |
648 temp_ptr += rect->w * bpp; | |
649 pixels += pitch; | |
650 } | |
651 | |
652 data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y, | |
653 rect->w, rect->h, texturedata->format, | |
654 texturedata->formattype, temp_buffer); | |
655 | |
656 SDL_free(temp_buffer); | |
657 | |
658 } | |
659 SDL_ClearDirtyRects(&texturedata->dirty); | |
660 } | |
661 | |
662 data->glBindTexture(texturedata->type, texturedata->texture); | |
663 data->glEnable(GL_TEXTURE_2D); | |
664 | |
665 if (texture->modMode) { | |
666 data->glColor4f((GLfloat) texture->r * inv255f, | |
667 (GLfloat) texture->g * inv255f, | |
668 (GLfloat) texture->b * inv255f, | |
669 (GLfloat) texture->a * inv255f); | |
670 } else { | |
671 data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
672 } | |
673 | |
674 if (texture->blendMode != data->blendMode) { | |
675 switch (texture->blendMode) { | |
676 case SDL_TEXTUREBLENDMODE_NONE: | |
677 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); | |
678 data->glDisable(GL_BLEND); | |
679 break; | |
680 case SDL_TEXTUREBLENDMODE_MASK: | |
681 case SDL_TEXTUREBLENDMODE_BLEND: | |
682 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | |
683 data->glEnable(GL_BLEND); | |
684 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
685 break; | |
686 case SDL_TEXTUREBLENDMODE_ADD: | |
687 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | |
688 data->glEnable(GL_BLEND); | |
689 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE); | |
690 break; | |
691 case SDL_TEXTUREBLENDMODE_MOD: | |
692 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | |
693 data->glEnable(GL_BLEND); | |
694 data->glBlendFunc(GL_ZERO, GL_SRC_COLOR); | |
695 break; | |
696 } | |
697 data->blendMode = texture->blendMode; | |
698 } | |
699 | |
700 switch (texture->scaleMode) { | |
701 case SDL_TEXTURESCALEMODE_NONE: | |
702 case SDL_TEXTURESCALEMODE_FAST: | |
703 data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER, | |
704 GL_NEAREST); | |
705 data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER, | |
706 GL_NEAREST); | |
707 break; | |
708 case SDL_TEXTURESCALEMODE_SLOW: | |
709 case SDL_TEXTURESCALEMODE_BEST: | |
710 data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER, | |
711 GL_LINEAR); | |
712 data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER, | |
713 GL_LINEAR); | |
714 break; | |
715 } | |
716 | |
717 if (data->GL_OES_draw_texture_supported && data->useDrawTexture) { | |
718 /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */ | |
719 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | |
720 GLint cropRect[4]; | |
721 cropRect[0] = srcrect->x; | |
722 cropRect[1] = srcrect->y + srcrect->h; | |
723 cropRect[2] = srcrect->w; | |
724 cropRect[3] = -srcrect->h; | |
725 data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect); | |
726 data->glDrawTexiOES(dstrect->x, window->h - dstrect->y - dstrect->h, 0, dstrect->w, dstrect->h); | |
727 } | |
728 else { | |
729 | |
730 minx = dstrect->x; | |
731 miny = dstrect->y; | |
732 maxx = dstrect->x + dstrect->w; | |
733 maxy = dstrect->y + dstrect->h; | |
734 | |
735 minu = (GLfloat) srcrect->x / texture->w; | |
736 minu *= texturedata->texw; | |
737 maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; | |
738 maxu *= texturedata->texw; | |
739 minv = (GLfloat) srcrect->y / texture->h; | |
740 minv *= texturedata->texh; | |
741 maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; | |
742 maxv *= texturedata->texh; | |
743 | |
744 GLshort vertices[8]; | |
745 GLfloat texCoords[8]; | |
746 | |
747 vertices[0] = minx; vertices[1] = miny; | |
748 vertices[2] = maxx; vertices[3] = miny; | |
749 vertices[4] = minx; vertices[5] = maxy; | |
750 vertices[6] = maxx; vertices[7] = maxy; | |
751 | |
752 texCoords[0] = minu; texCoords[1] = minv; | |
753 texCoords[2] = maxu; texCoords[3] = minv; | |
754 texCoords[4] = minu; texCoords[5] = maxv; | |
755 texCoords[6] = maxu; texCoords[7] = maxv; | |
756 | |
757 data->glVertexPointer(2, GL_SHORT, 0, vertices); | |
758 data->glEnableClientState(GL_VERTEX_ARRAY); | |
759 data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords); | |
760 data->glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
761 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
762 | |
763 } | |
764 | |
765 return 0; | |
766 } | |
767 | |
768 static void | |
769 GLES_RenderPresent(SDL_Renderer * renderer) | |
770 { | |
771 SDL_GL_SwapWindow(renderer->window); | |
772 } | |
773 | |
774 static void | |
775 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
776 { | |
777 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; | |
778 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; | |
779 | |
780 if (!data) { | |
781 return; | |
782 } | |
783 if (data->texture) { | |
784 glDeleteTextures(1, &data->texture); | |
785 } | |
786 if (data->pixels) { | |
787 SDL_free(data->pixels); | |
788 } | |
789 SDL_FreeDirtyRects(&data->dirty); | |
790 SDL_free(data); | |
791 texture->driverdata = NULL; | |
792 } | |
793 | |
794 static void | |
795 GLES_DestroyRenderer(SDL_Renderer * renderer) | |
796 { | |
797 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; | |
798 | |
799 if (data) { | |
800 if (data->context) { | |
801 /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */ | |
802 SDL_GL_DeleteContext(data->context); | |
803 } | |
804 SDL_free(data); | |
805 } | |
806 SDL_free(renderer); | |
807 } | |
808 | |
809 #endif /* SDL_VIDEO_RENDER_OGL */ | |
810 | |
811 /* vi: set ts=4 sw=4 expandtab: */ |