comparison src/render/opengles/SDL_renderer_gles.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_gles.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_ES
25
26 #include "SDL_opengles.h"
27 #include "../SDL_sysrender.h"
28
29 #if defined(SDL_VIDEO_DRIVER_PANDORA)
30
31 /* Empty function stub to get OpenGL ES 1.x support without */
32 /* OpenGL ES extension GL_OES_draw_texture supported */
33 GL_API void GL_APIENTRY
34 glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height)
35 {
36 return;
37 }
38
39 #endif /* PANDORA */
40
41 /* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */
42
43 /* Used to re-create the window with OpenGL capability */
44 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
45
46 static const float inv255f = 1.0f / 255.0f;
47
48 static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
49 static void GLES_WindowEvent(SDL_Renderer * renderer,
50 const SDL_WindowEvent *event);
51 static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
52 static int GLES_QueryTexturePixels(SDL_Renderer * renderer,
53 SDL_Texture * texture, void **pixels,
54 int *pitch);
55 static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
56 const SDL_Rect * rect, const void *pixels,
57 int pitch);
58 static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
59 const SDL_Rect * rect, int markDirty,
60 void **pixels, int *pitch);
61 static void GLES_UnlockTexture(SDL_Renderer * renderer,
62 SDL_Texture * texture);
63 static void GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
64 int numrects, const SDL_Rect * rects);
65 static int GLES_RenderDrawPoints(SDL_Renderer * renderer,
66 const SDL_Point * points, int count);
67 static int GLES_RenderDrawLines(SDL_Renderer * renderer,
68 const SDL_Point * points, int count);
69 static int GLES_RenderFillRects(SDL_Renderer * renderer,
70 const SDL_Rect ** rects, int count);
71 static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
72 const SDL_Rect * srcrect,
73 const SDL_Rect * dstrect);
74 static void GLES_RenderPresent(SDL_Renderer * renderer);
75 static void GLES_DestroyTexture(SDL_Renderer * renderer,
76 SDL_Texture * texture);
77 static void GLES_DestroyRenderer(SDL_Renderer * renderer);
78
79
80 SDL_RenderDriver GL_ES_RenderDriver = {
81 GLES_CreateRenderer,
82 {
83 "opengl_es",
84 (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
85 6,
86 {
87 /* OpenGL ES 1.x supported formats list */
88 SDL_PIXELFORMAT_RGBA4444,
89 SDL_PIXELFORMAT_RGBA5551,
90 SDL_PIXELFORMAT_RGB565,
91 SDL_PIXELFORMAT_RGB24,
92 SDL_PIXELFORMAT_BGR888,
93 SDL_PIXELFORMAT_ABGR8888},
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 SDL_Renderer *
178 GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
179 {
180
181 SDL_Renderer *renderer;
182 GLES_RenderData *data;
183 GLint value;
184 Uint32 window_flags;
185
186 window_flags = SDL_GetWindowFlags(window);
187 if (!(window_flags & SDL_WINDOW_OPENGL)) {
188 if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
189 return NULL;
190 }
191 }
192
193 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
194 if (!renderer) {
195 SDL_OutOfMemory();
196 return NULL;
197 }
198
199 data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
200 if (!data) {
201 GLES_DestroyRenderer(renderer);
202 SDL_OutOfMemory();
203 return NULL;
204 }
205
206 renderer->WindowEvent = GLES_WindowEvent;
207 renderer->CreateTexture = GLES_CreateTexture;
208 renderer->QueryTexturePixels = GLES_QueryTexturePixels;
209 renderer->UpdateTexture = GLES_UpdateTexture;
210 renderer->LockTexture = GLES_LockTexture;
211 renderer->UnlockTexture = GLES_UnlockTexture;
212 renderer->DirtyTexture = GLES_DirtyTexture;
213 renderer->RenderDrawPoints = GLES_RenderDrawPoints;
214 renderer->RenderDrawLines = GLES_RenderDrawLines;
215 renderer->RenderFillRects = GLES_RenderFillRects;
216 renderer->RenderCopy = GLES_RenderCopy;
217 renderer->RenderPresent = GLES_RenderPresent;
218 renderer->DestroyTexture = GLES_DestroyTexture;
219 renderer->DestroyRenderer = GLES_DestroyRenderer;
220 renderer->info = GL_ES_RenderDriver.info;
221 renderer->window = window;
222 renderer->driverdata = data;
223
224 renderer->info.flags = SDL_RENDERER_ACCELERATED;
225
226 if (GLES_LoadFunctions(data) < 0) {
227 GLES_DestroyRenderer(renderer);
228 return NULL;
229 }
230
231 data->context = SDL_GL_CreateContext(window);
232 if (!data->context) {
233 GLES_DestroyRenderer(renderer);
234 return NULL;
235 }
236 if (SDL_GL_MakeCurrent(window, data->context) < 0) {
237 GLES_DestroyRenderer(renderer);
238 return NULL;
239 }
240
241 if (flags & SDL_RENDERER_PRESENTVSYNC) {
242 SDL_GL_SetSwapInterval(1);
243 } else {
244 SDL_GL_SetSwapInterval(0);
245 }
246 if (SDL_GL_GetSwapInterval() > 0) {
247 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
248 }
249
250 #if SDL_VIDEO_DRIVER_PANDORA
251 data->GL_OES_draw_texture_supported = SDL_FALSE;
252 data->useDrawTexture = SDL_FALSE;
253 #else
254 if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) {
255 data->GL_OES_draw_texture_supported = SDL_TRUE;
256 data->useDrawTexture = SDL_TRUE;
257 } else {
258 data->GL_OES_draw_texture_supported = SDL_FALSE;
259 data->useDrawTexture = SDL_FALSE;
260 }
261 #endif
262
263 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
264 renderer->info.max_texture_width = value;
265 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
266 renderer->info.max_texture_height = value;
267
268 /* Set up parameters for rendering */
269 data->blendMode = -1;
270 data->glDisable(GL_DEPTH_TEST);
271 data->glDisable(GL_CULL_FACE);
272 data->updateSize = SDL_TRUE;
273
274 data->glEnableClientState(GL_VERTEX_ARRAY);
275 data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
276
277 return renderer;
278 }
279
280 static SDL_GLContext SDL_CurrentContext = NULL;
281
282 static int
283 GLES_ActivateRenderer(SDL_Renderer * renderer)
284 {
285
286 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
287 SDL_Window *window = renderer->window;
288
289 if (SDL_CurrentContext != data->context) {
290 if (SDL_GL_MakeCurrent(window, data->context) < 0) {
291 return -1;
292 }
293 SDL_CurrentContext = data->context;
294 }
295 if (data->updateSize) {
296 int w, h;
297
298 SDL_GetWindowSize(window, &w, &h);
299 data->glMatrixMode(GL_PROJECTION);
300 data->glLoadIdentity();
301 data->glMatrixMode(GL_MODELVIEW);
302 data->glLoadIdentity();
303 data->glViewport(0, 0, w, h);
304 data->glOrthof(0.0, (GLfloat) w, (GLfloat) h, 0.0, 0.0, 1.0);
305 data->updateSize = SDL_FALSE;
306 }
307 return 0;
308 }
309
310 static void
311 GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
312 {
313 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
314
315 if (event->event == SDL_WINDOWEVENT_RESIZED) {
316 /* Rebind the context to the window area and update matrices */
317 SDL_CurrentContext = NULL;
318 data->updateSize = SDL_TRUE;
319 }
320 }
321
322 static __inline__ int
323 power_of_2(int input)
324 {
325 int value = 1;
326
327 while (value < input) {
328 value <<= 1;
329 }
330 return value;
331 }
332
333 static int
334 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
335 {
336 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
337 GLES_TextureData *data;
338 GLint internalFormat;
339 GLenum format, type;
340 int texture_w, texture_h;
341 GLenum result;
342
343 GLES_ActivateRenderer(renderer);
344
345 switch (texture->format) {
346 case SDL_PIXELFORMAT_RGB24:
347 internalFormat = GL_RGB;
348 format = GL_RGB;
349 type = GL_UNSIGNED_BYTE;
350 break;
351 case SDL_PIXELFORMAT_BGR888:
352 case SDL_PIXELFORMAT_ABGR8888:
353 internalFormat = GL_RGBA;
354 format = GL_RGBA;
355 type = GL_UNSIGNED_BYTE;
356 break;
357 case SDL_PIXELFORMAT_RGB565:
358 internalFormat = GL_RGB;
359 format = GL_RGB;
360 type = GL_UNSIGNED_SHORT_5_6_5;
361 break;
362 case SDL_PIXELFORMAT_RGBA5551:
363 internalFormat = GL_RGBA;
364 format = GL_RGBA;
365 type = GL_UNSIGNED_SHORT_5_5_5_1;
366 break;
367 case SDL_PIXELFORMAT_RGBA4444:
368 internalFormat = GL_RGBA;
369 format = GL_RGBA;
370 type = GL_UNSIGNED_SHORT_4_4_4_4;
371 break;
372 default:
373 SDL_SetError("Texture format %s not supported by OpenGL ES",
374 SDL_GetPixelFormatName(texture->format));
375 return -1;
376 }
377
378 data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data));
379 if (!data) {
380 SDL_OutOfMemory();
381 return -1;
382 }
383
384 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
385 data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
386 data->pixels = SDL_malloc(texture->h * data->pitch);
387 if (!data->pixels) {
388 SDL_OutOfMemory();
389 SDL_free(data);
390 return -1;
391 }
392 }
393
394 texture->driverdata = data;
395
396 renderdata->glGetError();
397 renderdata->glEnable(GL_TEXTURE_2D);
398 renderdata->glGenTextures(1, &data->texture);
399
400 data->type = GL_TEXTURE_2D;
401 /* no NPOV textures allowed in OpenGL ES (yet) */
402 texture_w = power_of_2(texture->w);
403 texture_h = power_of_2(texture->h);
404 data->texw = (GLfloat) texture->w / texture_w;
405 data->texh = (GLfloat) texture->h / texture_h;
406
407 data->format = format;
408 data->formattype = type;
409 renderdata->glBindTexture(data->type, data->texture);
410 renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
411 GL_LINEAR);
412 renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
413 GL_LINEAR);
414 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
415 GL_CLAMP_TO_EDGE);
416 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
417 GL_CLAMP_TO_EDGE);
418
419 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
420 texture_h, 0, format, type, NULL);
421 renderdata->glDisable(GL_TEXTURE_2D);
422
423 result = renderdata->glGetError();
424 if (result != GL_NO_ERROR) {
425 GLES_SetError("glTexImage2D()", result);
426 return -1;
427 }
428 return 0;
429 }
430
431 static int
432 GLES_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
433 void **pixels, int *pitch)
434 {
435 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
436
437 *pixels = data->pixels;
438 *pitch = data->pitch;
439 return 0;
440 }
441
442 static void
443 SetupTextureUpdate(GLES_RenderData * renderdata, SDL_Texture * texture,
444 int pitch)
445 {
446 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
447 renderdata->glBindTexture(data->type, data->texture);
448 renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
449 }
450
451 static int
452 GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
453 const SDL_Rect * rect, const void *pixels, int pitch)
454 {
455 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
456 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
457 GLenum result;
458 int bpp = SDL_BYTESPERPIXEL(texture->format);
459 void * temp_buffer;
460 void * temp_ptr;
461 int i;
462
463 GLES_ActivateRenderer(renderer);
464
465 renderdata->glGetError();
466 renderdata->glEnable(data->type);
467 SetupTextureUpdate(renderdata, texture, pitch);
468
469 if( rect->w * bpp == pitch ) {
470 temp_buffer = (void *)pixels; /* No need to reformat */
471 } else {
472 /* Reformatting of mem area required */
473 temp_buffer = SDL_malloc(rect->w * rect->h * bpp);
474 temp_ptr = temp_buffer;
475 for (i = 0; i < rect->h; i++) {
476 SDL_memcpy(temp_ptr, pixels, rect->w * bpp);
477 temp_ptr += rect->w * bpp;
478 pixels += pitch;
479 }
480 }
481
482 renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
483 rect->h, data->format, data->formattype,
484 temp_buffer);
485
486 if( temp_buffer != pixels ) {
487 SDL_free(temp_buffer);
488 }
489
490 renderdata->glDisable(data->type);
491 result = renderdata->glGetError();
492 if (result != GL_NO_ERROR) {
493 GLES_SetError("glTexSubImage2D()", result);
494 return -1;
495 }
496 return 0;
497 }
498
499 static int
500 GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
501 const SDL_Rect * rect, int markDirty, void **pixels,
502 int *pitch)
503 {
504 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
505
506 if (markDirty) {
507 SDL_AddDirtyRect(&data->dirty, rect);
508 }
509
510 *pixels =
511 (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
512 rect->x * SDL_BYTESPERPIXEL(texture->format));
513 *pitch = data->pitch;
514 return 0;
515 }
516
517 static void
518 GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
519 {
520 }
521
522 static void
523 GLES_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
524 int numrects, const SDL_Rect * rects)
525 {
526 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
527 int i;
528
529 for (i = 0; i < numrects; ++i) {
530 SDL_AddDirtyRect(&data->dirty, &rects[i]);
531 }
532 }
533
534 static void
535 GLES_SetBlendMode(GLES_RenderData * data, int blendMode)
536 {
537 if (blendMode != data->blendMode) {
538 switch (blendMode) {
539 case SDL_BLENDMODE_NONE:
540 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
541 data->glDisable(GL_BLEND);
542 break;
543 case SDL_BLENDMODE_BLEND:
544 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
545 data->glEnable(GL_BLEND);
546 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
547 break;
548 case SDL_BLENDMODE_ADD:
549 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
550 data->glEnable(GL_BLEND);
551 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
552 break;
553 }
554 data->blendMode = blendMode;
555 }
556 }
557
558 static int
559 GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
560 int count)
561 {
562 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
563 int i;
564 GLshort *vertices;
565
566 GLES_ActivateRenderer(renderer);
567
568 GLES_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 vertices = SDL_stack_alloc(GLshort, count*2);
576 for (i = 0; i < count; ++i) {
577 vertices[2*i+0] = (GLshort)points[i].x;
578 vertices[2*i+1] = (GLshort)points[i].y;
579 }
580 data->glVertexPointer(2, GL_SHORT, 0, vertices);
581 data->glDrawArrays(GL_POINTS, 0, count);
582 SDL_stack_free(vertices);
583
584 return 0;
585 }
586
587 static int
588 GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
589 int count)
590 {
591 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
592 int i;
593 GLshort *vertices;
594
595 GLES_ActivateRenderer(renderer);
596
597 GLES_SetBlendMode(data, renderer->blendMode);
598
599 data->glColor4f((GLfloat) renderer->r * inv255f,
600 (GLfloat) renderer->g * inv255f,
601 (GLfloat) renderer->b * inv255f,
602 (GLfloat) renderer->a * inv255f);
603
604 vertices = SDL_stack_alloc(GLshort, count*2);
605 for (i = 0; i < count; ++i) {
606 vertices[2*i+0] = (GLshort)points[i].x;
607 vertices[2*i+1] = (GLshort)points[i].y;
608 }
609 data->glVertexPointer(2, GL_SHORT, 0, vertices);
610 if (count > 2 &&
611 points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
612 /* GL_LINE_LOOP takes care of the final segment */
613 --count;
614 data->glDrawArrays(GL_LINE_LOOP, 0, count);
615 } else {
616 data->glDrawArrays(GL_LINE_STRIP, 0, count);
617 }
618 SDL_stack_free(vertices);
619
620 return 0;
621 }
622
623 static int
624 GLES_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
625 int count)
626 {
627 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
628 int i;
629
630 GLES_ActivateRenderer(renderer);
631
632 GLES_SetBlendMode(data, renderer->blendMode);
633
634 data->glColor4f((GLfloat) renderer->r * inv255f,
635 (GLfloat) renderer->g * inv255f,
636 (GLfloat) renderer->b * inv255f,
637 (GLfloat) renderer->a * inv255f);
638
639 for (i = 0; i < count; ++i) {
640 const SDL_Rect *rect = rects[i];
641 GLshort minx = rect->x;
642 GLshort maxx = rect->x + rect->w;
643 GLshort miny = rect->y;
644 GLshort maxy = rect->y + rect->h;
645 GLshort vertices[8];
646 vertices[0] = minx;
647 vertices[1] = miny;
648 vertices[2] = maxx;
649 vertices[3] = miny;
650 vertices[4] = minx;
651 vertices[5] = maxy;
652 vertices[6] = maxx;
653 vertices[7] = maxy;
654
655 data->glVertexPointer(2, GL_SHORT, 0, vertices);
656 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
657 }
658
659 return 0;
660 }
661
662 static int
663 GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
664 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
665 {
666
667 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
668 GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
669 int minx, miny, maxx, maxy;
670 GLfloat minu, maxu, minv, maxv;
671 int i;
672 void *temp_buffer; /* used for reformatting dirty rect pixels */
673 void *temp_ptr;
674
675 GLES_ActivateRenderer(renderer);
676
677 data->glEnable(GL_TEXTURE_2D);
678
679 if (texturedata->dirty.list) {
680 SDL_DirtyRect *dirty;
681 void *pixels;
682 int bpp = SDL_BYTESPERPIXEL(texture->format);
683 int pitch = texturedata->pitch;
684
685 SetupTextureUpdate(data, texture, pitch);
686
687 data->glBindTexture(texturedata->type, texturedata->texture);
688 for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
689 SDL_Rect *rect = &dirty->rect;
690 pixels =
691 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
692 rect->x * bpp);
693 /* There is no GL_UNPACK_ROW_LENGTH in OpenGLES
694 we must do this reformatting ourselves(!)
695
696 maybe it'd be a good idea to keep a temp buffer around
697 for this purpose rather than allocating it each time
698 */
699 if( rect->x == 0 && rect->w * bpp == pitch ) {
700 temp_buffer = pixels; /* Updating whole texture, no need to reformat */
701 } else {
702 temp_buffer = SDL_malloc(rect->w * rect->h * bpp);
703 temp_ptr = temp_buffer;
704 for (i = 0; i < rect->h; i++) {
705 SDL_memcpy(temp_ptr, pixels, rect->w * bpp);
706 temp_ptr += rect->w * bpp;
707 pixels += pitch;
708 }
709 }
710
711 data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
712 rect->w, rect->h, texturedata->format,
713 texturedata->formattype, temp_buffer);
714
715 if( temp_buffer != pixels ) {
716 SDL_free(temp_buffer);
717 }
718 }
719 SDL_ClearDirtyRects(&texturedata->dirty);
720 }
721
722 data->glBindTexture(texturedata->type, texturedata->texture);
723
724 if (texture->modMode) {
725 data->glColor4f((GLfloat) texture->r * inv255f,
726 (GLfloat) texture->g * inv255f,
727 (GLfloat) texture->b * inv255f,
728 (GLfloat) texture->a * inv255f);
729 } else {
730 data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
731 }
732
733 GLES_SetBlendMode(data, texture->blendMode);
734
735 if (data->GL_OES_draw_texture_supported && data->useDrawTexture) {
736 /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */
737 GLint cropRect[4];
738 int w, h;
739 SDL_Window *window = renderer->window;
740
741 SDL_GetWindowSize(window, &w, &h);
742 cropRect[0] = srcrect->x;
743 cropRect[1] = srcrect->y + srcrect->h;
744 cropRect[2] = srcrect->w;
745 cropRect[3] = -srcrect->h;
746 data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
747 cropRect);
748 data->glDrawTexiOES(dstrect->x, h - dstrect->y - dstrect->h, 0,
749 dstrect->w, dstrect->h);
750 } else {
751
752 minx = dstrect->x;
753 miny = dstrect->y;
754 maxx = dstrect->x + dstrect->w;
755 maxy = dstrect->y + dstrect->h;
756
757 minu = (GLfloat) srcrect->x / texture->w;
758 minu *= texturedata->texw;
759 maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
760 maxu *= texturedata->texw;
761 minv = (GLfloat) srcrect->y / texture->h;
762 minv *= texturedata->texh;
763 maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
764 maxv *= texturedata->texh;
765
766 GLshort vertices[8];
767 GLfloat texCoords[8];
768
769 vertices[0] = minx;
770 vertices[1] = miny;
771 vertices[2] = maxx;
772 vertices[3] = miny;
773 vertices[4] = minx;
774 vertices[5] = maxy;
775 vertices[6] = maxx;
776 vertices[7] = maxy;
777
778 texCoords[0] = minu;
779 texCoords[1] = minv;
780 texCoords[2] = maxu;
781 texCoords[3] = minv;
782 texCoords[4] = minu;
783 texCoords[5] = maxv;
784 texCoords[6] = maxu;
785 texCoords[7] = maxv;
786
787 data->glVertexPointer(2, GL_SHORT, 0, vertices);
788 data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
789 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
790 }
791
792 data->glDisable(GL_TEXTURE_2D);
793
794 return 0;
795 }
796
797 static void
798 GLES_RenderPresent(SDL_Renderer * renderer)
799 {
800 GLES_ActivateRenderer(renderer);
801
802 SDL_GL_SwapWindow(renderer->window);
803 }
804
805 static void
806 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
807 {
808 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
809
810 GLES_ActivateRenderer(renderer);
811
812 if (!data) {
813 return;
814 }
815 if (data->texture) {
816 glDeleteTextures(1, &data->texture);
817 }
818 if (data->pixels) {
819 SDL_free(data->pixels);
820 }
821 SDL_FreeDirtyRects(&data->dirty);
822 SDL_free(data);
823 texture->driverdata = NULL;
824 }
825
826 static void
827 GLES_DestroyRenderer(SDL_Renderer * renderer)
828 {
829 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
830
831 if (data) {
832 if (data->context) {
833 SDL_GL_DeleteContext(data->context);
834 }
835 SDL_free(data);
836 }
837 SDL_free(renderer);
838 }
839
840 #endif /* SDL_VIDEO_RENDER_OGL_ES */
841
842 /* vi: set ts=4 sw=4 expandtab: */