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