src/video/SDL_renderer_gles.c
author Holmes Futrell <hfutrell@umail.ucsb.edu>
Tue, 02 Sep 2008 00:37:04 +0000
changeset 2739 68862734a5fd
child 2753 0969758c8809
permissions -rw-r--r--
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.
     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: */