SDL_gpu  0.11.0
A hardware-accelerated, cross-platform 2D graphics API
renderer_GL_common.inl
Go to the documentation of this file.
1 /* This is an implementation file to be included after certain #defines have been set.
2 See a particular renderer's *.c file for specifics. */
3 
4 #if !defined(GLAPIENTRY)
5  #if defined(GL_APIENTRY)
6  #define GLAPIENTRY GL_APIENTRY
7  #else
8  #define GLAPIENTRY
9  #endif
10 #endif
11 
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include "SDL_platform.h"
15 #include <math.h>
16 #include <string.h>
17 
18 // Check for C99 support
19 // We'll use it for intptr_t which is used to suppress warnings about converting an int to a ptr for GL calls.
20 #if __STDC_VERSION__ >= 199901L
21  #include <stdint.h>
22 #else
23  #define intptr_t long
24 #endif
25 
26 #include "stb_image.h"
27 #include "stb_image_write.h"
28 
29 #ifndef M_PI
30 #define M_PI 3.14159265358979323846
31 #endif
32 
33 // Visual C does not support static inline
34 #ifndef static_inline
35  #ifdef _MSC_VER
36  #define static_inline static
37  #else
38  #define static_inline static inline
39  #endif
40 #endif
41 
42 #if defined ( WIN32 )
43 #define __func__ __FUNCTION__
44 #endif
45 
46 // Old Visual C did not support C99 (which includes a safe snprintf)
47 #if defined(_MSC_VER) && (_MSC_VER < 1900)
48  #define snprintf c99_snprintf
49  // From Valentin Milea: http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
50  static_inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
51  {
52  int count = -1;
53 
54  if (size != 0)
55  count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
56  if (count == -1)
57  count = _vscprintf(format, ap);
58 
59  return count;
60  }
61 
62  static_inline int c99_snprintf(char* str, size_t size, const char* format, ...)
63  {
64  int count;
65  va_list ap;
66 
67  va_start(ap, format);
68  count = c99_vsnprintf(str, size, format, ap);
69  va_end(ap);
70 
71  return count;
72  }
73 #endif
74 
75 int gpu_strcasecmp(const char* s1, const char* s2);
76 
77 
78 // Default to buffer reset VBO upload method
79 #if defined(SDL_GPU_USE_BUFFER_PIPELINE) && !defined(SDL_GPU_USE_BUFFER_RESET) && !defined(SDL_GPU_USE_BUFFER_MAPPING) && !defined(SDL_GPU_USE_BUFFER_UPDATE)
80  #define SDL_GPU_USE_BUFFER_RESET
81 #endif
82 
83 
84 // Forces a flush when vertex limit is reached (roughly 1000 sprites)
85 #define GPU_BLIT_BUFFER_VERTICES_PER_SPRITE 4
86 #define GPU_BLIT_BUFFER_INIT_MAX_NUM_VERTICES (GPU_BLIT_BUFFER_VERTICES_PER_SPRITE*1000)
87 
88 
89 // Near the unsigned short limit (65535)
90 #define GPU_BLIT_BUFFER_ABSOLUTE_MAX_VERTICES 60000
91 // Near the unsigned int limit (4294967295)
92 #define GPU_INDEX_BUFFER_ABSOLUTE_MAX_VERTICES 4000000000u
93 
94 
95 // x, y, s, t, r, g, b, a
96 #define GPU_BLIT_BUFFER_FLOATS_PER_VERTEX 8
97 
98 // bytes per vertex
99 #define GPU_BLIT_BUFFER_STRIDE (sizeof(float)*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX)
100 #define GPU_BLIT_BUFFER_VERTEX_OFFSET 0
101 #define GPU_BLIT_BUFFER_TEX_COORD_OFFSET 2
102 #define GPU_BLIT_BUFFER_COLOR_OFFSET 4
103 
104 
105 
106 // SDL 1.2 / SDL 2.0 translation layer
107 
108 
109 #ifdef SDL_GPU_USE_SDL2
110 
111 #define GET_ALPHA(sdl_color) ((sdl_color).a)
112 
113 static_inline SDL_Window* get_window(Uint32 windowID)
114 {
115  return SDL_GetWindowFromID(windowID);
116 }
117 
118 static_inline Uint32 get_window_id(SDL_Window* window)
119 {
120  return SDL_GetWindowID(window);
121 }
122 
123 static_inline void get_window_dimensions(SDL_Window* window, int* w, int* h)
124 {
125  SDL_GetWindowSize(window, w, h);
126 }
127 
128 static_inline void get_drawable_dimensions(SDL_Window* window, int* w, int* h)
129 {
130  SDL_GL_GetDrawableSize(window, w, h);
131 }
132 
133 static_inline void resize_window(GPU_Target* target, int w, int h)
134 {
135  SDL_SetWindowSize(SDL_GetWindowFromID(target->context->windowID), w, h);
136 }
137 
139 {
140  return (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN);
141 }
142 
143 static_inline GPU_bool has_colorkey(SDL_Surface* surface)
144 {
145  return (SDL_GetColorKey(surface, NULL) == 0);
146 }
147 
148 #else
149 
150 #define SDL_Window SDL_Surface
151 #define GET_ALPHA(sdl_color) ((sdl_color).unused)
152 
154 {
155  return (windowID == 1? SDL_GetVideoSurface() : NULL);
156 }
157 
158 static_inline Uint32 get_window_id(SDL_Surface* window)
159 {
160  return (SDL_GetVideoSurface() == window? 1 : 0);
161 }
162 
163 static_inline void get_window_dimensions(SDL_Window* window, int* w, int* h)
164 {
165  if(window == NULL)
166  return;
167  *w = window->w;
168  *h = window->h;
169 }
170 
171 static_inline void get_drawable_dimensions(SDL_Window* window, int* w, int* h)
172 {
173  get_window_dimensions(window, w, h);
174 }
175 
176 static_inline void resize_window(GPU_Target* target, int w, int h)
177 {
178  SDL_Surface* screen = SDL_GetVideoSurface();
179  Uint32 flags = screen->flags;
180 
181  screen = SDL_SetVideoMode(w, h, 0, flags);
182  // NOTE: There's a bug in SDL 1.2. This is a workaround. Let's resize again:
183  screen = SDL_SetVideoMode(w, h, 0, flags);
184 }
185 
187 {
188  return (window->flags & SDL_FULLSCREEN);
189 }
190 
191 static_inline GPU_bool has_colorkey(SDL_Surface* surface)
192 {
193  return (surface->flags & SDL_SRCCOLORKEY);
194 }
195 
196 #endif
197 
198 
199 
201 {
202  SDL_Window* window;
203  if(target == NULL || target->context == NULL)
204  return;
205  window = get_window(target->context->windowID);
206  get_window_dimensions(window, w, h);
207 }
208 
210 {
211  SDL_Window* window;
212  if(target == NULL || target->context == NULL)
213  return;
214  window = get_window(target->context->windowID);
215  get_drawable_dimensions(window, w, h);
216 }
217 
218 
219 
220 
221 #ifndef GL_VERTEX_SHADER
222  #ifndef SDL_GPU_DISABLE_SHADERS
223  #define SDL_GPU_DISABLE_SHADERS
224  #endif
225 #endif
226 
227 
228 // Workaround for Intel HD glVertexAttrib() bug.
229 #ifdef SDL_GPU_USE_OPENGL
230 // FIXME: This should probably exist in context storage, as I expect it to be a problem across contexts.
231 static GPU_bool apply_Intel_attrib_workaround = GPU_FALSE;
232 static GPU_bool vendor_is_Intel = GPU_FALSE;
233 #endif
234 
235 
236 
237 static SDL_PixelFormat* AllocFormat(GLenum glFormat);
238 static void FreeFormat(SDL_PixelFormat* format);
239 
240 
241 static char shader_message[256];
242 
243 
244 
245 static GPU_bool isExtensionSupported(const char* extension_str)
246 {
247 #ifdef SDL_GPU_USE_OPENGL
248  return glewIsExtensionSupported(extension_str);
249 #else
250  // As suggested by Mesa3D.org
251  char* p = (char*)glGetString(GL_EXTENSIONS);
252  char* end;
253  unsigned long extNameLen;
254 
255  if(p == NULL)
256  return GPU_FALSE;
257 
258  extNameLen = strlen(extension_str);
259  end = p + strlen(p);
260 
261  while(p < end)
262  {
263  unsigned long n = strcspn(p, " ");
264  if((extNameLen == n) && (strncmp(extension_str, p, n) == 0))
265  return GPU_TRUE;
266 
267  p += (n + 1);
268  }
269  return GPU_FALSE;
270 #endif
271 }
272 
273 static_inline void fast_upload_texture(const void* pixels, GPU_Rect update_rect, Uint32 format, int alignment, int row_length)
274 {
275  glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
276  #if defined(SDL_GPU_USE_OPENGL) || SDL_GPU_GLES_MAJOR_VERSION > 2
277  glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
278  #endif
279 
280  glTexSubImage2D(GL_TEXTURE_2D, 0,
281  update_rect.x, update_rect.y, update_rect.w, update_rect.h,
282  format, GL_UNSIGNED_BYTE, pixels);
283 
284  #if defined(SDL_GPU_USE_OPENGL) || SDL_GPU_GLES_MAJOR_VERSION > 2
285  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
286  #endif
287  glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
288 }
289 
290 static void row_upload_texture(const unsigned char* pixels, GPU_Rect update_rect, Uint32 format, int alignment, unsigned int pitch, int bytes_per_pixel)
291 {
292  unsigned int i;
293  unsigned int h = update_rect.h;
294  glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
295  if(h > 0 && update_rect.w > 0.0f)
296  {
297  // Must upload row by row to account for row length
298  for(i = 0; i < h; ++i)
299  {
300  glTexSubImage2D(GL_TEXTURE_2D, 0,
301  update_rect.x, update_rect.y + i, update_rect.w, 1,
302  format, GL_UNSIGNED_BYTE, pixels);
303  pixels += pitch;
304  }
305  }
306  glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
307 }
308 
309 static void copy_upload_texture(const unsigned char* pixels, GPU_Rect update_rect, Uint32 format, int alignment, unsigned int pitch, int bytes_per_pixel)
310 {
311  unsigned int i;
312  unsigned int h = update_rect.h;
313  unsigned int w = update_rect.w*bytes_per_pixel;
314 
315  if(h > 0 && w > 0)
316  {
317  // Account for padding
318  w += w % alignment;
319 
320  unsigned char *copy = (unsigned char*)SDL_malloc(update_rect.h*w);
321  unsigned char *dst = copy;
322 
323  for(i = 0; i < h; ++i)
324  {
325  memcpy(dst, pixels, w);
326  pixels += pitch;
327  dst += w;
328  }
329  fast_upload_texture(copy, update_rect, format, alignment, update_rect.w);
330  SDL_free(copy);
331  }
332 }
333 
334 static void (*slow_upload_texture)(const unsigned char* pixels, GPU_Rect update_rect, Uint32 format, int alignment, unsigned int pitch, int bytes_per_pixel) = NULL;
335 
336 static_inline void upload_texture(const void* pixels, GPU_Rect update_rect, Uint32 format, int alignment, int row_length, unsigned int pitch, int bytes_per_pixel)
337 {
338  #if defined(SDL_GPU_USE_OPENGL) || SDL_GPU_GLES_MAJOR_VERSION > 2
339  fast_upload_texture(pixels, update_rect, format, alignment, row_length);
340  #else
341  if(row_length == update_rect.w)
342  fast_upload_texture(pixels, update_rect, format, alignment, row_length);
343  else
344  slow_upload_texture(pixels, update_rect, format, alignment, pitch, bytes_per_pixel);
345 
346  #endif
347 }
348 
349 static_inline void upload_new_texture(void* pixels, GPU_Rect update_rect, Uint32 format, int alignment, int row_length, int bytes_per_pixel)
350 {
351  #if defined(SDL_GPU_USE_OPENGL) || SDL_GPU_GLES_MAJOR_VERSION > 2
352  glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
353  glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
354  glTexImage2D(GL_TEXTURE_2D, 0, format, update_rect.w, update_rect.h, 0,
355  format, GL_UNSIGNED_BYTE, pixels);
356  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
357  glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
358  #else
359  glTexImage2D(GL_TEXTURE_2D, 0, format, update_rect.w, update_rect.h, 0,
360  format, GL_UNSIGNED_BYTE, NULL);
361  upload_texture(pixels, update_rect, format, alignment, row_length, row_length*bytes_per_pixel, bytes_per_pixel);
362  #endif
363 }
364 
365 // Define intermediates for FBO functions in case we only have EXT or OES FBO support.
366 #if defined(SDL_GPU_ASSUME_CORE_FBO)
367  #define glBindFramebufferPROC glBindFramebuffer
368  #define glCheckFramebufferStatusPROC glCheckFramebufferStatus
369  #define glDeleteFramebuffersPROC glDeleteFramebuffers
370  #define glFramebufferTexture2DPROC glFramebufferTexture2D
371  #define glGenFramebuffersPROC glGenFramebuffers
372  #define glGenerateMipmapPROC glGenerateMipmap
373 #else
374  static void GLAPIENTRY glBindFramebufferNOOP(GLenum target, GLuint framebuffer)
375  {
376  GPU_LogError("%s: Unsupported operation\n", __func__);
377  }
378  static GLenum GLAPIENTRY glCheckFramebufferStatusNOOP(GLenum target)
379  {
380  GPU_LogError("%s: Unsupported operation\n", __func__);
381  return 0;
382  }
383  static void GLAPIENTRY glDeleteFramebuffersNOOP(GLsizei n, const GLuint* framebuffers)
384  {
385  GPU_LogError("%s: Unsupported operation\n", __func__);
386  }
387  static void GLAPIENTRY glFramebufferTexture2DNOOP(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
388  {
389  GPU_LogError("%s: Unsupported operation\n", __func__);
390  }
391  static void GLAPIENTRY glGenFramebuffersNOOP(GLsizei n, GLuint *ids)
392  {
393  GPU_LogError("%s: Unsupported operation\n", __func__);
394  }
395  static void GLAPIENTRY glGenerateMipmapNOOP(GLenum target)
396  {
397  GPU_LogError("%s: Unsupported operation\n", __func__);
398  }
399 
400  static void (GLAPIENTRY *glBindFramebufferPROC)(GLenum target, GLuint framebuffer) = glBindFramebufferNOOP;
401  static GLenum (GLAPIENTRY *glCheckFramebufferStatusPROC)(GLenum target) = glCheckFramebufferStatusNOOP;
402  static void (GLAPIENTRY *glDeleteFramebuffersPROC)(GLsizei n, const GLuint* framebuffers) = glDeleteFramebuffersNOOP;
403  static void (GLAPIENTRY *glFramebufferTexture2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) = glFramebufferTexture2DNOOP;
404  static void (GLAPIENTRY *glGenFramebuffersPROC)(GLsizei n, GLuint *ids) = glGenFramebuffersNOOP;
405  static void (GLAPIENTRY *glGenerateMipmapPROC)(GLenum target) = glGenerateMipmapNOOP;
406 #endif
407 
408 static void init_features(GPU_Renderer* renderer)
409 {
410  // Reset supported features
411  renderer->enabled_features = 0;
412 
413  // NPOT textures
414 #ifdef SDL_GPU_USE_OPENGL
415  #if SDL_GPU_GL_MAJOR_VERSION >= 2
416  // Core in GL 2+
417  renderer->enabled_features |= GPU_FEATURE_NON_POWER_OF_TWO;
418  #else
419  if(isExtensionSupported("GL_ARB_texture_non_power_of_two"))
420  renderer->enabled_features |= GPU_FEATURE_NON_POWER_OF_TWO;
421  else
422  renderer->enabled_features &= ~GPU_FEATURE_NON_POWER_OF_TWO;
423  #endif
424 #elif defined(SDL_GPU_USE_GLES)
425  #if SDL_GPU_GLES_MAJOR_VERSION >= 3
426  // Core in GLES 3+
427  renderer->enabled_features |= GPU_FEATURE_NON_POWER_OF_TWO;
428  #else
429  if(isExtensionSupported("GL_OES_texture_npot") || isExtensionSupported("GL_IMG_texture_npot")
430  || isExtensionSupported("GL_APPLE_texture_2D_limited_npot") || isExtensionSupported("GL_ARB_texture_non_power_of_two"))
431  renderer->enabled_features |= GPU_FEATURE_NON_POWER_OF_TWO;
432  else
433  renderer->enabled_features &= ~GPU_FEATURE_NON_POWER_OF_TWO;
434 
435  #if SDL_GPU_GLES_MAJOR_VERSION >= 2
436  // Assume limited NPOT support for GLES 2+
437  renderer->enabled_features |= GPU_FEATURE_NON_POWER_OF_TWO;
438  #endif
439  #endif
440 #endif
441 
442  // FBO support
443 #ifdef SDL_GPU_ASSUME_CORE_FBO
444  renderer->enabled_features |= GPU_FEATURE_RENDER_TARGETS;
445  renderer->enabled_features |= GPU_FEATURE_CORE_FRAMEBUFFER_OBJECTS;
446 #elif defined(SDL_GPU_USE_OPENGL)
447  if(isExtensionSupported("GL_ARB_framebuffer_object"))
448  {
449  renderer->enabled_features |= GPU_FEATURE_RENDER_TARGETS;
450  renderer->enabled_features |= GPU_FEATURE_CORE_FRAMEBUFFER_OBJECTS;
451  glBindFramebufferPROC = glBindFramebuffer;
452  glCheckFramebufferStatusPROC = glCheckFramebufferStatus;
453  glDeleteFramebuffersPROC = glDeleteFramebuffers;
454  glFramebufferTexture2DPROC = glFramebufferTexture2D;
455  glGenFramebuffersPROC = glGenFramebuffers;
456  glGenerateMipmapPROC = glGenerateMipmap;
457  }
458  else if(isExtensionSupported("GL_EXT_framebuffer_object"))
459  {
460  renderer->enabled_features |= GPU_FEATURE_RENDER_TARGETS;
461  glBindFramebufferPROC = glBindFramebufferEXT;
462  glCheckFramebufferStatusPROC = glCheckFramebufferStatusEXT;
463  glDeleteFramebuffersPROC = glDeleteFramebuffersEXT;
464  glFramebufferTexture2DPROC = glFramebufferTexture2DEXT;
465  glGenFramebuffersPROC = glGenFramebuffersEXT;
466  glGenerateMipmapPROC = glGenerateMipmapEXT;
467  }
468  else
469  renderer->enabled_features &= ~GPU_FEATURE_RENDER_TARGETS;
470 #elif defined(SDL_GPU_USE_GLES)
471  if(isExtensionSupported("GL_OES_framebuffer_object"))
472  {
473  renderer->enabled_features |= GPU_FEATURE_RENDER_TARGETS;
474  glBindFramebufferPROC = glBindFramebufferOES;
475  glCheckFramebufferStatusPROC = glCheckFramebufferStatusOES;
476  glDeleteFramebuffersPROC = glDeleteFramebuffersOES;
477  glFramebufferTexture2DPROC = glFramebufferTexture2DOES;
478  glGenFramebuffersPROC = glGenFramebuffersOES;
479  glGenerateMipmapPROC = glGenerateMipmapOES;
480  }
481  else
482  renderer->enabled_features &= ~GPU_FEATURE_RENDER_TARGETS;
483 #endif
484 
485  // Blending
486 #ifdef SDL_GPU_USE_OPENGL
487  renderer->enabled_features |= GPU_FEATURE_BLEND_EQUATIONS;
488  renderer->enabled_features |= GPU_FEATURE_BLEND_FUNC_SEPARATE;
489 
490  #if SDL_GPU_GL_MAJOR_VERSION >= 2
491  // Core in GL 2+
492  renderer->enabled_features |= GPU_FEATURE_BLEND_EQUATIONS_SEPARATE;
493  #else
494  if(isExtensionSupported("GL_EXT_blend_equation_separate"))
495  renderer->enabled_features |= GPU_FEATURE_BLEND_EQUATIONS_SEPARATE;
496  else
497  renderer->enabled_features &= ~GPU_FEATURE_BLEND_EQUATIONS_SEPARATE;
498  #endif
499 
500 #elif defined(SDL_GPU_USE_GLES)
501 
502  #if SDL_GPU_GLES_MAJOR_VERSION >= 2
503  // Core in GLES 2+
504  renderer->enabled_features |= GPU_FEATURE_BLEND_EQUATIONS;
505  renderer->enabled_features |= GPU_FEATURE_BLEND_FUNC_SEPARATE;
506  renderer->enabled_features |= GPU_FEATURE_BLEND_EQUATIONS_SEPARATE;
507  #else
508  if(isExtensionSupported("GL_OES_blend_subtract"))
509  renderer->enabled_features |= GPU_FEATURE_BLEND_EQUATIONS;
510  else
511  renderer->enabled_features &= ~GPU_FEATURE_BLEND_EQUATIONS;
512 
513  if(isExtensionSupported("GL_OES_blend_func_separate"))
514  renderer->enabled_features |= GPU_FEATURE_BLEND_FUNC_SEPARATE;
515  else
516  renderer->enabled_features &= ~GPU_FEATURE_BLEND_FUNC_SEPARATE;
517 
518  if(isExtensionSupported("GL_OES_blend_equation_separate"))
519  renderer->enabled_features |= GPU_FEATURE_BLEND_EQUATIONS_SEPARATE;
520  else
521  renderer->enabled_features &= ~GPU_FEATURE_BLEND_EQUATIONS_SEPARATE;
522  #endif
523 #endif
524 
525  // Wrap modes
526 #ifdef SDL_GPU_USE_OPENGL
527  #if SDL_GPU_GL_MAJOR_VERSION >= 2
528  renderer->enabled_features |= GPU_FEATURE_WRAP_REPEAT_MIRRORED;
529  #else
530  if(isExtensionSupported("GL_ARB_texture_mirrored_repeat"))
531  renderer->enabled_features |= GPU_FEATURE_WRAP_REPEAT_MIRRORED;
532  else
533  renderer->enabled_features &= ~GPU_FEATURE_WRAP_REPEAT_MIRRORED;
534  #endif
535 #elif defined(SDL_GPU_USE_GLES)
536  #if SDL_GPU_GLES_MAJOR_VERSION >= 2
537  renderer->enabled_features |= GPU_FEATURE_WRAP_REPEAT_MIRRORED;
538  #else
539  if(isExtensionSupported("GL_OES_texture_mirrored_repeat"))
540  renderer->enabled_features |= GPU_FEATURE_WRAP_REPEAT_MIRRORED;
541  else
542  renderer->enabled_features &= ~GPU_FEATURE_WRAP_REPEAT_MIRRORED;
543  #endif
544 #endif
545 
546  // GL texture formats
547  if(isExtensionSupported("GL_EXT_bgr"))
548  renderer->enabled_features |= GPU_FEATURE_GL_BGR;
549  if(isExtensionSupported("GL_EXT_bgra"))
550  renderer->enabled_features |= GPU_FEATURE_GL_BGRA;
551  if(isExtensionSupported("GL_EXT_abgr"))
552  renderer->enabled_features |= GPU_FEATURE_GL_ABGR;
553 
554  // Disable other texture formats for GLES.
555  // TODO: Add better (static) checking for format support. Some GL versions do not report previously non-core features as extensions.
556  #ifdef SDL_GPU_USE_GLES
557  renderer->enabled_features &= ~GPU_FEATURE_GL_BGR;
558  renderer->enabled_features &= ~GPU_FEATURE_GL_BGRA;
559  renderer->enabled_features &= ~GPU_FEATURE_GL_ABGR;
560  #endif
561 
562  // Shader support
563  #ifndef SDL_GPU_DISABLE_SHADERS
564  if(isExtensionSupported("GL_ARB_fragment_shader"))
565  renderer->enabled_features |= GPU_FEATURE_FRAGMENT_SHADER;
566  if(isExtensionSupported("GL_ARB_vertex_shader"))
567  renderer->enabled_features |= GPU_FEATURE_VERTEX_SHADER;
568  if(isExtensionSupported("GL_ARB_geometry_shader4"))
569  renderer->enabled_features |= GPU_FEATURE_GEOMETRY_SHADER;
570  #endif
571  #ifdef SDL_GPU_ASSUME_SHADERS
573  #endif
574 }
575 
576 static void extBindFramebuffer(GPU_Renderer* renderer, GLuint handle)
577 {
578  if(renderer->enabled_features & GPU_FEATURE_RENDER_TARGETS)
579  glBindFramebufferPROC(GL_FRAMEBUFFER, handle);
580 }
581 
582 
584 {
585  return ((x != 0) && !(x & (x - 1)));
586 }
587 
588 static_inline unsigned int getNearestPowerOf2(unsigned int n)
589 {
590  unsigned int x = 1;
591  while(x < n)
592  {
593  x <<= 1;
594  }
595  return x;
596 }
597 
598 static void bindTexture(GPU_Renderer* renderer, GPU_Image* image)
599 {
600  // Bind the texture to which subsequent calls refer
601  if(image != ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_image)
602  {
603  GLuint handle = ((GPU_IMAGE_DATA*)image->data)->handle;
604  renderer->impl->FlushBlitBuffer(renderer);
605 
606  glBindTexture( GL_TEXTURE_2D, handle );
607  ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_image = image;
608  }
609 }
610 
611 static_inline void flushAndBindTexture(GPU_Renderer* renderer, GLuint handle)
612 {
613  // Bind the texture to which subsequent calls refer
614  renderer->impl->FlushBlitBuffer(renderer);
615 
616  glBindTexture( GL_TEXTURE_2D, handle );
617  ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_image = NULL;
618 }
619 
620 // Returns false if it can't be bound
621 static GPU_bool bindFramebuffer(GPU_Renderer* renderer, GPU_Target* target)
622 {
623  if(renderer->enabled_features & GPU_FEATURE_RENDER_TARGETS)
624  {
625  // Bind the FBO
626  if(target != ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target)
627  {
628  GLuint handle = 0;
629  if(target != NULL)
630  handle = ((GPU_TARGET_DATA*)target->data)->handle;
631  renderer->impl->FlushBlitBuffer(renderer);
632 
633  extBindFramebuffer(renderer, handle);
634  ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target = target;
635  }
636  return GPU_TRUE;
637  }
638  else
639  {
640  // There's only one possible render target, the default framebuffer.
641  // Note: Could check against the default framebuffer value (((GPU_TARGET_DATA*)target->data)->handle versus result of GL_FRAMEBUFFER_BINDING)...
642  if(target != NULL)
643  {
644  ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target = target;
645  return GPU_TRUE;
646  }
647  return GPU_FALSE;
648  }
649 }
650 
651 static_inline void flushAndBindFramebuffer(GPU_Renderer* renderer, GLuint handle)
652 {
653  // Bind the FBO
654  renderer->impl->FlushBlitBuffer(renderer);
655 
656  extBindFramebuffer(renderer, handle);
657  ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target = NULL;
658 }
659 
661 {
662  if(image == ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_image)
663  {
664  renderer->impl->FlushBlitBuffer(renderer);
665  }
666 }
667 
669 {
670  if(image == ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_image)
671  {
672  renderer->impl->FlushBlitBuffer(renderer);
673  ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_image = NULL;
674  }
675 }
676 
678 {
679  return (target == ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target
680  || ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target == NULL);
681 }
682 
684 {
685  if(target == ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target
686  || ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target == NULL)
687  {
688  renderer->impl->FlushBlitBuffer(renderer);
689  ((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target = NULL;
690  }
691 }
692 
693 static GPU_bool growBlitBuffer(GPU_CONTEXT_DATA* cdata, unsigned int minimum_vertices_needed)
694 {
695  unsigned int new_max_num_vertices;
696  float* new_buffer;
697 
698  if(minimum_vertices_needed <= cdata->blit_buffer_max_num_vertices)
699  return GPU_TRUE;
700  if(cdata->blit_buffer_max_num_vertices == GPU_BLIT_BUFFER_ABSOLUTE_MAX_VERTICES)
701  return GPU_FALSE;
702 
703  // Calculate new size (in vertices)
704  new_max_num_vertices = ((unsigned int)cdata->blit_buffer_max_num_vertices) * 2;
705  while(new_max_num_vertices <= minimum_vertices_needed)
706  new_max_num_vertices *= 2;
707 
708  if(new_max_num_vertices > GPU_BLIT_BUFFER_ABSOLUTE_MAX_VERTICES)
709  new_max_num_vertices = GPU_BLIT_BUFFER_ABSOLUTE_MAX_VERTICES;
710 
711  //GPU_LogError("Growing to %d vertices\n", new_max_num_vertices);
712  // Resize the blit buffer
713  new_buffer = (float*)SDL_malloc(new_max_num_vertices * GPU_BLIT_BUFFER_STRIDE);
714  memcpy(new_buffer, cdata->blit_buffer, cdata->blit_buffer_num_vertices * GPU_BLIT_BUFFER_STRIDE);
715  SDL_free(cdata->blit_buffer);
716  cdata->blit_buffer = new_buffer;
717  cdata->blit_buffer_max_num_vertices = new_max_num_vertices;
718 
719  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
720  // Resize the VBOs
721  #if !defined(SDL_GPU_NO_VAO)
722  glBindVertexArray(cdata->blit_VAO);
723  #endif
724 
725  glBindBuffer(GL_ARRAY_BUFFER, cdata->blit_VBO[0]);
726  glBufferData(GL_ARRAY_BUFFER, GPU_BLIT_BUFFER_STRIDE * cdata->blit_buffer_max_num_vertices, NULL, GL_STREAM_DRAW);
727  glBindBuffer(GL_ARRAY_BUFFER, cdata->blit_VBO[1]);
728  glBufferData(GL_ARRAY_BUFFER, GPU_BLIT_BUFFER_STRIDE * cdata->blit_buffer_max_num_vertices, NULL, GL_STREAM_DRAW);
729 
730  #if !defined(SDL_GPU_NO_VAO)
731  glBindVertexArray(0);
732  #endif
733  #endif
734 
735  return GPU_TRUE;
736 }
737 
738 static GPU_bool growIndexBuffer(GPU_CONTEXT_DATA* cdata, unsigned int minimum_vertices_needed)
739 {
740  unsigned int new_max_num_vertices;
741  unsigned short* new_indices;
742 
743  if(minimum_vertices_needed <= cdata->index_buffer_max_num_vertices)
744  return GPU_TRUE;
745  if(cdata->index_buffer_max_num_vertices == GPU_INDEX_BUFFER_ABSOLUTE_MAX_VERTICES)
746  return GPU_FALSE;
747 
748  // Calculate new size (in vertices)
749  new_max_num_vertices = cdata->index_buffer_max_num_vertices * 2;
750  while(new_max_num_vertices <= minimum_vertices_needed)
751  new_max_num_vertices *= 2;
752 
753  if(new_max_num_vertices > GPU_INDEX_BUFFER_ABSOLUTE_MAX_VERTICES)
754  new_max_num_vertices = GPU_INDEX_BUFFER_ABSOLUTE_MAX_VERTICES;
755 
756  //GPU_LogError("Growing to %d indices\n", new_max_num_vertices);
757  // Resize the index buffer
758  new_indices = (unsigned short*)SDL_malloc(new_max_num_vertices * sizeof(unsigned short));
759  memcpy(new_indices, cdata->index_buffer, cdata->index_buffer_num_vertices * sizeof(unsigned short));
760  SDL_free(cdata->index_buffer);
761  cdata->index_buffer = new_indices;
762  cdata->index_buffer_max_num_vertices = new_max_num_vertices;
763 
764  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
765  // Resize the IBO
766  #if !defined(SDL_GPU_NO_VAO)
767  glBindVertexArray(cdata->blit_VAO);
768  #endif
769 
770  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cdata->blit_IBO);
771  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * cdata->index_buffer_max_num_vertices, NULL, GL_DYNAMIC_DRAW);
772 
773  #if !defined(SDL_GPU_NO_VAO)
774  glBindVertexArray(0);
775  #endif
776  #endif
777 
778  return GPU_TRUE;
779 }
780 
781 
782 // Only for window targets, which have their own contexts.
783 static void makeContextCurrent(GPU_Renderer* renderer, GPU_Target* target)
784 {
785  if(target == NULL || target->context == NULL || renderer->current_context_target == target)
786  return;
787 
788  renderer->impl->FlushBlitBuffer(renderer);
789 
790  #ifdef SDL_GPU_USE_SDL2
791  SDL_GL_MakeCurrent(SDL_GetWindowFromID(target->context->windowID), target->context->context);
792  #endif
793  renderer->current_context_target = target;
794 }
795 
796 static void setClipRect(GPU_Renderer* renderer, GPU_Target* target)
797 {
798  if(target->use_clip_rect)
799  {
800  GPU_Target* context_target = renderer->current_context_target;
801  glEnable(GL_SCISSOR_TEST);
802  if(target->context != NULL)
803  {
804  int y;
805  if(renderer->coordinate_mode == 0)
806  y = context_target->h - (target->clip_rect.y + target->clip_rect.h);
807  else
808  y = target->clip_rect.y;
809  float xFactor = ((float)context_target->context->drawable_w)/context_target->w;
810  float yFactor = ((float)context_target->context->drawable_h)/context_target->h;
811  glScissor(target->clip_rect.x * xFactor, y * yFactor, target->clip_rect.w * xFactor, target->clip_rect.h * yFactor);
812  }
813  else
814  glScissor(target->clip_rect.x, target->clip_rect.y, target->clip_rect.w, target->clip_rect.h);
815  }
816 }
817 
818 static void unsetClipRect(GPU_Renderer* renderer, GPU_Target* target)
819 {
820  (void)renderer;
821  if(target->use_clip_rect)
822  glDisable(GL_SCISSOR_TEST);
823 }
824 
825 static void prepareToRenderToTarget(GPU_Renderer* renderer, GPU_Target* target)
826 {
827  // Set up the camera
828  renderer->impl->SetCamera(renderer, target, &target->camera);
829 }
830 
831 
832 
833 static void changeColor(GPU_Renderer* renderer, SDL_Color color)
834 {
835  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
836  (void)renderer;
837  (void)color;
838  return;
839  #else
841  if(cdata->last_color.r != color.r
842  || cdata->last_color.g != color.g
843  || cdata->last_color.b != color.b
844  || GET_ALPHA(cdata->last_color) != GET_ALPHA(color))
845  {
846  renderer->impl->FlushBlitBuffer(renderer);
847  cdata->last_color = color;
848  glColor4f(color.r/255.01f, color.g/255.01f, color.b/255.01f, GET_ALPHA(color)/255.01f);
849  }
850  #endif
851 }
852 
853 static void changeBlending(GPU_Renderer* renderer, GPU_bool enable)
854 {
856  if(cdata->last_use_blending == enable)
857  return;
858 
859  renderer->impl->FlushBlitBuffer(renderer);
860 
861  if(enable)
862  glEnable(GL_BLEND);
863  else
864  glDisable(GL_BLEND);
865 
866  cdata->last_use_blending = enable;
867 }
868 
869 static void forceChangeBlendMode(GPU_Renderer* renderer, GPU_BlendMode mode)
870 {
872 
873  renderer->impl->FlushBlitBuffer(renderer);
874 
875  cdata->last_blend_mode = mode;
876 
877  if(mode.source_color == mode.source_alpha && mode.dest_color == mode.dest_alpha)
878  {
879  glBlendFunc(mode.source_color, mode.dest_color);
880  }
881  else if(renderer->enabled_features & GPU_FEATURE_BLEND_FUNC_SEPARATE)
882  {
884  }
885  else
886  {
887  GPU_PushErrorCode("(SDL_gpu internal)", GPU_ERROR_BACKEND_ERROR, "Could not set blend function because GPU_FEATURE_BLEND_FUNC_SEPARATE is not supported.");
888  }
889 
890  if(renderer->enabled_features & GPU_FEATURE_BLEND_EQUATIONS)
891  {
892  if(mode.color_equation == mode.alpha_equation)
894  else if(renderer->enabled_features & GPU_FEATURE_BLEND_EQUATIONS_SEPARATE)
896  else
897  {
898  GPU_PushErrorCode("(SDL_gpu internal)", GPU_ERROR_BACKEND_ERROR, "Could not set blend equation because GPU_FEATURE_BLEND_EQUATIONS_SEPARATE is not supported.");
899  }
900  }
901  else
902  {
903  GPU_PushErrorCode("(SDL_gpu internal)", GPU_ERROR_BACKEND_ERROR, "Could not set blend equation because GPU_FEATURE_BLEND_EQUATIONS is not supported.");
904  }
905 }
906 
907 static void changeBlendMode(GPU_Renderer* renderer, GPU_BlendMode mode)
908 {
910  if(cdata->last_blend_mode.source_color == mode.source_color
911  && cdata->last_blend_mode.dest_color == mode.dest_color
912  && cdata->last_blend_mode.source_alpha == mode.source_alpha
913  && cdata->last_blend_mode.dest_alpha == mode.dest_alpha
914  && cdata->last_blend_mode.color_equation == mode.color_equation
915  && cdata->last_blend_mode.alpha_equation == mode.alpha_equation)
916  return;
917 
918  forceChangeBlendMode(renderer, mode);
919 }
920 
921 
922 // If 0 is returned, there is no valid shader.
923 static Uint32 get_proper_program_id(GPU_Renderer* renderer, Uint32 program_object)
924 {
925  GPU_Context* context = renderer->current_context_target->context;
926  if(context->default_textured_shader_program == 0) // No shaders loaded!
927  return 0;
928 
929  if(program_object == 0)
930  return context->default_textured_shader_program;
931 
932  return program_object;
933 }
934 
935 
936 
937 static void applyTexturing(GPU_Renderer* renderer)
938 {
939  GPU_Context* context = renderer->current_context_target->context;
940  if(context->use_texturing != ((GPU_CONTEXT_DATA*)context->data)->last_use_texturing)
941  {
942  ((GPU_CONTEXT_DATA*)context->data)->last_use_texturing = context->use_texturing;
943  #ifndef SDL_GPU_SKIP_ENABLE_TEXTURE_2D
944  if(context->use_texturing)
945  glEnable(GL_TEXTURE_2D);
946  else
947  glDisable(GL_TEXTURE_2D);
948  #endif
949  }
950 }
951 
952 static void changeTexturing(GPU_Renderer* renderer, GPU_bool enable)
953 {
954  GPU_Context* context = renderer->current_context_target->context;
955  if(enable != ((GPU_CONTEXT_DATA*)context->data)->last_use_texturing)
956  {
957  renderer->impl->FlushBlitBuffer(renderer);
958 
959  ((GPU_CONTEXT_DATA*)context->data)->last_use_texturing = enable;
960  #ifndef SDL_GPU_SKIP_ENABLE_TEXTURE_2D
961  if(enable)
962  glEnable(GL_TEXTURE_2D);
963  else
964  glDisable(GL_TEXTURE_2D);
965  #endif
966  }
967 }
968 
969 static void enableTexturing(GPU_Renderer* renderer)
970 {
972  {
973  renderer->impl->FlushBlitBuffer(renderer);
975  }
976 }
977 
978 static void disableTexturing(GPU_Renderer* renderer)
979 {
981  {
982  renderer->impl->FlushBlitBuffer(renderer);
984  }
985 }
986 
987 #define MIX_COLOR_COMPONENT_NORMALIZED_RESULT(a, b) ((a)/255.0f * (b)/255.0f)
988 #define MIX_COLOR_COMPONENT(a, b) (((a)/255.0f * (b)/255.0f)*255)
989 
990 static SDL_Color get_complete_mod_color(GPU_Renderer* renderer, GPU_Target* target, GPU_Image* image)
991 {
992  if(target->use_color)
993  {
994  SDL_Color color;
995  color.r = MIX_COLOR_COMPONENT(target->color.r, image->color.r);
996  color.g = MIX_COLOR_COMPONENT(target->color.g, image->color.g);
997  color.b = MIX_COLOR_COMPONENT(target->color.b, image->color.b);
998  GET_ALPHA(color) = MIX_COLOR_COMPONENT(GET_ALPHA(target->color), GET_ALPHA(image->color));
999 
1000  return color;
1001  }
1002  else
1003  return image->color;
1004 }
1005 
1006 static void prepareToRenderImage(GPU_Renderer* renderer, GPU_Target* target, GPU_Image* image)
1007 {
1008  GPU_Context* context = renderer->current_context_target->context;
1009 
1010  enableTexturing(renderer);
1011  if(GL_TRIANGLES != ((GPU_CONTEXT_DATA*)context->data)->last_shape)
1012  {
1013  renderer->impl->FlushBlitBuffer(renderer);
1014  ((GPU_CONTEXT_DATA*)context->data)->last_shape = GL_TRIANGLES;
1015  }
1016 
1017  // Blitting
1018  changeColor(renderer, get_complete_mod_color(renderer, target, image));
1019  changeBlending(renderer, image->use_blending);
1020  changeBlendMode(renderer, image->blend_mode);
1021 
1022  // If we're using the untextured shader, switch it.
1024  renderer->impl->ActivateShaderProgram(renderer, context->default_textured_shader_program, NULL);
1025 }
1026 
1027 static void prepareToRenderShapes(GPU_Renderer* renderer, unsigned int shape)
1028 {
1029  GPU_Context* context = renderer->current_context_target->context;
1030 
1031  disableTexturing(renderer);
1032  if(shape != ((GPU_CONTEXT_DATA*)context->data)->last_shape)
1033  {
1034  renderer->impl->FlushBlitBuffer(renderer);
1035  ((GPU_CONTEXT_DATA*)context->data)->last_shape = shape;
1036  }
1037 
1038  // Shape rendering
1039  // Color is set elsewhere for shapes
1040  changeBlending(renderer, context->shapes_use_blending);
1041  changeBlendMode(renderer, context->shapes_blend_mode);
1042 
1043  // If we're using the textured shader, switch it.
1045  renderer->impl->ActivateShaderProgram(renderer, context->default_untextured_shader_program, NULL);
1046 }
1047 
1048 
1049 
1050 static void forceChangeViewport(GPU_Target* target, GPU_Rect viewport)
1051 {
1052  float y;
1054 
1055  cdata->last_viewport = viewport;
1056 
1057  y = viewport.y;
1058  if(GPU_GetCoordinateMode() == 0)
1059  {
1060  // Need the real height to flip the y-coord (from OpenGL coord system)
1061  if(target->image != NULL)
1062  y = target->image->h - viewport.h - viewport.y;
1063  else if(target->context != NULL)
1064  y = target->context->drawable_h - viewport.h - viewport.y;
1065  }
1066 
1067  glViewport(viewport.x, y, viewport.w, viewport.h);
1068 }
1069 
1070 static void changeViewport(GPU_Target* target)
1071 {
1073 
1074  if(cdata->last_viewport.x == target->viewport.x && cdata->last_viewport.y == target->viewport.y && cdata->last_viewport.w == target->viewport.w && cdata->last_viewport.h == target->viewport.h)
1075  return;
1076 
1077  forceChangeViewport(target, target->viewport);
1078 }
1079 
1080 static void applyTargetCamera(GPU_Target* target)
1081 {
1083 
1084  cdata->last_camera = target->camera;
1085  cdata->last_camera_inverted = (target->image != NULL);
1086 }
1087 
1088 static GPU_bool equal_cameras(GPU_Camera a, GPU_Camera b)
1089 {
1090  return (a.x == b.x && a.y == b.y && a.z == b.z && a.angle == b.angle && a.zoom == b.zoom);
1091 }
1092 
1093 static void changeCamera(GPU_Target* target)
1094 {
1095  //GPU_CONTEXT_DATA* cdata = (GPU_CONTEXT_DATA*)GPU_GetContextTarget()->context->data;
1096 
1097  //if(cdata->last_camera_target != target || !equal_cameras(cdata->last_camera, target->camera))
1098  {
1099  applyTargetCamera(target);
1100  }
1101 }
1102 
1103 static void get_camera_matrix(float* result, GPU_Camera camera)
1104 {
1106  GPU_Target* target = cdata->last_target;
1107  GPU_bool invert = cdata->last_camera_inverted;
1108  float offsetX, offsetY;
1109 
1110  GPU_MatrixIdentity(result);
1111 
1112  // Now multiply in the projection part
1113  if(!invert ^ GPU_GetCoordinateMode())
1114  GPU_MatrixOrtho(result, target->camera.x, target->w + target->camera.x, target->h + target->camera.y, target->camera.y, -1.0f, 1.0f);
1115  else
1116  GPU_MatrixOrtho(result, target->camera.x, target->w + target->camera.x, target->camera.y, target->h + target->camera.y, -1.0f, 1.0f); // Special inverted orthographic projection because tex coords are inverted already for render-to-texture
1117 
1118  // First the modelview part
1119  offsetX = target->w/2.0f;
1120  offsetY = target->h/2.0f;
1121  GPU_MatrixTranslate(result, offsetX, offsetY, 0);
1122  GPU_MatrixRotate(result, target->camera.angle, 0, 0, 1);
1123  GPU_MatrixTranslate(result, -offsetX, -offsetY, 0);
1124 
1125  GPU_MatrixTranslate(result, target->camera.x + offsetX, target->camera.y + offsetY, 0);
1126  GPU_MatrixScale(result, target->camera.zoom, target->camera.zoom, 1.0f);
1127  GPU_MatrixTranslate(result, -target->camera.x - offsetX, -target->camera.y - offsetY, 0);
1128 
1129 }
1130 
1131 
1132 
1133 #ifdef SDL_GPU_APPLY_TRANSFORMS_TO_GL_STACK
1134 static void applyTransforms(void)
1135 {
1137  float* p = GPU_GetProjection();
1138  float* m = GPU_GetModelView();
1139 
1140  float cam_matrix[16];
1141  get_camera_matrix(cam_matrix, cdata->last_camera);
1142 
1143  GPU_MultiplyAndAssign(m, cam_matrix);
1144 
1145  glMatrixMode(GL_PROJECTION);
1146  glLoadMatrixf(p);
1147  glMatrixMode(GL_MODELVIEW);
1148  glLoadMatrixf(m);
1149 }
1150 #endif
1151 
1152 
1153 static GPU_Target* Init(GPU_Renderer* renderer, GPU_RendererID renderer_request, Uint16 w, Uint16 h, GPU_WindowFlagEnum SDL_flags)
1154 {
1155  GPU_InitFlagEnum GPU_flags;
1156  SDL_Window* window;
1157 
1158 #ifdef SDL_GPU_USE_OPENGL
1159  const char* vendor_string;
1160 #endif
1161 
1162  if(renderer_request.major_version < 1)
1163  {
1164  renderer_request.major_version = 1;
1165  renderer_request.minor_version = 1;
1166  }
1167 
1168  // Tell SDL what we require for the GL context.
1169  GPU_flags = GPU_GetPreInitFlags();
1170 
1171  renderer->GPU_init_flags = GPU_flags;
1172  if(GPU_flags & GPU_INIT_DISABLE_DOUBLE_BUFFER)
1173  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
1174  else
1175  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
1176 #ifdef SDL_GPU_USE_SDL2
1177 
1178  // GL profile
1179  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); // Disable in case this is a fallback renderer
1180  #ifdef SDL_GPU_USE_GLES
1181  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
1182  #endif
1183  // GL 3.2 and 3.3 have two profile modes
1184  // ARB_compatibility brings support for this to GL 3.1, but glGetStringi() via GLEW has chicken and egg problems.
1185  #if SDL_GPU_GL_MAJOR_VERSION == 3
1186  if(renderer_request.minor_version >= 2)
1187  {
1188  if(GPU_flags & GPU_INIT_REQUEST_COMPATIBILITY_PROFILE)
1189  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
1190  else
1191  {
1192  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
1193  // Force newer default shader version for core contexts because they don't support lower versions
1195  if(renderer->min_shader_version > renderer->max_shader_version)
1197  }
1198 
1199  }
1200  #endif
1201 
1202  // GL version
1203  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, renderer_request.major_version);
1204  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, renderer_request.minor_version);
1205 #else
1206  // vsync for SDL 1.2
1207  if(!(GPU_flags & GPU_INIT_DISABLE_VSYNC))
1208  SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
1209 #endif
1210 
1211  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
1212 
1213  SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
1214  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
1215  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
1216  SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
1217 
1218  renderer->requested_id = renderer_request;
1219 
1220 #ifdef SDL_GPU_USE_SDL2
1221 
1222  window = NULL;
1223  // Is there a window already set up that we are supposed to use?
1224  if(renderer->current_context_target != NULL)
1225  window = SDL_GetWindowFromID(renderer->current_context_target->context->windowID);
1226  else
1227  window = SDL_GetWindowFromID(GPU_GetInitWindow());
1228 
1229  if(window == NULL)
1230  {
1231  int win_w, win_h;
1232  #ifdef __ANDROID__
1233  win_w = win_h = 0; // Force Android to create full screen window
1234  #else
1235  win_w = w;
1236  win_h = h;
1237  #endif
1238 
1239  // Set up window flags
1240  SDL_flags |= SDL_WINDOW_OPENGL;
1241  if(!(SDL_flags & SDL_WINDOW_HIDDEN))
1242  SDL_flags |= SDL_WINDOW_SHOWN;
1243 
1244  renderer->SDL_init_flags = SDL_flags;
1245  window = SDL_CreateWindow("",
1246  SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
1247  win_w, win_h,
1248  SDL_flags);
1249 
1250  if(window == NULL)
1251  {
1252  GPU_PushErrorCode("GPU_Init", GPU_ERROR_BACKEND_ERROR, "Window creation failed.");
1253  return NULL;
1254  }
1255 
1257  }
1258  else
1259  renderer->SDL_init_flags = SDL_flags;
1260 
1261 #else
1262  SDL_flags |= SDL_OPENGL;
1263  renderer->SDL_init_flags = SDL_flags;
1264  window = SDL_SetVideoMode(w, h, 0, SDL_flags);
1265 
1266  if(window == NULL)
1267  {
1268  GPU_PushErrorCode("GPU_Init", GPU_ERROR_BACKEND_ERROR, "Screen surface creation failed.");
1269  return NULL;
1270  }
1271 #endif
1272 
1273  renderer->enabled_features = 0xFFFFFFFF; // Pretend to support them all if using incompatible headers
1274 
1275 
1276  // Create or re-init the current target. This also creates the GL context and initializes enabled_features.
1277  if(renderer->impl->CreateTargetFromWindow(renderer, get_window_id(window), renderer->current_context_target) == NULL)
1278  return NULL;
1279 
1280  // If the dimensions of the window don't match what we asked for, then set up a virtual resolution to pretend like they are.
1281  if(!(GPU_flags & GPU_INIT_DISABLE_AUTO_VIRTUAL_RESOLUTION) && w != 0 && h != 0 && (w != renderer->current_context_target->w || h != renderer->current_context_target->h))
1282  renderer->impl->SetVirtualResolution(renderer, renderer->current_context_target, w, h);
1283 
1284  // Init glVertexAttrib workaround
1285  #ifdef SDL_GPU_USE_OPENGL
1286  vendor_string = (const char*)glGetString(GL_VENDOR);
1287  if(strstr(vendor_string, "Intel") != NULL)
1288  {
1289  vendor_is_Intel = 1;
1290  apply_Intel_attrib_workaround = 1;
1291  }
1292  #endif
1293 
1294  return renderer->current_context_target;
1295 }
1296 
1297 
1298 static GPU_bool IsFeatureEnabled(GPU_Renderer* renderer, GPU_FeatureEnum feature)
1299 {
1300  return ((renderer->enabled_features & feature) == feature);
1301 }
1302 
1303 static GPU_bool get_GL_version(int* major, int* minor)
1304 {
1305  const char* version_string;
1306  #ifdef SDL_GPU_USE_OPENGL
1307  // OpenGL < 3.0 doesn't have GL_MAJOR_VERSION. Check via version string instead.
1308  version_string = (const char*)glGetString(GL_VERSION);
1309  if(version_string == NULL || sscanf(version_string, "%d.%d", major, minor) <= 0)
1310  {
1311  // Failure
1312  *major = SDL_GPU_GL_MAJOR_VERSION;
1313  #if SDL_GPU_GL_MAJOR_VERSION != 3
1314  *minor = 1;
1315  #else
1316  *minor = 0;
1317  #endif
1318 
1319  GPU_PushErrorCode(__func__, GPU_ERROR_BACKEND_ERROR, "Failed to parse OpenGL version string: \"%s\"", version_string);
1320  return GPU_FALSE;
1321  }
1322  return GPU_TRUE;
1323  #else
1324  // GLES doesn't have GL_MAJOR_VERSION. Check via version string instead.
1325  version_string = (const char*)glGetString(GL_VERSION);
1326  // OpenGL ES 2.0?
1327  if(version_string == NULL || sscanf(version_string, "OpenGL ES %d.%d", major, minor) <= 0)
1328  {
1329  // OpenGL ES-CM 1.1? OpenGL ES-CL 1.1?
1330  if(version_string == NULL || sscanf(version_string, "OpenGL ES-C%*c %d.%d", major, minor) <= 0)
1331  {
1332  // Failure
1333  *major = SDL_GPU_GLES_MAJOR_VERSION;
1334  #if SDL_GPU_GLES_MAJOR_VERSION == 1
1335  *minor = 1;
1336  #else
1337  *minor = 0;
1338  #endif
1339 
1340  GPU_PushErrorCode(__func__, GPU_ERROR_BACKEND_ERROR, "Failed to parse OpenGL ES version string: \"%s\"", version_string);
1341  return GPU_FALSE;
1342  }
1343  }
1344  return GPU_TRUE;
1345  #endif
1346 }
1347 
1348 static GPU_bool get_GLSL_version(int* version)
1349 {
1350  #ifndef SDL_GPU_DISABLE_SHADERS
1351  const char* version_string;
1352  int major, minor;
1353  #ifdef SDL_GPU_USE_OPENGL
1354  {
1355  version_string = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
1356  if(version_string == NULL || sscanf(version_string, "%d.%d", &major, &minor) <= 0)
1357  {
1358  GPU_PushErrorCode(__func__, GPU_ERROR_BACKEND_ERROR, "Failed to parse GLSL version string: \"%s\"", version_string);
1359  *version = SDL_GPU_GLSL_VERSION;
1360  return GPU_FALSE;
1361  }
1362  else
1363  *version = major*100 + minor;
1364  }
1365  #else
1366  {
1367  version_string = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
1368  if(version_string == NULL || sscanf(version_string, "OpenGL ES GLSL ES %d.%d", &major, &minor) <= 0)
1369  {
1370  GPU_PushErrorCode(__func__, GPU_ERROR_BACKEND_ERROR, "Failed to parse GLSL ES version string: \"%s\"", version_string);
1371  *version = SDL_GPU_GLSL_VERSION;
1372  return GPU_FALSE;
1373  }
1374  else
1375  *version = major*100 + minor;
1376  }
1377  #endif
1378  #endif
1379  return GPU_TRUE;
1380 }
1381 
1382 static GPU_bool get_API_versions(GPU_Renderer* renderer)
1383 {
1384  return (get_GL_version(&renderer->id.major_version, &renderer->id.minor_version)
1385  && get_GLSL_version(&renderer->max_shader_version));
1386 }
1387 
1388 
1389 static void update_stored_dimensions(GPU_Target* target)
1390 {
1391  GPU_bool is_fullscreen;
1392  SDL_Window* window;
1393 
1394  if(target->context == NULL)
1395  return;
1396 
1397  window = get_window(target->context->windowID);
1398  get_window_dimensions(window, &target->context->window_w, &target->context->window_h);
1399  is_fullscreen = get_fullscreen_state(window);
1400 
1401  if(!is_fullscreen)
1402  {
1403  target->context->stored_window_w = target->context->window_w;
1404  target->context->stored_window_h = target->context->window_h;
1405  }
1406 }
1407 
1408 static GPU_Target* CreateTargetFromWindow(GPU_Renderer* renderer, Uint32 windowID, GPU_Target* target)
1409 {
1410  GPU_bool created = GPU_FALSE; // Make a new one or repurpose an existing target?
1411  GPU_CONTEXT_DATA* cdata;
1412  SDL_Window* window;
1413 
1414  int framebuffer_handle;
1415  SDL_Color white = { 255, 255, 255, 255 };
1416 #ifdef SDL_GPU_USE_OPENGL
1417  GLenum err;
1418 #endif
1419  GPU_FeatureEnum required_features = GPU_GetRequiredFeatures();
1420 
1421  if(target == NULL)
1422  {
1423  int blit_buffer_storage_size;
1424  int index_buffer_storage_size;
1425 
1426  created = GPU_TRUE;
1427  target = (GPU_Target*)SDL_malloc(sizeof(GPU_Target));
1428  memset(target, 0, sizeof(GPU_Target));
1429  target->refcount = 1;
1430  target->is_alias = GPU_FALSE;
1431  target->data = (GPU_TARGET_DATA*)SDL_malloc(sizeof(GPU_TARGET_DATA));
1432  memset(target->data, 0, sizeof(GPU_TARGET_DATA));
1433  ((GPU_TARGET_DATA*)target->data)->refcount = 1;
1434  target->image = NULL;
1435  target->context = (GPU_Context*)SDL_malloc(sizeof(GPU_Context));
1436  memset(target->context, 0, sizeof(GPU_Context));
1437  cdata = (GPU_CONTEXT_DATA*)SDL_malloc(sizeof(GPU_CONTEXT_DATA));
1438  memset(cdata, 0, sizeof(GPU_CONTEXT_DATA));
1439 
1440  target->context->refcount = 1;
1441  target->context->data = cdata;
1442  target->context->context = NULL;
1443 
1444  cdata->last_image = NULL;
1445  cdata->last_target = NULL;
1446  // Initialize the blit buffer
1447  cdata->blit_buffer_max_num_vertices = GPU_BLIT_BUFFER_INIT_MAX_NUM_VERTICES;
1448  cdata->blit_buffer_num_vertices = 0;
1450  cdata->blit_buffer = (float*)SDL_malloc(blit_buffer_storage_size);
1451  cdata->index_buffer_max_num_vertices = GPU_BLIT_BUFFER_INIT_MAX_NUM_VERTICES;
1452  cdata->index_buffer_num_vertices = 0;
1453  index_buffer_storage_size = GPU_BLIT_BUFFER_INIT_MAX_NUM_VERTICES*sizeof(unsigned short);
1454  cdata->index_buffer = (unsigned short*)SDL_malloc(index_buffer_storage_size);
1455  }
1456  else
1457  {
1459  cdata = (GPU_CONTEXT_DATA*)target->context->data;
1460  }
1461 
1462 
1463  window = get_window(windowID);
1464  if(window == NULL)
1465  {
1466  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to acquire the window from the given ID.");
1467  if(created)
1468  {
1469  SDL_free(cdata->blit_buffer);
1470  SDL_free(cdata->index_buffer);
1471  SDL_free(target->context->data);
1472  SDL_free(target->context);
1473  SDL_free(target->data);
1474  SDL_free(target);
1475  }
1476  return NULL;
1477  }
1478 
1479  // Store the window info
1480  target->context->windowID = get_window_id(window);
1481 
1482  #ifdef SDL_GPU_USE_SDL2
1483  // Make a new context if needed and make it current
1484  if(created || target->context->context == NULL)
1485  {
1486  target->context->context = SDL_GL_CreateContext(window);
1487  if(target->context->context == NULL)
1488  {
1489  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to create GL context.");
1490  SDL_free(cdata->blit_buffer);
1491  SDL_free(cdata->index_buffer);
1492  SDL_free(target->context->data);
1493  SDL_free(target->context);
1494  SDL_free(target->data);
1495  SDL_free(target);
1496  return NULL;
1497  }
1498  GPU_AddWindowMapping(target);
1499  }
1500 
1501  // We need a GL context before we can get the drawable size.
1502  SDL_GL_GetDrawableSize(window, &target->context->drawable_w, &target->context->drawable_h);
1503 
1504  #else
1505 
1506  target->context->drawable_w = window->w;
1507  target->context->drawable_h = window->h;
1508 
1509  #endif
1510 
1511  update_stored_dimensions(target);
1512 
1513 
1514  ((GPU_TARGET_DATA*)target->data)->handle = 0;
1515  ((GPU_TARGET_DATA*)target->data)->format = GL_RGBA;
1516 
1517  target->renderer = renderer;
1518  target->context_target = renderer->current_context_target;
1519  target->w = target->context->drawable_w;
1520  target->h = target->context->drawable_h;
1521  target->base_w = target->context->drawable_w;
1522  target->base_h = target->context->drawable_h;
1523 
1524  target->use_clip_rect = GPU_FALSE;
1525  target->clip_rect.x = 0;
1526  target->clip_rect.y = 0;
1527  target->clip_rect.w = target->w;
1528  target->clip_rect.h = target->h;
1529  target->use_color = GPU_FALSE;
1530 
1531  target->viewport = GPU_MakeRect(0, 0, target->context->drawable_w, target->context->drawable_h);
1532  target->camera = GPU_GetDefaultCamera();
1533  target->use_camera = GPU_TRUE;
1534 
1535  target->context->line_thickness = 1.0f;
1536  target->context->use_texturing = GPU_TRUE;
1539 
1540  cdata->last_color = white;
1541 
1542  cdata->last_use_texturing = GPU_TRUE;
1543  cdata->last_shape = GL_TRIANGLES;
1544 
1545  cdata->last_use_blending = GPU_FALSE;
1546  cdata->last_blend_mode = GPU_GetBlendModeFromPreset(GPU_BLEND_NORMAL);
1547 
1548  cdata->last_viewport = target->viewport;
1549  cdata->last_camera = target->camera; // Redundant due to applyTargetCamera(), below
1550  cdata->last_camera_inverted = GPU_FALSE;
1551 
1552  #ifdef SDL_GPU_USE_OPENGL
1553  glewExperimental = GL_TRUE; // Force GLEW to get exported functions instead of checking via extension string
1554  err = glewInit();
1555  if (GLEW_OK != err)
1556  {
1557  // Probably don't have the right GL version for this renderer
1558  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to initialize extensions for renderer %s.", renderer->id.name);
1559  target->context->failed = GPU_TRUE;
1560  return NULL;
1561  }
1562  #endif
1563 
1564  renderer->impl->MakeCurrent(renderer, target, target->context->windowID);
1565 
1566  framebuffer_handle = 0;
1567  glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_handle);
1568  ((GPU_TARGET_DATA*)target->data)->handle = framebuffer_handle;
1569 
1570 
1571  // Update our renderer info from the current GL context.
1572  if(!get_API_versions(renderer))
1573  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to get backend API versions.");
1574 
1575  // Did the wrong runtime library try to use a later versioned renderer?
1576  if(renderer->id.major_version < renderer->requested_id.major_version)
1577  {
1578  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Renderer major version (%d) is incompatible with the available OpenGL runtime library version (%d).", renderer->requested_id.major_version, renderer->id.major_version);
1579  target->context->failed = GPU_TRUE;
1580  return NULL;
1581  }
1582 
1583 
1584  init_features(renderer);
1585 
1586  if(!IsFeatureEnabled(renderer, required_features))
1587  {
1588  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Renderer does not support required features.");
1589  target->context->failed = GPU_TRUE;
1590  return NULL;
1591  }
1592 
1593  #ifdef SDL_GPU_USE_SDL2
1594  // No preference for vsync?
1595  if(!(renderer->GPU_init_flags & (GPU_INIT_DISABLE_VSYNC | GPU_INIT_ENABLE_VSYNC)))
1596  {
1597  // Default to late swap vsync if available
1598  if(SDL_GL_SetSwapInterval(-1) < 0)
1599  SDL_GL_SetSwapInterval(1); // Or go for vsync
1600  }
1601  else if(renderer->GPU_init_flags & GPU_INIT_ENABLE_VSYNC)
1602  SDL_GL_SetSwapInterval(1);
1603  else if(renderer->GPU_init_flags & GPU_INIT_DISABLE_VSYNC)
1604  SDL_GL_SetSwapInterval(0);
1605  #endif
1606 
1607  // Set fallback texture upload method
1608  if(renderer->GPU_init_flags & GPU_INIT_USE_COPY_TEXTURE_UPLOAD_FALLBACK)
1609  slow_upload_texture = copy_upload_texture;
1610  else
1611  slow_upload_texture = row_upload_texture;
1612 
1613 
1614  // Set up GL state
1615 
1616  target->context->projection_matrix.size = 1;
1618 
1619  target->context->modelview_matrix.size = 1;
1621 
1622  target->context->matrix_mode = GPU_MODELVIEW;
1623 
1624  // Modes
1625  #ifndef SDL_GPU_SKIP_ENABLE_TEXTURE_2D
1626  glEnable(GL_TEXTURE_2D);
1627  #endif
1628  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1629 
1630  glDisable(GL_BLEND);
1631  glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
1632 
1633  // Viewport and Framebuffer
1634  glViewport(0.0f, 0.0f, target->viewport.w, target->viewport.h);
1635 
1636  glClear( GL_COLOR_BUFFER_BIT );
1637  #if SDL_GPU_GL_TIER < 3
1638  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1639  #endif
1640 
1641  // Set up camera
1642  applyTargetCamera(target);
1643 
1644  renderer->impl->SetLineThickness(renderer, 1.0f);
1645 
1646 
1647  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
1648  // Create vertex array container and buffer
1649  #if !defined(SDL_GPU_NO_VAO)
1650  glGenVertexArrays(1, &cdata->blit_VAO);
1651  glBindVertexArray(cdata->blit_VAO);
1652  #endif
1653  #endif
1654 
1657  target->context->current_shader_program = 0;
1658 
1659  #ifndef SDL_GPU_DISABLE_SHADERS
1660  // Load default shaders
1661 
1662  if(IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
1663  {
1664  Uint32 v, f, p;
1665  const char* textured_vertex_shader_source = GPU_DEFAULT_TEXTURED_VERTEX_SHADER_SOURCE;
1666  const char* textured_fragment_shader_source = GPU_DEFAULT_TEXTURED_FRAGMENT_SHADER_SOURCE;
1667  const char* untextured_vertex_shader_source = GPU_DEFAULT_UNTEXTURED_VERTEX_SHADER_SOURCE;
1668  const char* untextured_fragment_shader_source = GPU_DEFAULT_UNTEXTURED_FRAGMENT_SHADER_SOURCE;
1669 
1670  #ifdef SDL_GPU_ENABLE_CORE_SHADERS
1671  // Use core shaders only when supported by the actual context we got
1672  if(renderer->id.major_version > 3 || (renderer->id.major_version == 3 && renderer->id.minor_version >= 2))
1673  {
1674  textured_vertex_shader_source = GPU_DEFAULT_TEXTURED_VERTEX_SHADER_SOURCE_CORE;
1675  textured_fragment_shader_source = GPU_DEFAULT_TEXTURED_FRAGMENT_SHADER_SOURCE_CORE;
1676  untextured_vertex_shader_source = GPU_DEFAULT_UNTEXTURED_VERTEX_SHADER_SOURCE_CORE;
1677  untextured_fragment_shader_source = GPU_DEFAULT_UNTEXTURED_FRAGMENT_SHADER_SOURCE_CORE;
1678  }
1679  #endif
1680 
1681  // Textured shader
1682  v = renderer->impl->CompileShader(renderer, GPU_VERTEX_SHADER, textured_vertex_shader_source);
1683 
1684  if(!v)
1685  {
1686  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to load default textured vertex shader: %s.", GPU_GetShaderMessage());
1687  target->context->failed = GPU_TRUE;
1688  return NULL;
1689  }
1690 
1691  f = renderer->impl->CompileShader(renderer, GPU_FRAGMENT_SHADER, textured_fragment_shader_source);
1692 
1693  if(!f)
1694  {
1695  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to load default textured fragment shader: %s.", GPU_GetShaderMessage());
1696  target->context->failed = GPU_TRUE;
1697  return NULL;
1698  }
1699 
1700  p = renderer->impl->CreateShaderProgram(renderer);
1701  renderer->impl->AttachShader(renderer, p, v);
1702  renderer->impl->AttachShader(renderer, p, f);
1703  renderer->impl->LinkShaderProgram(renderer, p);
1704 
1705  if(!p)
1706  {
1707  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to link default textured shader program: %s.", GPU_GetShaderMessage());
1708  target->context->failed = GPU_TRUE;
1709  return NULL;
1710  }
1711 
1713 
1714  // Get locations of the attributes in the shader
1715  target->context->default_textured_shader_block = GPU_LoadShaderBlock(p, "gpu_Vertex", "gpu_TexCoord", "gpu_Color", "gpu_ModelViewProjectionMatrix");
1716 
1717 
1718  // Untextured shader
1719  v = renderer->impl->CompileShader(renderer, GPU_VERTEX_SHADER, untextured_vertex_shader_source);
1720 
1721  if(!v)
1722  {
1723  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to load default untextured vertex shader: %s.", GPU_GetShaderMessage());
1724  target->context->failed = GPU_TRUE;
1725  return NULL;
1726  }
1727 
1728  f = renderer->impl->CompileShader(renderer, GPU_FRAGMENT_SHADER, untextured_fragment_shader_source);
1729 
1730  if(!f)
1731  {
1732  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to load default untextured fragment shader: %s.", GPU_GetShaderMessage());
1733  target->context->failed = GPU_TRUE;
1734  return NULL;
1735  }
1736 
1737  p = renderer->impl->CreateShaderProgram(renderer);
1738  renderer->impl->AttachShader(renderer, p, v);
1739  renderer->impl->AttachShader(renderer, p, f);
1740  renderer->impl->LinkShaderProgram(renderer, p);
1741 
1742  if(!p)
1743  {
1744  GPU_PushErrorCode("GPU_CreateTargetFromWindow", GPU_ERROR_BACKEND_ERROR, "Failed to link default untextured shader program: %s.", GPU_GetShaderMessage());
1745  target->context->failed = GPU_TRUE;
1746  return NULL;
1747  }
1748 
1749  glUseProgram(p);
1750 
1752 
1753  // Get locations of the attributes in the shader
1754  target->context->default_untextured_shader_block = GPU_LoadShaderBlock(p, "gpu_Vertex", NULL, "gpu_Color", "gpu_ModelViewProjectionMatrix");
1756 
1757  }
1758  else
1759  {
1760  snprintf(shader_message, 256, "Shaders not supported by this hardware. Default shaders are disabled.\n");
1762  }
1763 
1764  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
1765  // Create vertex array container and buffer
1766 
1767  glGenBuffers(2, cdata->blit_VBO);
1768  // Create space on the GPU
1769  glBindBuffer(GL_ARRAY_BUFFER, cdata->blit_VBO[0]);
1770  glBufferData(GL_ARRAY_BUFFER, GPU_BLIT_BUFFER_STRIDE * cdata->blit_buffer_max_num_vertices, NULL, GL_STREAM_DRAW);
1771  glBindBuffer(GL_ARRAY_BUFFER, cdata->blit_VBO[1]);
1772  glBufferData(GL_ARRAY_BUFFER, GPU_BLIT_BUFFER_STRIDE * cdata->blit_buffer_max_num_vertices, NULL, GL_STREAM_DRAW);
1773  cdata->blit_VBO_flop = GPU_FALSE;
1774 
1775  glGenBuffers(1, &cdata->blit_IBO);
1776  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cdata->blit_IBO);
1777  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * cdata->blit_buffer_max_num_vertices, NULL, GL_DYNAMIC_DRAW);
1778 
1779  glGenBuffers(16, cdata->attribute_VBO);
1780 
1781  // Init 16 attributes to 0 / NULL.
1782  memset(cdata->shader_attributes, 0, 16*sizeof(GPU_AttributeSource));
1783  #endif
1784  #endif
1785 
1786  return target;
1787 }
1788 
1789 
1790 static GPU_Target* CreateAliasTarget(GPU_Renderer* renderer, GPU_Target* target)
1791 {
1792  GPU_Target* result;
1793  (void)renderer;
1794 
1795  if(target == NULL)
1796  return NULL;
1797 
1798  result = (GPU_Target*)SDL_malloc(sizeof(GPU_Target));
1799 
1800  // Copy the members
1801  *result = *target;
1802 
1803  // Alias info
1804  if(target->image != NULL)
1805  target->image->refcount++;
1806  if(target->context != NULL)
1807  target->context->refcount++;
1808  ((GPU_TARGET_DATA*)target->data)->refcount++;
1809  result->refcount = 1;
1810  result->is_alias = GPU_TRUE;
1811 
1812  return result;
1813 }
1814 
1815 static void MakeCurrent(GPU_Renderer* renderer, GPU_Target* target, Uint32 windowID)
1816 {
1817  SDL_Window* window;
1818 
1819  if(target == NULL || target->context == NULL)
1820  return;
1821 
1822  if(target->image != NULL)
1823  return;
1824 
1825 
1826  #ifdef SDL_GPU_USE_SDL2
1827  if(target->context->context != NULL)
1828  #endif
1829  {
1830  renderer->current_context_target = target;
1831  #ifdef SDL_GPU_USE_SDL2
1832  SDL_GL_MakeCurrent(SDL_GetWindowFromID(windowID), target->context->context);
1833  #endif
1834 
1835  // Reset window mapping, base size, and camera if the target's window was changed
1836  if(target->context->windowID != windowID)
1837  {
1838  renderer->impl->FlushBlitBuffer(renderer);
1839 
1840  // Update the window mappings
1841  GPU_RemoveWindowMapping(windowID);
1842  // Don't remove the target's current mapping. That lets other windows refer to it.
1843  target->context->windowID = windowID;
1844  GPU_AddWindowMapping(target);
1845 
1846  // Update target's window size
1847  window = get_window(windowID);
1848  if(window != NULL)
1849  {
1850  get_window_dimensions(window, &target->context->window_w, &target->context->window_h);
1851  get_drawable_dimensions(window, &target->context->drawable_w, &target->context->drawable_h);
1852  target->base_w = target->context->drawable_w;
1853  target->base_h = target->context->drawable_h;
1854  }
1855 
1856  // Reset the camera for this window
1857  applyTargetCamera(((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_target);
1858  }
1859  }
1860 }
1861 
1862 
1863 static void SetAsCurrent(GPU_Renderer* renderer)
1864 {
1865  if(renderer->current_context_target == NULL)
1866  return;
1867 
1868  renderer->impl->MakeCurrent(renderer, renderer->current_context_target, renderer->current_context_target->context->windowID);
1869 }
1870 
1871 static void ResetRendererState(GPU_Renderer* renderer)
1872 {
1873  GPU_Target* target;
1874  GPU_CONTEXT_DATA* cdata;
1875 
1876  if(renderer->current_context_target == NULL)
1877  return;
1878 
1879  target = renderer->current_context_target;
1880  cdata = (GPU_CONTEXT_DATA*)target->context->data;
1881 
1882 
1883  #ifndef SDL_GPU_DISABLE_SHADERS
1884  if(IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
1886  #endif
1887 
1888  #ifdef SDL_GPU_USE_SDL2
1889  SDL_GL_MakeCurrent(SDL_GetWindowFromID(target->context->windowID), target->context->context);
1890  #endif
1891 
1892 
1893  #ifndef SDL_GPU_USE_BUFFER_PIPELINE
1894  glColor4f(cdata->last_color.r/255.01f, cdata->last_color.g/255.01f, cdata->last_color.b/255.01f, GET_ALPHA(cdata->last_color)/255.01f);
1895  #endif
1896  #ifndef SDL_GPU_SKIP_ENABLE_TEXTURE_2D
1897  if(cdata->last_use_texturing)
1898  glEnable(GL_TEXTURE_2D);
1899  else
1900  glDisable(GL_TEXTURE_2D);
1901  #endif
1902 
1903  if(cdata->last_use_blending)
1904  glEnable(GL_BLEND);
1905  else
1906  glDisable(GL_BLEND);
1907 
1908  forceChangeBlendMode(renderer, cdata->last_blend_mode);
1909 
1910  forceChangeViewport(target, target->viewport);
1911 
1912  if(cdata->last_image != NULL)
1913  glBindTexture(GL_TEXTURE_2D, ((GPU_IMAGE_DATA*)(cdata->last_image)->data)->handle);
1914 
1915  if(cdata->last_target != NULL)
1916  extBindFramebuffer(renderer, ((GPU_TARGET_DATA*)cdata->last_target->data)->handle);
1917  else
1918  extBindFramebuffer(renderer, ((GPU_TARGET_DATA*)target->data)->handle);
1919 }
1920 
1921 static GPU_bool SetWindowResolution(GPU_Renderer* renderer, Uint16 w, Uint16 h)
1922 {
1923  GPU_Target* target = renderer->current_context_target;
1924 
1925  GPU_bool isCurrent = isCurrentTarget(renderer, target);
1926  if(isCurrent)
1927  renderer->impl->FlushBlitBuffer(renderer);
1928 
1929  // Don't need to resize (only update internals) when resolution isn't changing.
1930  get_target_window_dimensions(target, &target->context->window_w, &target->context->window_h);
1931  get_target_drawable_dimensions(target, &target->context->drawable_w, &target->context->drawable_h);
1932  if(target->context->window_w != w || target->context->window_h != h)
1933  {
1934  resize_window(target, w, h);
1935  get_target_window_dimensions(target, &target->context->window_w, &target->context->window_h);
1936  get_target_drawable_dimensions(target, &target->context->drawable_w, &target->context->drawable_h);
1937  }
1938 
1939 #ifdef SDL_GPU_USE_SDL1
1940 
1941  // FIXME: Does the entire GL state need to be reset because the screen was recreated?
1942  {
1943  GPU_Context* context;
1944 
1945  // Reset texturing state
1946  context = renderer->current_context_target->context;
1947  context->use_texturing = GPU_TRUE;
1948  ((GPU_CONTEXT_DATA*)context->data)->last_use_texturing = GPU_FALSE;
1949  }
1950 
1951  // Clear target (no state change)
1952  glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
1953  glClear( GL_COLOR_BUFFER_BIT );
1954 #endif
1955 
1956  // Store the resolution for fullscreen_desktop changes
1957  update_stored_dimensions(target);
1958 
1959  // Update base dimensions
1960  target->base_w = target->context->drawable_w;
1961  target->base_h = target->context->drawable_h;
1962 
1963  // Resets virtual resolution
1964  target->w = target->base_w;
1965  target->h = target->base_h;
1967 
1968  // Resets viewport
1969  target->viewport = GPU_MakeRect(0, 0, target->w, target->h);
1970  changeViewport(target);
1971 
1972  GPU_UnsetClip(target);
1973 
1974  if(isCurrent)
1975  applyTargetCamera(target);
1976 
1977  return 1;
1978 }
1979 
1980 static void SetVirtualResolution(GPU_Renderer* renderer, GPU_Target* target, Uint16 w, Uint16 h)
1981 {
1982  GPU_bool isCurrent;
1983 
1984  if(target == NULL)
1985  return;
1986 
1987  isCurrent = isCurrentTarget(renderer, target);
1988  if(isCurrent)
1989  renderer->impl->FlushBlitBuffer(renderer);
1990 
1991  target->w = w;
1992  target->h = h;
1994 
1995  if(isCurrent)
1996  applyTargetCamera(target);
1997 }
1998 
1999 static void UnsetVirtualResolution(GPU_Renderer* renderer, GPU_Target* target)
2000 {
2001  GPU_bool isCurrent;
2002 
2003  if(target == NULL)
2004  return;
2005 
2006  isCurrent = isCurrentTarget(renderer, target);
2007  if(isCurrent)
2008  renderer->impl->FlushBlitBuffer(renderer);
2009 
2010  target->w = target->base_w;
2011  target->h = target->base_h;
2012 
2014 
2015  if(isCurrent)
2016  applyTargetCamera(target);
2017 }
2018 
2019 static void Quit(GPU_Renderer* renderer)
2020 {
2021  renderer->impl->FreeTarget(renderer, renderer->current_context_target);
2022  renderer->current_context_target = NULL;
2023 }
2024 
2025 
2026 
2027 static GPU_bool SetFullscreen(GPU_Renderer* renderer, GPU_bool enable_fullscreen, GPU_bool use_desktop_resolution)
2028 {
2029  GPU_Target* target = renderer->current_context_target;
2030 
2031 #ifdef SDL_GPU_USE_SDL2
2032  SDL_Window* window = SDL_GetWindowFromID(target->context->windowID);
2033  Uint32 old_flags = SDL_GetWindowFlags(window);
2034  GPU_bool was_fullscreen = (old_flags & SDL_WINDOW_FULLSCREEN);
2035  GPU_bool is_fullscreen = was_fullscreen;
2036 
2037  Uint32 flags = 0;
2038 
2039  if(enable_fullscreen)
2040  {
2041  if(use_desktop_resolution)
2042  flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
2043  else
2044  flags = SDL_WINDOW_FULLSCREEN;
2045  }
2046 
2047  if(SDL_SetWindowFullscreen(window, flags) >= 0)
2048  {
2049  flags = SDL_GetWindowFlags(window);
2050  is_fullscreen = (flags & SDL_WINDOW_FULLSCREEN);
2051 
2052  // If we just went fullscreen, save the original resolution
2053  // We do this because you can't depend on the resolution to be preserved by SDL
2054  // SDL_WINDOW_FULLSCREEN_DESKTOP changes the resolution and SDL_WINDOW_FULLSCREEN can change it when a given mode is not available
2055  if(!was_fullscreen && is_fullscreen)
2056  {
2057  target->context->stored_window_w = target->context->window_w;
2058  target->context->stored_window_h = target->context->window_h;
2059  }
2060 
2061  // If we're in windowed mode now and a resolution was stored, restore the original window resolution
2062  if(was_fullscreen && !is_fullscreen && (target->context->stored_window_w != 0 && target->context->stored_window_h != 0))
2063  SDL_SetWindowSize(window, target->context->stored_window_w, target->context->stored_window_h);
2064  }
2065 
2066 #else
2067  SDL_Surface* surf = SDL_GetVideoSurface();
2068  GPU_bool was_fullscreen = (surf->flags & SDL_FULLSCREEN);
2069  GPU_bool is_fullscreen = was_fullscreen;
2070 
2071  if(was_fullscreen ^ enable_fullscreen)
2072  {
2073  SDL_WM_ToggleFullScreen(surf);
2074  is_fullscreen = (surf->flags & SDL_FULLSCREEN);
2075  }
2076 
2077 #endif
2078 
2079  if(is_fullscreen != was_fullscreen)
2080  {
2081  // Update window dims
2082  get_target_window_dimensions(target, &target->context->window_w, &target->context->window_h);
2083  get_target_drawable_dimensions(target, &target->context->drawable_w, &target->context->drawable_h);
2084 
2085  // If virtual res is not set, we need to update the target dims and reset stuff that no longer is right
2086  if(!target->using_virtual_resolution)
2087  {
2088  // Update dims
2089  target->w = target->context->drawable_w;
2090  target->h = target->context->drawable_h;
2091  }
2092 
2093  // Reset viewport
2094  target->viewport = GPU_MakeRect(0, 0, target->context->drawable_w, target->context->drawable_h);
2095  changeViewport(target);
2096 
2097  // Reset clip
2098  GPU_UnsetClip(target);
2099 
2100  // Update camera
2101  if(isCurrentTarget(renderer, target))
2102  applyTargetCamera(target);
2103  }
2104 
2105  target->base_w = target->context->drawable_w;
2106  target->base_h = target->context->drawable_h;
2107 
2108  return is_fullscreen;
2109 }
2110 
2111 
2112 static GPU_Camera SetCamera(GPU_Renderer* renderer, GPU_Target* target, GPU_Camera* cam)
2113 {
2114  GPU_Camera new_camera;
2115  GPU_Camera old_camera;
2116 
2117  if(target == NULL)
2118  {
2119  GPU_PushErrorCode("GPU_SetCamera", GPU_ERROR_NULL_ARGUMENT, "target");
2120  return GPU_GetDefaultCamera();
2121  }
2122 
2123  if(cam == NULL)
2124  new_camera = GPU_GetDefaultCamera();
2125  else
2126  new_camera = *cam;
2127 
2128  old_camera = target->camera;
2129 
2130  if(!equal_cameras(new_camera, old_camera))
2131  {
2132  if(isCurrentTarget(renderer, target))
2133  renderer->impl->FlushBlitBuffer(renderer);
2134 
2135  target->camera = new_camera;
2136  }
2137 
2138  return old_camera;
2139 }
2140 
2141 static GLuint CreateUninitializedTexture(GPU_Renderer* renderer)
2142 {
2143  GLuint handle;
2144 
2145  glGenTextures(1, &handle);
2146  if(handle == 0)
2147  return 0;
2148 
2149  flushAndBindTexture(renderer, handle);
2150 
2151  // Set the texture's stretching properties
2152  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2153  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2154  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2155  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2156  #if defined(SDL_GPU_USE_GLES) && (SDL_GPU_GLES_TIER == 1)
2157  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2158 
2159  glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
2160  #endif
2161 
2162  return handle;
2163 }
2164 
2165 static GPU_Image* CreateUninitializedImage(GPU_Renderer* renderer, Uint16 w, Uint16 h, GPU_FormatEnum format)
2166 {
2167  GLuint handle, num_layers, bytes_per_pixel;
2168  GLenum gl_format;
2169  GPU_Image* result;
2170  GPU_IMAGE_DATA* data;
2171  SDL_Color white = { 255, 255, 255, 255 };
2172 
2173  switch(format)
2174  {
2175  case GPU_FORMAT_LUMINANCE:
2176  gl_format = GL_LUMINANCE;
2177  num_layers = 1;
2178  bytes_per_pixel = 1;
2179  break;
2181  gl_format = GL_LUMINANCE_ALPHA;
2182  num_layers = 1;
2183  bytes_per_pixel = 2;
2184  break;
2185  case GPU_FORMAT_RGB:
2186  gl_format = GL_RGB;
2187  num_layers = 1;
2188  bytes_per_pixel = 3;
2189  break;
2190  case GPU_FORMAT_RGBA:
2191  gl_format = GL_RGBA;
2192  num_layers = 1;
2193  bytes_per_pixel = 4;
2194  break;
2195  #ifdef GL_BGR
2196  case GPU_FORMAT_BGR:
2197  gl_format = GL_BGR;
2198  num_layers = 1;
2199  bytes_per_pixel = 3;
2200  break;
2201  #endif
2202  #ifdef GL_BGRA
2203  case GPU_FORMAT_BGRA:
2204  gl_format = GL_BGRA;
2205  num_layers = 1;
2206  bytes_per_pixel = 4;
2207  break;
2208  #endif
2209  #ifdef GL_ABGR
2210  case GPU_FORMAT_ABGR:
2211  gl_format = GL_ABGR;
2212  num_layers = 1;
2213  bytes_per_pixel = 4;
2214  break;
2215  #endif
2216  case GPU_FORMAT_ALPHA:
2217  gl_format = GL_ALPHA;
2218  num_layers = 1;
2219  bytes_per_pixel = 1;
2220  break;
2221  #ifndef SDL_GPU_USE_GLES
2222  case GPU_FORMAT_RG:
2223  gl_format = GL_RG;
2224  num_layers = 1;
2225  bytes_per_pixel = 2;
2226  break;
2227  #endif
2228  case GPU_FORMAT_YCbCr420P:
2229  gl_format = GL_LUMINANCE;
2230  num_layers = 3;
2231  bytes_per_pixel = 1;
2232  break;
2233  case GPU_FORMAT_YCbCr422:
2234  gl_format = GL_LUMINANCE;
2235  num_layers = 3;
2236  bytes_per_pixel = 1;
2237  break;
2238  default:
2239  GPU_PushErrorCode("GPU_CreateUninitializedImage", GPU_ERROR_DATA_ERROR, "Unsupported image format (0x%x)", format);
2240  return NULL;
2241  }
2242 
2243  if(bytes_per_pixel < 1 || bytes_per_pixel > 4)
2244  {
2245  GPU_PushErrorCode("GPU_CreateUninitializedImage", GPU_ERROR_DATA_ERROR, "Unsupported number of bytes per pixel (%d)", bytes_per_pixel);
2246  return NULL;
2247  }
2248 
2249  // Create the underlying texture
2250  handle = CreateUninitializedTexture(renderer);
2251  if(handle == 0)
2252  {
2253  GPU_PushErrorCode("GPU_CreateUninitializedImage", GPU_ERROR_BACKEND_ERROR, "Failed to generate a texture handle.");
2254  return NULL;
2255  }
2256 
2257  // Create the GPU_Image
2258  result = (GPU_Image*)SDL_malloc(sizeof(GPU_Image));
2259  result->refcount = 1;
2260  data = (GPU_IMAGE_DATA*)SDL_malloc(sizeof(GPU_IMAGE_DATA));
2261  data->refcount = 1;
2262  result->target = NULL;
2263  result->renderer = renderer;
2264  result->context_target = renderer->current_context_target;
2265  result->format = format;
2266  result->num_layers = num_layers;
2267  result->bytes_per_pixel = bytes_per_pixel;
2268  result->has_mipmaps = GPU_FALSE;
2269 
2270  result->anchor_x = renderer->default_image_anchor_x;
2271  result->anchor_y = renderer->default_image_anchor_y;
2272 
2273  result->color = white;
2274  result->use_blending = GPU_TRUE;
2276  result->filter_mode = GPU_FILTER_LINEAR;
2278  result->wrap_mode_x = GPU_WRAP_NONE;
2279  result->wrap_mode_y = GPU_WRAP_NONE;
2280 
2281  result->data = data;
2282  result->is_alias = GPU_FALSE;
2283  data->handle = handle;
2284  data->owns_handle = GPU_TRUE;
2285  data->format = gl_format;
2286 
2288  result->w = w;
2289  result->h = h;
2290  result->base_w = w;
2291  result->base_h = h;
2292  // POT textures will change this later
2293  result->texture_w = w;
2294  result->texture_h = h;
2295 
2296  return result;
2297 }
2298 
2299 
2300 static GPU_Image* CreateImage(GPU_Renderer* renderer, Uint16 w, Uint16 h, GPU_FormatEnum format)
2301 {
2302  GPU_Image* result;
2303  GLenum internal_format;
2304  static unsigned char* zero_buffer = NULL;
2305  static unsigned int zero_buffer_size = 0;
2306 
2307  if(format < 1)
2308  {
2309  GPU_PushErrorCode("GPU_CreateImage", GPU_ERROR_DATA_ERROR, "Unsupported image format (0x%x)", format);
2310  return NULL;
2311  }
2312 
2313  result = CreateUninitializedImage(renderer, w, h, format);
2314 
2315  if(result == NULL)
2316  {
2317  GPU_PushErrorCode("GPU_CreateImage", GPU_ERROR_BACKEND_ERROR, "Could not create image as requested.");
2318  return NULL;
2319  }
2320 
2321  changeTexturing(renderer, GPU_TRUE);
2322  bindTexture(renderer, result);
2323 
2324  internal_format = ((GPU_IMAGE_DATA*)(result->data))->format;
2325  w = result->w;
2326  h = result->h;
2327  if(!(renderer->enabled_features & GPU_FEATURE_NON_POWER_OF_TWO))
2328  {
2329  if(!isPowerOfTwo(w))
2330  w = getNearestPowerOf2(w);
2331  if(!isPowerOfTwo(h))
2332  h = getNearestPowerOf2(h);
2333  }
2334 
2335  // Initialize texture using a blank buffer
2336  if(zero_buffer_size < (unsigned int)(w*h*result->bytes_per_pixel))
2337  {
2338  SDL_free(zero_buffer);
2339  zero_buffer_size = w*h*result->bytes_per_pixel;
2340  zero_buffer = (unsigned char*)SDL_malloc(zero_buffer_size);
2341  memset(zero_buffer, 0, zero_buffer_size);
2342  }
2343 
2344 
2345  upload_new_texture(zero_buffer, GPU_MakeRect(0, 0, w, h), internal_format, 1, w, result->bytes_per_pixel);
2346 
2347 
2348  // Tell SDL_gpu what we got (power-of-two requirements have made this change)
2349  result->texture_w = w;
2350  result->texture_h = h;
2351 
2352 
2353  return result;
2354 }
2355 
2356 
2357 static GPU_Image* CreateImageUsingTexture(GPU_Renderer* renderer, Uint32 handle, GPU_bool take_ownership)
2358 {
2359  #ifdef SDL_GPU_DISABLE_TEXTURE_GETS
2360  GPU_PushErrorCode("GPU_CreateImageUsingTexture", GPU_ERROR_UNSUPPORTED_FUNCTION, "Renderer %s does not support this function", renderer->id.name);
2361  return NULL;
2362  #else
2363 
2364  GLint w, h;
2365  GLuint num_layers, bytes_per_pixel;
2366  GLint gl_format;
2367  GLint wrap_s, wrap_t;
2368  GLint min_filter;
2369 
2370  GPU_FormatEnum format;
2371  GPU_WrapEnum wrap_x, wrap_y;
2372  GPU_FilterEnum filter_mode;
2373  SDL_Color white = { 255, 255, 255, 255 };
2374 
2375  GPU_Image* result;
2376  GPU_IMAGE_DATA* data;
2377 
2378  #ifdef SDL_GPU_USE_GLES
2379  if(renderer->id.major_version == 3 && renderer->id.minor_version == 0)
2380  {
2381  GPU_PushErrorCode("GPU_CreateImageUsingTexture", GPU_ERROR_UNSUPPORTED_FUNCTION, "Renderer %s's runtime version on this device (3.0) does not support this function", renderer->id.name);
2382  return NULL;
2383  }
2384  #endif
2385 
2386  flushAndBindTexture(renderer, handle);
2387 
2388  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &gl_format);
2389 
2390  switch(gl_format)
2391  {
2392  case GL_LUMINANCE:
2393  format = GPU_FORMAT_LUMINANCE;
2394  num_layers = 1;
2395  bytes_per_pixel = 1;
2396  break;
2397  case GL_LUMINANCE_ALPHA:
2398  format = GPU_FORMAT_LUMINANCE_ALPHA;
2399  num_layers = 1;
2400  bytes_per_pixel = 2;
2401  break;
2402  case GL_RGB:
2403  format = GPU_FORMAT_RGB;
2404  num_layers = 1;
2405  bytes_per_pixel = 3;
2406  break;
2407  case GL_RGBA:
2408  format = GPU_FORMAT_RGBA;
2409  num_layers = 1;
2410  bytes_per_pixel = 4;
2411  break;
2412  #ifdef GL_BGR
2413  case GL_BGR:
2414  format = GPU_FORMAT_BGR;
2415  num_layers = 1;
2416  bytes_per_pixel = 3;
2417  break;
2418  #endif
2419  #ifdef GL_BGRA
2420  case GL_BGRA:
2421  format = GPU_FORMAT_BGRA;
2422  num_layers = 1;
2423  bytes_per_pixel = 4;
2424  break;
2425  #endif
2426  #ifdef GL_ABGR
2427  case GL_ABGR:
2428  format = GPU_FORMAT_ABGR;
2429  num_layers = 1;
2430  bytes_per_pixel = 4;
2431  break;
2432  #endif
2433  case GL_ALPHA:
2434  format = GPU_FORMAT_ALPHA;
2435  num_layers = 1;
2436  bytes_per_pixel = 1;
2437  break;
2438  #ifndef SDL_GPU_USE_GLES
2439  case GL_RG:
2440  format = GPU_FORMAT_RG;
2441  num_layers = 1;
2442  bytes_per_pixel = 2;
2443  break;
2444  #endif
2445  default:
2446  GPU_PushErrorCode("GPU_CreateImageUsingTexture", GPU_ERROR_DATA_ERROR, "Unsupported GL image format (0x%x)", gl_format);
2447  return NULL;
2448  }
2449 
2450  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
2451  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
2452 
2453 
2454  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &min_filter);
2455  // Ignore mag filter... Maybe the wrong thing to do?
2456 
2457  // Let the user use one that we don't support and pretend that we're okay with that.
2458  switch(min_filter)
2459  {
2460  case GL_NEAREST:
2461  filter_mode = GPU_FILTER_NEAREST;
2462  break;
2463  case GL_LINEAR:
2464  case GL_LINEAR_MIPMAP_NEAREST:
2465  filter_mode = GPU_FILTER_LINEAR;
2466  break;
2467  case GL_LINEAR_MIPMAP_LINEAR:
2468  filter_mode = GPU_FILTER_LINEAR_MIPMAP;
2469  break;
2470  default:
2471  GPU_PushErrorCode("GPU_CreateImageUsingTexture", GPU_ERROR_USER_ERROR, "Unsupported value for GL_TEXTURE_MIN_FILTER (0x%x)", min_filter);
2472  filter_mode = GPU_FILTER_LINEAR;
2473  break;
2474  }
2475 
2476 
2477  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &wrap_s);
2478  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, &wrap_t);
2479 
2480  // Let the user use one that we don't support and pretend that we're okay with that.
2481  switch(wrap_s)
2482  {
2483  case GL_CLAMP_TO_EDGE:
2484  wrap_x = GPU_WRAP_NONE;
2485  break;
2486  case GL_REPEAT:
2487  wrap_x = GPU_WRAP_REPEAT;
2488  break;
2489  case GL_MIRRORED_REPEAT:
2490  wrap_x = GPU_WRAP_MIRRORED;
2491  break;
2492  default:
2493  GPU_PushErrorCode("GPU_CreateImageUsingTexture", GPU_ERROR_USER_ERROR, "Unsupported value for GL_TEXTURE_WRAP_S (0x%x)", wrap_s);
2494  wrap_x = GPU_WRAP_NONE;
2495  break;
2496  }
2497 
2498  switch(wrap_t)
2499  {
2500  case GL_CLAMP_TO_EDGE:
2501  wrap_y = GPU_WRAP_NONE;
2502  break;
2503  case GL_REPEAT:
2504  wrap_y = GPU_WRAP_REPEAT;
2505  break;
2506  case GL_MIRRORED_REPEAT:
2507  wrap_y = GPU_WRAP_MIRRORED;
2508  break;
2509  default:
2510  GPU_PushErrorCode("GPU_CreateImageUsingTexture", GPU_ERROR_USER_ERROR, "Unsupported value for GL_TEXTURE_WRAP_T (0x%x)", wrap_t);
2511  wrap_y = GPU_WRAP_NONE;
2512  break;
2513  }
2514 
2515  // Finally create the image
2516 
2517  data = (GPU_IMAGE_DATA*)SDL_malloc(sizeof(GPU_IMAGE_DATA));
2518  data->refcount = 1;
2519  data->handle = handle;
2520  data->owns_handle = take_ownership;
2521  data->format = gl_format;
2522 
2523 
2524  result = (GPU_Image*)SDL_malloc(sizeof(GPU_Image));
2525  result->refcount = 1;
2526  result->target = NULL;
2527  result->renderer = renderer;
2528  result->context_target = renderer->current_context_target;
2529  result->format = format;
2530  result->num_layers = num_layers;
2531  result->bytes_per_pixel = bytes_per_pixel;
2532  result->has_mipmaps = GPU_FALSE;
2533 
2534  result->anchor_x = renderer->default_image_anchor_x;
2535  result->anchor_y = renderer->default_image_anchor_y;
2536 
2537  result->color = white;
2538  result->use_blending = GPU_TRUE;
2541  result->filter_mode = filter_mode;
2542  result->wrap_mode_x = wrap_x;
2543  result->wrap_mode_y = wrap_y;
2544 
2545  result->data = data;
2546  result->is_alias = GPU_FALSE;
2547 
2549  result->w = w;
2550  result->h = h;
2551 
2552  result->base_w = w;
2553  result->base_h = h;
2554  result->texture_w = w;
2555  result->texture_h = h;
2556 
2557  return result;
2558  #endif
2559 }
2560 
2561 
2562 static GPU_Image* CreateAliasImage(GPU_Renderer* renderer, GPU_Image* image)
2563 {
2564  GPU_Image* result;
2565  (void)renderer;
2566 
2567  if(image == NULL)
2568  return NULL;
2569 
2570  result = (GPU_Image*)SDL_malloc(sizeof(GPU_Image));
2571  // Copy the members
2572  *result = *image;
2573 
2574  // Alias info
2575  ((GPU_IMAGE_DATA*)image->data)->refcount++;
2576  result->refcount = 1;
2577  result->is_alias = GPU_TRUE;
2578 
2579  return result;
2580 }
2581 
2582 
2583 static GPU_bool readTargetPixels(GPU_Renderer* renderer, GPU_Target* source, GLint format, GLubyte* pixels)
2584 {
2585  if(source == NULL)
2586  return GPU_FALSE;
2587 
2588  if(isCurrentTarget(renderer, source))
2589  renderer->impl->FlushBlitBuffer(renderer);
2590 
2591  if(bindFramebuffer(renderer, source))
2592  {
2593  glReadPixels(0, 0, source->base_w, source->base_h, format, GL_UNSIGNED_BYTE, pixels);
2594  return GPU_TRUE;
2595  }
2596  return GPU_FALSE;
2597 }
2598 
2599 static GPU_bool readImagePixels(GPU_Renderer* renderer, GPU_Image* source, GLint format, GLubyte* pixels)
2600 {
2601 #ifdef SDL_GPU_USE_GLES
2602  GPU_bool created_target;
2603  GPU_bool result;
2604 #endif
2605 
2606  if(source == NULL)
2607  return GPU_FALSE;
2608 
2609  // No glGetTexImage() in OpenGLES
2610  #ifdef SDL_GPU_USE_GLES
2611  // Load up the target
2612  created_target = GPU_FALSE;
2613  if(source->target == NULL)
2614  {
2615  renderer->impl->GetTarget(renderer, source);
2616  created_target = GPU_TRUE;
2617  }
2618  // Get the data
2619  // FIXME: This may use different dimensions than the OpenGL code... (base_w vs texture_w)
2620  // FIXME: I should force it to use the texture dims.
2621  result = readTargetPixels(renderer, source->target, format, pixels);
2622  // Free the target
2623  if(created_target)
2624  renderer->impl->FreeTarget(renderer, source->target);
2625  return result;
2626  #else
2627  // Bind the texture temporarily
2628  glBindTexture(GL_TEXTURE_2D, ((GPU_IMAGE_DATA*)source->data)->handle);
2629  // Get the data
2630  glGetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, pixels);
2631  // Rebind the last texture
2632  if(((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_image != NULL)
2633  glBindTexture(GL_TEXTURE_2D, ((GPU_IMAGE_DATA*)(((GPU_CONTEXT_DATA*)renderer->current_context_target->context->data)->last_image)->data)->handle);
2634  return GPU_TRUE;
2635  #endif
2636 }
2637 
2638 static unsigned char* getRawTargetData(GPU_Renderer* renderer, GPU_Target* target)
2639 {
2640  int bytes_per_pixel;
2641  unsigned char* data;
2642  int pitch;
2643  unsigned char* copy;
2644  int y;
2645 
2646  if(isCurrentTarget(renderer, target))
2647  renderer->impl->FlushBlitBuffer(renderer);
2648 
2649  bytes_per_pixel = 4;
2650  if(target->image != NULL)
2651  bytes_per_pixel = target->image->bytes_per_pixel;
2652  data = (unsigned char*)SDL_malloc(target->base_w * target->base_h * bytes_per_pixel);
2653 
2654  // This can take regions of pixels, so using base_w and base_h with an image target should be fine.
2655  if(!readTargetPixels(renderer, target, ((GPU_TARGET_DATA*)target->data)->format, data))
2656  {
2657  SDL_free(data);
2658  return NULL;
2659  }
2660 
2661  // Flip the data vertically (OpenGL framebuffer is read upside down)
2662  pitch = target->base_w * bytes_per_pixel;
2663  copy = (unsigned char*)SDL_malloc(pitch);
2664 
2665  for(y = 0; y < target->base_h/2; y++)
2666  {
2667  unsigned char* top = &data[target->base_w * y * bytes_per_pixel];
2668  unsigned char* bottom = &data[target->base_w * (target->base_h - y - 1) * bytes_per_pixel];
2669  memcpy(copy, top, pitch);
2670  memcpy(top, bottom, pitch);
2671  memcpy(bottom, copy, pitch);
2672  }
2673  SDL_free(copy);
2674 
2675  return data;
2676 }
2677 
2678 static unsigned char* getRawImageData(GPU_Renderer* renderer, GPU_Image* image)
2679 {
2680  unsigned char* data;
2681 
2682  if(image->target != NULL && isCurrentTarget(renderer, image->target))
2683  renderer->impl->FlushBlitBuffer(renderer);
2684 
2685  data = (unsigned char*)SDL_malloc(image->texture_w * image->texture_h * image->bytes_per_pixel);
2686 
2687  // FIXME: Sometimes the texture is stored and read in RGBA even when I specify RGB. getRawImageData() might need to return the stored format or Bpp.
2688  if(!readImagePixels(renderer, image, ((GPU_IMAGE_DATA*)image->data)->format, data))
2689  {
2690  SDL_free(data);
2691  return NULL;
2692  }
2693 
2694  return data;
2695 }
2696 
2697 static GPU_bool SaveImage(GPU_Renderer* renderer, GPU_Image* image, const char* filename, GPU_FileFormatEnum format)
2698 {
2699  GPU_bool result;
2700  SDL_Surface* surface;
2701 
2702  if(image == NULL || filename == NULL ||
2703  image->texture_w < 1 || image->texture_h < 1 || image->bytes_per_pixel < 1 || image->bytes_per_pixel > 4)
2704  {
2705  return GPU_FALSE;
2706  }
2707 
2708  surface = renderer->impl->CopySurfaceFromImage(renderer, image);
2709 
2710  if(surface == NULL)
2711  return GPU_FALSE;
2712 
2713  result = GPU_SaveSurface(surface, filename, format);
2714 
2715  SDL_FreeSurface(surface);
2716  return result;
2717 }
2718 
2719 static SDL_Surface* CopySurfaceFromTarget(GPU_Renderer* renderer, GPU_Target* target)
2720 {
2721  unsigned char* data;
2722  SDL_Surface* result;
2723  SDL_PixelFormat* format;
2724 
2725  if(target == NULL)
2726  {
2727  GPU_PushErrorCode("GPU_CopySurfaceFromTarget", GPU_ERROR_NULL_ARGUMENT, "target");
2728  return NULL;
2729  }
2730  if(target->base_w < 1 || target->base_h < 1)
2731  {
2732  GPU_PushErrorCode("GPU_CopySurfaceFromTarget", GPU_ERROR_DATA_ERROR, "Invalid target dimensions (%dx%d)", target->base_w, target->base_h);
2733  return NULL;
2734  }
2735 
2736  data = getRawTargetData(renderer, target);
2737 
2738  if(data == NULL)
2739  {
2740  GPU_PushErrorCode("GPU_CopySurfaceFromTarget", GPU_ERROR_BACKEND_ERROR, "Could not retrieve target data.");
2741  return NULL;
2742  }
2743 
2744  format = AllocFormat(((GPU_TARGET_DATA*)target->data)->format);
2745 
2746  result = SDL_CreateRGBSurface(SDL_SWSURFACE, target->base_w, target->base_h, format->BitsPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask);
2747 
2748  if(result == NULL)
2749  {
2750  GPU_PushErrorCode("GPU_CopySurfaceFromTarget", GPU_ERROR_DATA_ERROR, "Failed to create new %dx%d surface", target->base_w, target->base_h);
2751  SDL_free(data);
2752  return NULL;
2753  }
2754 
2755  // Copy row-by-row in case the pitch doesn't match
2756  {
2757  int i;
2758  int source_pitch = target->base_w*format->BytesPerPixel;
2759  for(i = 0; i < target->base_h; ++i)
2760  {
2761  memcpy((Uint8*)result->pixels + i*result->pitch, data + source_pitch*i, source_pitch);
2762  }
2763  }
2764 
2765  SDL_free(data);
2766 
2767  FreeFormat(format);
2768  return result;
2769 }
2770 
2771 static SDL_Surface* CopySurfaceFromImage(GPU_Renderer* renderer, GPU_Image* image)
2772 {
2773  unsigned char* data;
2774  SDL_Surface* result;
2775  SDL_PixelFormat* format;
2776  int w, h;
2777 
2778  if(image == NULL)
2779  {
2780  GPU_PushErrorCode("GPU_CopySurfaceFromImage", GPU_ERROR_NULL_ARGUMENT, "image");
2781  return NULL;
2782  }
2783  if(image->w < 1 || image->h < 1)
2784  {
2785  GPU_PushErrorCode("GPU_CopySurfaceFromImage", GPU_ERROR_DATA_ERROR, "Invalid image dimensions (%dx%d)", image->base_w, image->base_h);
2786  return NULL;
2787  }
2788 
2789  // FIXME: Virtual resolutions overwrite the NPOT dimensions when NPOT textures are not supported!
2790  if(image->using_virtual_resolution)
2791  {
2792  w = image->texture_w;
2793  h = image->texture_h;
2794  }
2795  else
2796  {
2797  w = image->w;
2798  h = image->h;
2799  }
2800  data = getRawImageData(renderer, image);
2801 
2802  if(data == NULL)
2803  {
2804  GPU_PushErrorCode("GPU_CopySurfaceFromImage", GPU_ERROR_BACKEND_ERROR, "Could not retrieve target data.");
2805  return NULL;
2806  }
2807 
2808  format = AllocFormat(((GPU_IMAGE_DATA*)image->data)->format);
2809 
2810  result = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, format->BitsPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask);
2811 
2812  if(result == NULL)
2813  {
2814  GPU_PushErrorCode("GPU_CopySurfaceFromImage", GPU_ERROR_DATA_ERROR, "Failed to create new %dx%d surface", w, h);
2815  SDL_free(data);
2816  return NULL;
2817  }
2818 
2819  // Copy row-by-row in case the pitch doesn't match
2820  {
2821  int i;
2822  int source_pitch = image->texture_w*format->BytesPerPixel; // Use the actual texture width to pull from the data
2823  for(i = 0; i < h; ++i)
2824  {
2825  memcpy((Uint8*)result->pixels + i*result->pitch, data + source_pitch*i, result->pitch);
2826  }
2827  }
2828 
2829  SDL_free(data);
2830 
2831  FreeFormat(format);
2832  return result;
2833 }
2834 
2835 
2836 
2837 
2838 
2839 
2840 
2841 
2842 
2843 
2844 
2845 
2846 
2847 
2848 
2849 // Returns 0 if a direct conversion (asking OpenGL to do it) is safe. Returns 1 if a copy is needed. Returns -1 on error.
2850 // The surfaceFormatResult is used to specify what direct conversion format the surface pixels are in (source format).
2851 #ifdef SDL_GPU_USE_GLES
2852 // OpenGLES does not do direct conversion. Internal format (glFormat) and original format (surfaceFormatResult) must be the same.
2853 static int compareFormats(GPU_Renderer* renderer, GLenum glFormat, SDL_Surface* surface, GLenum* surfaceFormatResult)
2854 {
2855  SDL_PixelFormat* format = surface->format;
2856  switch(glFormat)
2857  {
2858  // 3-channel formats
2859  case GL_RGB:
2860  if(format->BytesPerPixel != 3)
2861  return 1;
2862 
2863  if(format->Rmask == 0x0000FF && format->Gmask == 0x00FF00 && format->Bmask == 0xFF0000)
2864  {
2865  if(surfaceFormatResult != NULL)
2866  *surfaceFormatResult = GL_RGB;
2867  return 0;
2868  }
2869 #ifdef GL_BGR
2870  if(format->Rmask == 0xFF0000 && format->Gmask == 0x00FF00 && format->Bmask == 0x0000FF)
2871  {
2872  if(renderer->enabled_features & GPU_FEATURE_GL_BGR)
2873  {
2874  if(surfaceFormatResult != NULL)
2875  *surfaceFormatResult = GL_BGR;
2876  return 0;
2877  }
2878  }
2879 #endif
2880  return 1;
2881  // 4-channel formats
2882  case GL_RGBA:
2883  if(format->BytesPerPixel != 4)
2884  return 1;
2885 
2886  if (format->Rmask == 0x000000FF && format->Gmask == 0x0000FF00 && format->Bmask == 0x00FF0000)
2887  {
2888  if(surfaceFormatResult != NULL)
2889  *surfaceFormatResult = GL_RGBA;
2890  return 0;
2891  }
2892 #ifdef GL_BGRA
2893  if (format->Rmask == 0x00FF0000 && format->Gmask == 0x0000FF00 && format->Bmask == 0x000000FF)
2894  {
2895  if(renderer->enabled_features & GPU_FEATURE_GL_BGRA)
2896  {
2897  if(surfaceFormatResult != NULL)
2898  *surfaceFormatResult = GL_BGRA;
2899  return 0;
2900  }
2901  }
2902 #endif
2903 #ifdef GL_ABGR
2904  if (format->Rmask == 0xFF000000 && format->Gmask == 0x00FF0000 && format->Bmask == 0x0000FF00)
2905  {
2906  if(renderer->enabled_features & GPU_FEATURE_GL_ABGR)
2907  {
2908  if(surfaceFormatResult != NULL)
2909  *surfaceFormatResult = GL_ABGR;
2910  return 0;
2911  }
2912  }
2913 #endif
2914  return 1;
2915  default:
2916  GPU_PushErrorCode("GPU_CompareFormats", GPU_ERROR_DATA_ERROR, "Invalid texture format (0x%x)", glFormat);
2917  return -1;
2918  }
2919 }
2920 #else
2921 //GL_RGB/GL_RGBA and Surface format
2922 static int compareFormats(GPU_Renderer* renderer, GLenum glFormat, SDL_Surface* surface, GLenum* surfaceFormatResult)
2923 {
2924  SDL_PixelFormat* format = surface->format;
2925  switch(glFormat)
2926  {
2927  // 3-channel formats
2928  case GL_RGB:
2929  if(format->BytesPerPixel != 3)
2930  return 1;
2931 
2932  // Looks like RGB? Easy!
2933  if(format->Rmask == 0x0000FF && format->Gmask == 0x00FF00 && format->Bmask == 0xFF0000)
2934  {
2935  if(surfaceFormatResult != NULL)
2936  *surfaceFormatResult = GL_RGB;
2937  return 0;
2938  }
2939  // Looks like BGR?
2940  if(format->Rmask == 0xFF0000 && format->Gmask == 0x00FF00 && format->Bmask == 0x0000FF)
2941  {
2942 #ifdef GL_BGR
2943  if(renderer->enabled_features & GPU_FEATURE_GL_BGR)
2944  {
2945  if(surfaceFormatResult != NULL)
2946  *surfaceFormatResult = GL_BGR;
2947  return 0;
2948  }
2949 #endif
2950  }
2951  return 1;
2952 
2953  // 4-channel formats
2954  case GL_RGBA:
2955 
2956  if(format->BytesPerPixel != 4)
2957  return 1;
2958 
2959  // Looks like RGBA? Easy!
2960  if(format->Rmask == 0x000000FF && format->Gmask == 0x0000FF00 && format->Bmask == 0x00FF0000)
2961  {
2962  if(surfaceFormatResult != NULL)
2963  *surfaceFormatResult = GL_RGBA;
2964  return 0;
2965  }
2966  // Looks like ABGR?
2967  if(format->Rmask == 0xFF000000 && format->Gmask == 0x00FF0000 && format->Bmask == 0x0000FF00)
2968  {
2969 #ifdef GL_ABGR
2970  if(renderer->enabled_features & GPU_FEATURE_GL_ABGR)
2971  {
2972  if(surfaceFormatResult != NULL)
2973  *surfaceFormatResult = GL_ABGR;
2974  return 0;
2975  }
2976 #endif
2977  }
2978  // Looks like BGRA?
2979  else if(format->Rmask == 0x00FF0000 && format->Gmask == 0x0000FF00 && format->Bmask == 0x000000FF)
2980  {
2981 #ifdef GL_BGRA
2982  if(renderer->enabled_features & GPU_FEATURE_GL_BGRA)
2983  {
2984  //ARGB, for OpenGL BGRA
2985  if(surfaceFormatResult != NULL)
2986  *surfaceFormatResult = GL_BGRA;
2987  return 0;
2988  }
2989 #endif
2990  }
2991  return 1;
2992  default:
2993  GPU_PushErrorCode("GPU_CompareFormats", GPU_ERROR_DATA_ERROR, "Invalid texture format (0x%x)", glFormat);
2994  return -1;
2995  }
2996 }
2997 #endif
2998 
2999 
3000 // Adapted from SDL_AllocFormat()
3001 static SDL_PixelFormat* AllocFormat(GLenum glFormat)
3002 {
3003  // Yes, I need to do the whole thing myself... :(
3004  int channels;
3005  Uint32 Rmask, Gmask, Bmask, Amask = 0, mask;
3006  SDL_PixelFormat* result;
3007 
3008  switch(glFormat)
3009  {
3010  case GL_RGB:
3011  channels = 3;
3012  Rmask = 0x0000FF;
3013  Gmask = 0x00FF00;
3014  Bmask = 0xFF0000;
3015  break;
3016 #ifdef GL_BGR
3017  case GL_BGR:
3018  channels = 3;
3019  Rmask = 0xFF0000;
3020  Gmask = 0x00FF00;
3021  Bmask = 0x0000FF;
3022  break;
3023 #endif
3024  case GL_RGBA:
3025  channels = 4;
3026  Rmask = 0x000000FF;
3027  Gmask = 0x0000FF00;
3028  Bmask = 0x00FF0000;
3029  Amask = 0xFF000000;
3030  break;
3031 #ifdef GL_BGRA
3032  case GL_BGRA:
3033  channels = 4;
3034  Rmask = 0x00FF0000;
3035  Gmask = 0x0000FF00;
3036  Bmask = 0x000000FF;
3037  Amask = 0xFF000000;
3038  break;
3039 #endif
3040 #ifdef GL_ABGR
3041  case GL_ABGR:
3042  channels = 4;
3043  Rmask = 0xFF000000;
3044  Gmask = 0x00FF0000;
3045  Bmask = 0x0000FF00;
3046  Amask = 0x000000FF;
3047  break;
3048 #endif
3049  default:
3050  return NULL;
3051  }
3052 
3053  //GPU_LogError("AllocFormat(): %d, Masks: %X %X %X %X\n", glFormat, Rmask, Gmask, Bmask, Amask);
3054 
3055  result = (SDL_PixelFormat*)SDL_malloc(sizeof(SDL_PixelFormat));
3056  memset(result, 0, sizeof(SDL_PixelFormat));
3057 
3058  result->BitsPerPixel = 8*channels;
3059  result->BytesPerPixel = channels;
3060 
3061  result->Rmask = Rmask;
3062  result->Rshift = 0;
3063  result->Rloss = 8;
3064  if (Rmask) {
3065  for (mask = Rmask; !(mask & 0x01); mask >>= 1)
3066  ++result->Rshift;
3067  for (; (mask & 0x01); mask >>= 1)
3068  --result->Rloss;
3069  }
3070 
3071  result->Gmask = Gmask;
3072  result->Gshift = 0;
3073  result->Gloss = 8;
3074  if (Gmask) {
3075  for (mask = Gmask; !(mask & 0x01); mask >>= 1)
3076  ++result->Gshift;
3077  for (; (mask & 0x01); mask >>= 1)
3078  --result->Gloss;
3079  }
3080 
3081  result->Bmask = Bmask;
3082  result->Bshift = 0;
3083  result->Bloss = 8;
3084  if (Bmask) {
3085  for (mask = Bmask; !(mask & 0x01); mask >>= 1)
3086  ++result->Bshift;
3087  for (; (mask & 0x01); mask >>= 1)
3088  --result->Bloss;
3089  }
3090 
3091  result->Amask = Amask;
3092  result->Ashift = 0;
3093  result->Aloss = 8;
3094  if (Amask) {
3095  for (mask = Amask; !(mask & 0x01); mask >>= 1)
3096  ++result->Ashift;
3097  for (; (mask & 0x01); mask >>= 1)
3098  --result->Aloss;
3099  }
3100 
3101  return result;
3102 }
3103 
3104 static void FreeFormat(SDL_PixelFormat* format)
3105 {
3106  SDL_free(format);
3107 }
3108 
3109 
3110 // Returns NULL on failure. Returns the original surface if no copy is needed. Returns a new surface converted to the right format otherwise.
3111 static SDL_Surface* copySurfaceIfNeeded(GPU_Renderer* renderer, GLenum glFormat, SDL_Surface* surface, GLenum* surfaceFormatResult)
3112 {
3113  // If format doesn't match, we need to do a copy
3114  int format_compare = compareFormats(renderer, glFormat, surface, surfaceFormatResult);
3115 
3116  // There's a problem, logged in compareFormats()
3117  if(format_compare < 0)
3118  return NULL;
3119 
3120 
3121  // Copy it to a different format
3122  if(format_compare > 0)
3123  {
3124  // Convert to the right format
3125  SDL_PixelFormat* dst_fmt = AllocFormat(glFormat);
3126  surface = SDL_ConvertSurface(surface, dst_fmt, 0);
3127  FreeFormat(dst_fmt);
3128  if(surfaceFormatResult != NULL && surface != NULL)
3129  *surfaceFormatResult = glFormat;
3130  }
3131 
3132  // No copy needed
3133  return surface;
3134 }
3135 
3136 static GPU_Image* gpu_copy_image_pixels_only(GPU_Renderer* renderer, GPU_Image* image)
3137 {
3138  GPU_Image* result = NULL;
3139 
3140  if(image == NULL)
3141  return NULL;
3142 
3143  switch(image->format)
3144  {
3145  case GPU_FORMAT_RGB:
3146  case GPU_FORMAT_RGBA:
3147  case GPU_FORMAT_BGR:
3148  case GPU_FORMAT_BGRA:
3149  case GPU_FORMAT_ABGR:
3150  // Copy via framebuffer blitting (fast)
3151  {
3152  GPU_Target* target;
3153 
3154  result = renderer->impl->CreateImage(renderer, image->texture_w, image->texture_h, image->format);
3155  if(result == NULL)
3156  {
3157  GPU_PushErrorCode("GPU_CopyImage", GPU_ERROR_BACKEND_ERROR, "Failed to create new image.");
3158  return NULL;
3159  }
3160 
3161  // Don't free the target yet (a waste of perf), but let it be freed when the image is freed...
3162  target = GPU_GetTarget(result);
3163  if(target == NULL)
3164  {
3165  GPU_FreeImage(result);
3166  GPU_PushErrorCode("GPU_CopyImage", GPU_ERROR_BACKEND_ERROR, "Failed to load target.");
3167  return NULL;
3168  }
3169 
3170  // For some reason, I wasn't able to get glCopyTexImage2D() or glCopyTexSubImage2D() working without getting GL_INVALID_ENUM (0x500).
3171  // It seemed to only work for the default framebuffer...
3172 
3173  {
3174  // Clear the color, blending, and filter mode
3175  SDL_Color color = image->color;
3176  GPU_bool use_blending = image->use_blending;
3177  GPU_FilterEnum filter_mode = image->filter_mode;
3178  GPU_bool use_virtual = image->using_virtual_resolution;
3179  Uint16 w = 0, h = 0;
3180  GPU_UnsetColor(image);
3181  GPU_SetBlending(image, 0);
3183  if(use_virtual)
3184  {
3185  w = image->w;
3186  h = image->h;
3188  }
3189 
3190  renderer->impl->Blit(renderer, image, NULL, target, image->w / 2, image->h / 2);
3191 
3192  // Restore the saved settings
3193  GPU_SetColor(image, color);
3194  GPU_SetBlending(image, use_blending);
3195  GPU_SetImageFilter(image, filter_mode);
3196  if(use_virtual)
3197  {
3198  GPU_SetImageVirtualResolution(image, w, h);
3199  }
3200  }
3201  }
3202  break;
3203  case GPU_FORMAT_LUMINANCE:
3205  case GPU_FORMAT_ALPHA:
3206  case GPU_FORMAT_RG:
3207  // Copy via texture download and upload (slow)
3208  {
3209  GLenum internal_format;
3210  int w;
3211  int h;
3212  unsigned char* texture_data = getRawImageData(renderer, image);
3213  if(texture_data == NULL)
3214  {
3215  GPU_PushErrorCode("GPU_CopyImage", GPU_ERROR_BACKEND_ERROR, "Failed to get raw texture data.");
3216  return NULL;
3217  }
3218 
3219  result = CreateUninitializedImage(renderer, image->texture_w, image->texture_h, image->format);
3220  if(result == NULL)
3221  {
3222  SDL_free(texture_data);
3223  GPU_PushErrorCode("GPU_CopyImage", GPU_ERROR_BACKEND_ERROR, "Failed to create new image.");
3224  return NULL;
3225  }
3226 
3227  changeTexturing(renderer, 1);
3228  bindTexture(renderer, result);
3229 
3230  internal_format = ((GPU_IMAGE_DATA*)(result->data))->format;
3231  w = result->w;
3232  h = result->h;
3233  if(!(renderer->enabled_features & GPU_FEATURE_NON_POWER_OF_TWO))
3234  {
3235  if(!isPowerOfTwo(w))
3236  w = getNearestPowerOf2(w);
3237  if(!isPowerOfTwo(h))
3238  h = getNearestPowerOf2(h);
3239  }
3240 
3241  upload_new_texture(texture_data, GPU_MakeRect(0, 0, w, h), internal_format, 1, w, result->bytes_per_pixel);
3242 
3243 
3244  // Tell SDL_gpu what we got.
3245  result->texture_w = w;
3246  result->texture_h = h;
3247 
3248  SDL_free(texture_data);
3249  }
3250  break;
3251  default:
3252  GPU_PushErrorCode("GPU_CopyImage", GPU_ERROR_BACKEND_ERROR, "Could not copy the given image format.");
3253  break;
3254  }
3255 
3256  return result;
3257 }
3258 
3259 static GPU_Image* CopyImage(GPU_Renderer* renderer, GPU_Image* image)
3260 {
3261  GPU_Image* result = NULL;
3262 
3263  if(image == NULL)
3264  return NULL;
3265 
3266  result = gpu_copy_image_pixels_only(renderer, image);
3267 
3268  if(result != NULL)
3269  {
3270  // Copy the image settings
3271  GPU_SetColor(result, image->color);
3272  GPU_SetBlending(result, image->use_blending);
3273  result->blend_mode = image->blend_mode;
3274  GPU_SetImageFilter(result, image->filter_mode);
3275  GPU_SetSnapMode(result, image->snap_mode);
3276  GPU_SetWrapMode(result, image->wrap_mode_x, image->wrap_mode_y);
3277  if(image->has_mipmaps)
3278  GPU_GenerateMipmaps(result);
3279  if(image->using_virtual_resolution)
3280  GPU_SetImageVirtualResolution(result, image->w, image->h);
3281  }
3282 
3283  return result;
3284 }
3285 
3286 
3287 
3288 static void UpdateImage(GPU_Renderer* renderer, GPU_Image* image, const GPU_Rect* image_rect, SDL_Surface* surface, const GPU_Rect* surface_rect)
3289 {
3290  GPU_IMAGE_DATA* data;
3291  GLenum original_format;
3292 
3293  SDL_Surface* newSurface;
3294  GPU_Rect updateRect;
3295  GPU_Rect sourceRect;
3296  int alignment;
3297  Uint8* pixels;
3298 
3299  if(image == NULL || surface == NULL)
3300  return;
3301 
3302  data = (GPU_IMAGE_DATA*)image->data;
3303  original_format = data->format;
3304 
3305  newSurface = copySurfaceIfNeeded(renderer, data->format, surface, &original_format);
3306  if(newSurface == NULL)
3307  {
3308  GPU_PushErrorCode("GPU_UpdateImage", GPU_ERROR_BACKEND_ERROR, "Failed to convert surface to proper pixel format.");
3309  return;
3310  }
3311 
3312  if(image_rect != NULL)
3313  {
3314  updateRect = *image_rect;
3315  if(updateRect.x < 0)
3316  {
3317  updateRect.w += updateRect.x;
3318  updateRect.x = 0;
3319  }
3320  if(updateRect.y < 0)
3321  {
3322  updateRect.h += updateRect.y;
3323  updateRect.y = 0;
3324  }
3325  if(updateRect.x + updateRect.w > image->base_w)
3326  updateRect.w += image->base_w - (updateRect.x + updateRect.w);
3327  if(updateRect.y + updateRect.h > image->base_h)
3328  updateRect.h += image->base_h - (updateRect.y + updateRect.h);
3329 
3330  if(updateRect.w <= 0)
3331  updateRect.w = 0;
3332  if(updateRect.h <= 0)
3333  updateRect.h = 0;
3334  }
3335  else
3336  {
3337  updateRect.x = 0;
3338  updateRect.y = 0;
3339  updateRect.w = image->base_w;
3340  updateRect.h = image->base_h;
3341  if(updateRect.w < 0.0f || updateRect.h < 0.0f)
3342  {
3343  GPU_PushErrorCode("GPU_UpdateImage", GPU_ERROR_USER_ERROR, "Given negative image rectangle.");
3344  return;
3345  }
3346  }
3347 
3348  if(surface_rect != NULL)
3349  {
3350  sourceRect = *surface_rect;
3351  if(sourceRect.x < 0)
3352  {
3353  sourceRect.w += sourceRect.x;
3354  sourceRect.x = 0;
3355  }
3356  if(sourceRect.y < 0)
3357  {
3358  sourceRect.h += sourceRect.y;
3359  sourceRect.y = 0;
3360  }
3361  if(sourceRect.x + sourceRect.w > newSurface->w)
3362  sourceRect.w += newSurface->w - (sourceRect.x + sourceRect.w);
3363  if(sourceRect.y + sourceRect.h > newSurface->h)
3364  sourceRect.h += newSurface->h - (sourceRect.y + sourceRect.h);
3365 
3366  if(sourceRect.w <= 0)
3367  sourceRect.w = 0;
3368  if(sourceRect.h <= 0)
3369  sourceRect.h = 0;
3370  }
3371  else
3372  {
3373  sourceRect.x = 0;
3374  sourceRect.y = 0;
3375  sourceRect.w = newSurface->w;
3376  sourceRect.h = newSurface->h;
3377  }
3378 
3379 
3380  changeTexturing(renderer, 1);
3381  if(image->target != NULL && isCurrentTarget(renderer, image->target))
3382  renderer->impl->FlushBlitBuffer(renderer);
3383  bindTexture(renderer, image);
3384  alignment = 8;
3385  while(newSurface->pitch % alignment)
3386  alignment >>= 1;
3387 
3388  // Use the smaller of the image and surface rect dimensions
3389  if(sourceRect.w < updateRect.w)
3390  updateRect.w = sourceRect.w;
3391  if(sourceRect.h < updateRect.h)
3392  updateRect.h = sourceRect.h;
3393 
3394  pixels = (Uint8*)newSurface->pixels;
3395  // Shift the pixels pointer to the proper source position
3396  pixels += (int)(newSurface->pitch * sourceRect.y + (newSurface->format->BytesPerPixel)*sourceRect.x);
3397 
3398  upload_texture(pixels, updateRect, original_format, alignment, newSurface->pitch/newSurface->format->BytesPerPixel, newSurface->pitch, newSurface->format->BytesPerPixel);
3399 
3400  // Delete temporary surface
3401  if(surface != newSurface)
3402  SDL_FreeSurface(newSurface);
3403 
3404 }
3405 
3406 
3407 static void UpdateImageBytes(GPU_Renderer* renderer, GPU_Image* image, const GPU_Rect* image_rect, const unsigned char* bytes, int bytes_per_row)
3408 {
3409  GPU_IMAGE_DATA* data;
3410  GLenum original_format;
3411 
3412  GPU_Rect updateRect;
3413  int alignment;
3414 
3415  if(image == NULL || bytes == NULL)
3416  return;
3417 
3418  data = (GPU_IMAGE_DATA*)image->data;
3419  original_format = data->format;
3420 
3421  if(image_rect != NULL)
3422  {
3423  updateRect = *image_rect;
3424  if(updateRect.x < 0)
3425  {
3426  updateRect.w += updateRect.x;
3427  updateRect.x = 0;
3428  }
3429  if(updateRect.y < 0)
3430  {
3431  updateRect.h += updateRect.y;
3432  updateRect.y = 0;
3433  }
3434  if(updateRect.x + updateRect.w > image->base_w)
3435  updateRect.w += image->base_w - (updateRect.x + updateRect.w);
3436  if(updateRect.y + updateRect.h > image->base_h)
3437  updateRect.h += image->base_h - (updateRect.y + updateRect.h);
3438 
3439  if(updateRect.w <= 0)
3440  updateRect.w = 0;
3441  if(updateRect.h <= 0)
3442  updateRect.h = 0;
3443  }
3444  else
3445  {
3446  updateRect.x = 0;
3447  updateRect.y = 0;
3448  updateRect.w = image->base_w;
3449  updateRect.h = image->base_h;
3450  if(updateRect.w < 0.0f || updateRect.h < 0.0f)
3451  {
3452  GPU_PushErrorCode("GPU_UpdateImage", GPU_ERROR_USER_ERROR, "Given negative image rectangle.");
3453  return;
3454  }
3455  }
3456 
3457 
3458  changeTexturing(renderer, 1);
3459  if(image->target != NULL && isCurrentTarget(renderer, image->target))
3460  renderer->impl->FlushBlitBuffer(renderer);
3461  bindTexture(renderer, image);
3462  alignment = 8;
3463  while(bytes_per_row % alignment)
3464  alignment >>= 1;
3465 
3466  upload_texture(bytes, updateRect, original_format, alignment, bytes_per_row / image->bytes_per_pixel, bytes_per_row, image->bytes_per_pixel);
3467 }
3468 
3469 
3470 
3471 static GPU_bool ReplaceImage(GPU_Renderer* renderer, GPU_Image* image, SDL_Surface* surface, const GPU_Rect* surface_rect)
3472 {
3473  GPU_IMAGE_DATA* data;
3474  GPU_Rect sourceRect;
3475  SDL_Surface* newSurface;
3476  GLenum internal_format;
3477  Uint8* pixels;
3478  int w, h;
3479  int alignment;
3480 
3481  if(image == NULL)
3482  {
3483  GPU_PushErrorCode("GPU_ReplaceImage", GPU_ERROR_NULL_ARGUMENT, "image");
3484  return GPU_FALSE;
3485  }
3486 
3487  if(surface == NULL)
3488  {
3489  GPU_PushErrorCode("GPU_ReplaceImage", GPU_ERROR_NULL_ARGUMENT, "surface");
3490  return GPU_FALSE;
3491  }
3492 
3493  data = (GPU_IMAGE_DATA*)image->data;
3494  internal_format = data->format;
3495 
3496  newSurface = copySurfaceIfNeeded(renderer, internal_format, surface, &internal_format);
3497  if(newSurface == NULL)
3498  {
3499  GPU_PushErrorCode("GPU_ReplaceImage", GPU_ERROR_BACKEND_ERROR, "Failed to convert surface to proper pixel format.");
3500  return GPU_FALSE;
3501  }
3502 
3503  // Free the attached framebuffer
3504  if((renderer->enabled_features & GPU_FEATURE_RENDER_TARGETS) && image->target != NULL)
3505  {
3506  GPU_TARGET_DATA* tdata = (GPU_TARGET_DATA*)image->target->data;
3507  if(renderer->current_context_target != NULL)
3509  if(tdata->handle != 0)
3510  glDeleteFramebuffersPROC(1, &tdata->handle);
3511  tdata->handle = 0;
3512  }
3513 
3514  // Free the old texture
3515  if(data->owns_handle)
3516  glDeleteTextures( 1, &data->handle);
3517  data->handle = 0;
3518 
3519  // Get the area of the surface we'll use
3520  if(surface_rect == NULL)
3521  {
3522  sourceRect.x = 0;
3523  sourceRect.y = 0;
3524  sourceRect.w = surface->w;
3525  sourceRect.h = surface->h;
3526  }
3527  else
3528  sourceRect = *surface_rect;
3529 
3530  // Clip the source rect to the surface
3531  if(sourceRect.x < 0)
3532  {
3533  sourceRect.w += sourceRect.x;
3534  sourceRect.x = 0;
3535  }
3536  if(sourceRect.y < 0)
3537  {
3538  sourceRect.h += sourceRect.y;
3539  sourceRect.y = 0;
3540  }
3541  if(sourceRect.x >= surface->w)
3542  sourceRect.x = surface->w - 1;
3543  if(sourceRect.y >= surface->h)
3544  sourceRect.y = surface->h - 1;
3545 
3546  if(sourceRect.x + sourceRect.w > surface->w)
3547  sourceRect.w = surface->w - sourceRect.x;
3548  if(sourceRect.y + sourceRect.h > surface->h)
3549  sourceRect.h = surface->h - sourceRect.y;
3550 
3551  if(sourceRect.w <= 0 || sourceRect.h <= 0)
3552  {
3553  GPU_PushErrorCode("GPU_ReplaceImage", GPU_ERROR_DATA_ERROR, "Clipped source rect has zero size.");
3554  return GPU_FALSE;
3555  }
3556 
3557  // Allocate new texture
3558  data->handle = CreateUninitializedTexture(renderer);
3559  data->owns_handle = 1;
3560  if(data->handle == 0)
3561  {
3562  GPU_PushErrorCode("GPU_ReplaceImage", GPU_ERROR_BACKEND_ERROR, "Failed to create a new texture handle.");
3563  return GPU_FALSE;
3564  }
3565 
3566  // Update image members
3567  w = sourceRect.w;
3568  h = sourceRect.h;
3569 
3570  if(!image->using_virtual_resolution)
3571  {
3572  image->w = w;
3573  image->h = h;
3574  }
3575  image->base_w = w;
3576  image->base_h = h;
3577 
3578  if(!(renderer->enabled_features & GPU_FEATURE_NON_POWER_OF_TWO))
3579  {
3580  if(!isPowerOfTwo(w))
3581  w = getNearestPowerOf2(w);
3582  if(!isPowerOfTwo(h))
3583  h = getNearestPowerOf2(h);
3584  }
3585  image->texture_w = w;
3586  image->texture_h = h;
3587 
3588  image->has_mipmaps = GPU_FALSE;
3589 
3590 
3591  // Upload surface pixel data
3592  alignment = 8;
3593  while(newSurface->pitch % alignment)
3594  alignment >>= 1;
3595 
3596  pixels = (Uint8*)newSurface->pixels;
3597  // Shift the pixels pointer to the proper source position
3598  pixels += (int)(newSurface->pitch * sourceRect.y + (newSurface->format->BytesPerPixel)*sourceRect.x);
3599 
3600  upload_new_texture(pixels, GPU_MakeRect(0, 0, w, h), internal_format, alignment, (newSurface->pitch / newSurface->format->BytesPerPixel), newSurface->format->BytesPerPixel);
3601 
3602 
3603  // Delete temporary surface
3604  if(surface != newSurface)
3605  SDL_FreeSurface(newSurface);
3606 
3607 
3608 
3609 
3610  // Update target members
3611  if((renderer->enabled_features & GPU_FEATURE_RENDER_TARGETS) && image->target != NULL)
3612  {
3613  GLenum status;
3614  GPU_Target* target = image->target;
3615  GPU_TARGET_DATA* tdata = (GPU_TARGET_DATA*)target->data;
3616 
3617  // Create framebuffer object
3618  glGenFramebuffersPROC(1, &tdata->handle);
3619  if(tdata->handle == 0)
3620  {
3621  GPU_PushErrorCode("GPU_ReplaceImage", GPU_ERROR_BACKEND_ERROR, "Failed to create new framebuffer target.");
3622  return GPU_FALSE;
3623  }
3624 
3625  flushAndBindFramebuffer(renderer, tdata->handle);
3626 
3627  // Attach the texture to it
3628  glFramebufferTexture2DPROC(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, data->handle, 0);
3629 
3630  status = glCheckFramebufferStatusPROC(GL_FRAMEBUFFER);
3631  if(status != GL_FRAMEBUFFER_COMPLETE)
3632  {
3633  GPU_PushErrorCode("GPU_ReplaceImage", GPU_ERROR_BACKEND_ERROR, "Failed to recreate framebuffer target.");
3634  return GPU_FALSE;
3635  }
3636 
3637  if(!target->using_virtual_resolution)
3638  {
3639  target->w = image->base_w;
3640  target->h = image->base_h;
3641  }
3642  target->base_w = image->texture_w;
3643  target->base_h = image->texture_h;
3644 
3645  // Reset viewport?
3646  target->viewport = GPU_MakeRect(0, 0, target->w, target->h);
3647  }
3648 
3649  return GPU_TRUE;
3650 }
3651 
3652 
3653 static_inline Uint32 getPixel(SDL_Surface *Surface, int x, int y)
3654 {
3655  Uint8* bits;
3656  Uint32 bpp;
3657 
3658  if(x < 0 || x >= Surface->w)
3659  return 0; // Best I could do for errors
3660 
3661  bpp = Surface->format->BytesPerPixel;
3662  bits = ((Uint8*)Surface->pixels) + y*Surface->pitch + x*bpp;
3663 
3664  switch (bpp)
3665  {
3666  case 1:
3667  return *((Uint8*)Surface->pixels + y * Surface->pitch + x);
3668  break;
3669  case 2:
3670  return *((Uint16*)Surface->pixels + y * Surface->pitch/2 + x);
3671  break;
3672  case 3:
3673  // Endian-correct, but slower
3674  {
3675  Uint8 r, g, b;
3676  r = *((bits)+Surface->format->Rshift/8);
3677  g = *((bits)+Surface->format->Gshift/8);
3678  b = *((bits)+Surface->format->Bshift/8);
3679  return SDL_MapRGB(Surface->format, r, g, b);
3680  }
3681  break;
3682  case 4:
3683  return *((Uint32*)Surface->pixels + y * Surface->pitch/4 + x);
3684  break;
3685  }
3686 
3687  return 0; // FIXME: Handle errors better
3688 }
3689 
3690 static GPU_Image* CopyImageFromSurface(GPU_Renderer* renderer, SDL_Surface* surface)
3691 {
3692  GPU_FormatEnum format;
3693  GPU_Image* image;
3694 
3695  if(surface == NULL)
3696  {
3697  GPU_PushErrorCode("GPU_CopyImageFromSurface", GPU_ERROR_NULL_ARGUMENT, "surface");
3698  return NULL;
3699  }
3700 
3701  if(surface->w == 0 || surface->h == 0)
3702  {
3703  GPU_PushErrorCode("GPU_CopyImageFromSurface", GPU_ERROR_DATA_ERROR, "Surface has a zero dimension.");
3704  return NULL;
3705  }
3706 
3707  // See what the best image format is.
3708  if(surface->format->Amask == 0)
3709  {
3710  if(has_colorkey(surface))
3711  format = GPU_FORMAT_RGBA;
3712  else
3713  format = GPU_FORMAT_RGB;
3714  }
3715  else
3716  {
3717  // TODO: Choose the best format for the texture depending on endianness.
3718  format = GPU_FORMAT_RGBA;
3719  }
3720 
3721  image = renderer->impl->CreateImage(renderer, surface->w, surface->h, format);
3722  if(image == NULL)
3723  return NULL;
3724 
3725  renderer->impl->UpdateImage(renderer, image, NULL, surface, NULL);
3726 
3727  return image;
3728 }
3729 
3730 
3731 static GPU_Image* CopyImageFromTarget(GPU_Renderer* renderer, GPU_Target* target)
3732 {
3733  GPU_Image* result;
3734 
3735  if(target == NULL)
3736  return NULL;
3737 
3738  if(target->image != NULL)
3739  {
3740  result = gpu_copy_image_pixels_only(renderer, target->image);
3741  }
3742  else
3743  {
3744  SDL_Surface* surface = renderer->impl->CopySurfaceFromTarget(renderer, target);
3745  result = renderer->impl->CopyImageFromSurface(renderer, surface);
3746  SDL_FreeSurface(surface);
3747  }
3748 
3749  return result;
3750 }
3751 
3752 
3753 static void FreeImage(GPU_Renderer* renderer, GPU_Image* image)
3754 {
3755  GPU_IMAGE_DATA* data;
3756 
3757  if(image == NULL)
3758  return;
3759 
3760  if(image->refcount > 1)
3761  {
3762  image->refcount--;
3763  return;
3764  }
3765 
3766  // Delete the attached target first
3767  if(image->target != NULL)
3768  {
3769  GPU_Target* target = image->target;
3770  image->target = NULL;
3771 
3772  // Freeing it will decrement the refcount. If this is the only increment, it will be freed. This means GPU_LoadTarget() needs to be paired with GPU_FreeTarget().
3773  target->refcount++;
3774  renderer->impl->FreeTarget(renderer, target);
3775  }
3776 
3777  flushAndClearBlitBufferIfCurrentTexture(renderer, image);
3778 
3779  // Does the renderer data need to be freed too?
3780  data = (GPU_IMAGE_DATA*)image->data;
3781  if(data->refcount > 1)
3782  {
3783  data->refcount--;
3784  }
3785  else
3786  {
3787  if(data->owns_handle)
3788  {
3790  glDeleteTextures( 1, &data->handle);
3791  }
3792  SDL_free(data);
3793  }
3794 
3795  SDL_free(image);
3796 }
3797 
3798 
3799 
3800 static GPU_Target* GetTarget(GPU_Renderer* renderer, GPU_Image* image)
3801 {
3802  GLuint handle;
3803  GLenum status;
3804  GPU_Target* result;
3805  GPU_TARGET_DATA* data;
3806 
3807  if(image == NULL)
3808  return NULL;
3809 
3810  if(image->target != NULL)
3811  return image->target;
3812 
3813  if(!(renderer->enabled_features & GPU_FEATURE_RENDER_TARGETS))
3814  return NULL;
3815 
3816  // Create framebuffer object
3817  glGenFramebuffersPROC(1, &handle);
3818  flushAndBindFramebuffer(renderer, handle);
3819 
3820  // Attach the texture to it
3821  glFramebufferTexture2DPROC(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ((GPU_IMAGE_DATA*)image->data)->handle, 0);
3822 
3823  status = glCheckFramebufferStatusPROC(GL_FRAMEBUFFER);
3824  if(status != GL_FRAMEBUFFER_COMPLETE)
3825  {
3826  GPU_PushErrorCode("GPU_GetTarget", GPU_ERROR_DATA_ERROR, "Framebuffer incomplete with status: 0x%x. Format 0x%x for framebuffers might not be supported on this hardware.", status, ((GPU_IMAGE_DATA*)image->data)->format);
3827  return NULL;
3828  }
3829 
3830  result = (GPU_Target*)SDL_malloc(sizeof(GPU_Target));
3831  memset(result, 0, sizeof(GPU_Target));
3832  result->refcount = 0;
3833  data = (GPU_TARGET_DATA*)SDL_malloc(sizeof(GPU_TARGET_DATA));
3834  data->refcount = 1;
3835  result->data = data;
3836  data->handle = handle;
3837  data->format = ((GPU_IMAGE_DATA*)image->data)->format;
3838 
3839  result->renderer = renderer;
3840  result->context_target = renderer->current_context_target;
3841  result->context = NULL;
3842  result->image = image;
3843  result->w = image->w;
3844  result->h = image->h;
3845  result->base_w = image->texture_w;
3846  result->base_h = image->texture_h;
3848 
3849  result->viewport = GPU_MakeRect(0, 0, result->w, result->h);
3850 
3851  result->camera = GPU_GetDefaultCamera();
3852  result->use_camera = GPU_TRUE;
3853 
3854  result->use_clip_rect = GPU_FALSE;
3855  result->clip_rect.x = 0;
3856  result->clip_rect.y = 0;
3857  result->clip_rect.w = result->w;
3858  result->clip_rect.h = result->h;
3859  result->use_color = GPU_FALSE;
3860 
3861  image->target = result;
3862  return result;
3863 }
3864 
3865 
3866 
3867 static void FreeTargetData(GPU_Renderer* renderer, GPU_TARGET_DATA* data)
3868 {
3869  if(data == NULL)
3870  return;
3871 
3872  if(data->refcount > 1)
3873  {
3874  data->refcount--;
3875  return;
3876  }
3877 
3878  // Time to actually free this target data
3879  if(renderer->enabled_features & GPU_FEATURE_RENDER_TARGETS)
3880  {
3881  // It might be possible to check against the default framebuffer (save that binding in the context data) and avoid deleting that... Is that desired?
3882  glDeleteFramebuffersPROC(1, &data->handle);
3883  }
3884 
3885  SDL_free(data);
3886 }
3887 
3888 static void FreeContext(GPU_Context* context)
3889 {
3890  GPU_CONTEXT_DATA* cdata;
3891 
3892  if(context == NULL)
3893  return;
3894 
3895  if(context->refcount > 1)
3896  {
3897  context->refcount--;
3898  return;
3899  }
3900 
3901  // Time to actually free this context and its data
3902  cdata = (GPU_CONTEXT_DATA*)context->data;
3903 
3904  SDL_free(cdata->blit_buffer);
3905  SDL_free(cdata->index_buffer);
3906 
3907  if(!context->failed)
3908  {
3909  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
3910  glDeleteBuffers(2, cdata->blit_VBO);
3911  glDeleteBuffers(1, &cdata->blit_IBO);
3912  glDeleteBuffers(16, cdata->attribute_VBO);
3913  #if !defined(SDL_GPU_NO_VAO)
3914  glDeleteVertexArrays(1, &cdata->blit_VAO);
3915  #endif
3916  #endif
3917  }
3918 
3919  #ifdef SDL_GPU_USE_SDL2
3920  if(context->context != 0)
3921  SDL_GL_DeleteContext(context->context);
3922  #endif
3923 
3924  SDL_free(cdata);
3925  SDL_free(context);
3926 }
3927 
3928 static void FreeTarget(GPU_Renderer* renderer, GPU_Target* target)
3929 {
3930  if(target == NULL)
3931  return;
3932 
3933  if(target->refcount > 1)
3934  {
3935  target->refcount--;
3936  return;
3937  }
3938 
3939  // Time to actually free this target
3940 
3941  // Prepare to work in this target's context, if it has one
3942  if(target == renderer->current_context_target)
3943  renderer->impl->FlushBlitBuffer(renderer);
3944  else if(target->context_target != NULL)
3946 
3947 
3948  // Release renderer data reference
3949  FreeTargetData(renderer, (GPU_TARGET_DATA*)target->data);
3950 
3951  // Release context reference
3952  if(target->context != NULL)
3953  {
3954  // Remove all of the window mappings that refer to this target
3956 
3957  FreeContext(target->context);
3958  }
3959 
3960  // Clear references to this target
3961  if(target == renderer->current_context_target)
3962  renderer->current_context_target = NULL;
3963 
3964  if(target->image != NULL && target->image->target == target)
3965  target->image->target = NULL;
3966 
3967 
3968  SDL_free(target);
3969 }
3970 
3971 
3972 
3973 
3974 
3975 #define SET_TEXTURED_VERTEX(x, y, s, t, r, g, b, a) \
3976  blit_buffer[vert_index] = x; \
3977  blit_buffer[vert_index+1] = y; \
3978  blit_buffer[tex_index] = s; \
3979  blit_buffer[tex_index+1] = t; \
3980  blit_buffer[color_index] = r; \
3981  blit_buffer[color_index+1] = g; \
3982  blit_buffer[color_index+2] = b; \
3983  blit_buffer[color_index+3] = a; \
3984  index_buffer[cdata->index_buffer_num_vertices++] = cdata->blit_buffer_num_vertices++; \
3985  vert_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX; \
3986  tex_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX; \
3987  color_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
3988 
3989 #define SET_TEXTURED_VERTEX_UNINDEXED(x, y, s, t, r, g, b, a) \
3990  blit_buffer[vert_index] = x; \
3991  blit_buffer[vert_index+1] = y; \
3992  blit_buffer[tex_index] = s; \
3993  blit_buffer[tex_index+1] = t; \
3994  blit_buffer[color_index] = r; \
3995  blit_buffer[color_index+1] = g; \
3996  blit_buffer[color_index+2] = b; \
3997  blit_buffer[color_index+3] = a; \
3998  vert_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX; \
3999  tex_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX; \
4000  color_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4001 
4002 #define SET_UNTEXTURED_VERTEX(x, y, r, g, b, a) \
4003  blit_buffer[vert_index] = x; \
4004  blit_buffer[vert_index+1] = y; \
4005  blit_buffer[color_index] = r; \
4006  blit_buffer[color_index+1] = g; \
4007  blit_buffer[color_index+2] = b; \
4008  blit_buffer[color_index+3] = a; \
4009  index_buffer[cdata->index_buffer_num_vertices++] = cdata->blit_buffer_num_vertices++; \
4010  vert_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX; \
4011  color_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4012 
4013 #define SET_UNTEXTURED_VERTEX_UNINDEXED(x, y, r, g, b, a) \
4014  blit_buffer[vert_index] = x; \
4015  blit_buffer[vert_index+1] = y; \
4016  blit_buffer[color_index] = r; \
4017  blit_buffer[color_index+1] = g; \
4018  blit_buffer[color_index+2] = b; \
4019  blit_buffer[color_index+3] = a; \
4020  vert_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX; \
4021  color_index += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4022 
4023 #define SET_INDEXED_VERTEX(offset) \
4024  index_buffer[cdata->index_buffer_num_vertices++] = blit_buffer_starting_index + (offset);
4025 
4026 #define SET_RELATIVE_INDEXED_VERTEX(offset) \
4027  index_buffer[cdata->index_buffer_num_vertices++] = cdata->blit_buffer_num_vertices + (offset);
4028 
4029 
4030 
4031 #define BEGIN_UNTEXTURED_SEGMENTS(x1, y1, x2, y2, r, g, b, a) \
4032  SET_UNTEXTURED_VERTEX(x1, y1, r, g, b, a); \
4033  SET_UNTEXTURED_VERTEX(x2, y2, r, g, b, a);
4034 
4035 // Finish previous triangles and start the next one
4036 #define SET_UNTEXTURED_SEGMENTS(x1, y1, x2, y2, r, g, b, a) \
4037  SET_UNTEXTURED_VERTEX(x1, y1, r, g, b, a); \
4038  SET_RELATIVE_INDEXED_VERTEX(-2); \
4039  SET_UNTEXTURED_VERTEX(x2, y2, r, g, b, a); \
4040  SET_RELATIVE_INDEXED_VERTEX(-2); \
4041  SET_RELATIVE_INDEXED_VERTEX(-2); \
4042  SET_RELATIVE_INDEXED_VERTEX(-1);
4043 
4044 // Finish previous triangles
4045 #define LOOP_UNTEXTURED_SEGMENTS() \
4046  SET_INDEXED_VERTEX(0); \
4047  SET_RELATIVE_INDEXED_VERTEX(-1); \
4048  SET_INDEXED_VERTEX(1); \
4049  SET_INDEXED_VERTEX(0);
4050 
4051 #define END_UNTEXTURED_SEGMENTS(x1, y1, x2, y2, r, g, b, a) \
4052  SET_UNTEXTURED_VERTEX(x1, y1, r, g, b, a); \
4053  SET_RELATIVE_INDEXED_VERTEX(-2); \
4054  SET_UNTEXTURED_VERTEX(x2, y2, r, g, b, a); \
4055  SET_RELATIVE_INDEXED_VERTEX(-2);
4056 
4057 
4058 
4059 static void Blit(GPU_Renderer* renderer, GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y)
4060 {
4061  Uint32 tex_w, tex_h;
4062  float w;
4063  float h;
4064  float x1, y1, x2, y2;
4065  float dx1, dy1, dx2, dy2;
4066  GPU_CONTEXT_DATA* cdata;
4067  float* blit_buffer;
4068  unsigned short* index_buffer;
4069  unsigned short blit_buffer_starting_index;
4070  int vert_index;
4071  int tex_index;
4072  int color_index;
4073  float r, g, b, a;
4074 
4075  if(image == NULL)
4076  {
4077  GPU_PushErrorCode("GPU_Blit", GPU_ERROR_NULL_ARGUMENT, "image");
4078  return;
4079  }
4080  if(target == NULL)
4081  {
4082  GPU_PushErrorCode("GPU_Blit", GPU_ERROR_NULL_ARGUMENT, "target");
4083  return;
4084  }
4085  if(renderer != image->renderer || renderer != target->renderer)
4086  {
4087  GPU_PushErrorCode("GPU_Blit", GPU_ERROR_USER_ERROR, "Mismatched renderer");
4088  return;
4089  }
4090 
4091  makeContextCurrent(renderer, target);
4092  if(renderer->current_context_target == NULL)
4093  {
4094  GPU_PushErrorCode("GPU_Blit", GPU_ERROR_USER_ERROR, "NULL context");
4095  return;
4096  }
4097 
4098  prepareToRenderToTarget(renderer, target);
4099  prepareToRenderImage(renderer, target, image);
4100 
4101  // Bind the texture to which subsequent calls refer
4102  bindTexture(renderer, image);
4103 
4104  // Bind the FBO
4105  if(!bindFramebuffer(renderer, target))
4106  {
4107  GPU_PushErrorCode("GPU_Blit", GPU_ERROR_BACKEND_ERROR, "Failed to bind framebuffer.");
4108  return;
4109  }
4110 
4111  tex_w = image->texture_w;
4112  tex_h = image->texture_h;
4113 
4115  {
4116  // Avoid rounding errors in texture sampling by insisting on integral pixel positions
4117  x = floorf(x);
4118  y = floorf(y);
4119  }
4120 
4121  if(src_rect == NULL)
4122  {
4123  // Scale tex coords according to actual texture dims
4124  x1 = 0.0f;
4125  y1 = 0.0f;
4126  x2 = ((float)image->w)/tex_w;
4127  y2 = ((float)image->h)/tex_h;
4128  w = image->w;
4129  h = image->h;
4130  }
4131  else
4132  {
4133  // Scale src_rect tex coords according to actual texture dims
4134  x1 = src_rect->x/(float)tex_w;
4135  y1 = src_rect->y/(float)tex_h;
4136  x2 = (src_rect->x + src_rect->w)/(float)tex_w;
4137  y2 = (src_rect->y + src_rect->h)/(float)tex_h;
4138  w = src_rect->w;
4139  h = src_rect->h;
4140  }
4141 
4142  if(image->using_virtual_resolution)
4143  {
4144  // Scale texture coords to fit the original dims
4145  x1 *= image->base_w/(float)image->w;
4146  y1 *= image->base_h/(float)image->h;
4147  x2 *= image->base_w/(float)image->w;
4148  y2 *= image->base_h/(float)image->h;
4149  }
4150 
4151  // Center the image on the given coords
4152  dx1 = x - w * image->anchor_x;
4153  dy1 = y - h * image->anchor_y;
4154  dx2 = x + w * (1.0f - image->anchor_x);
4155  dy2 = y + h * (1.0f - image->anchor_y);
4156 
4158  {
4159  float fractional;
4160  fractional = w/2.0f - floorf(w/2.0f);
4161  dx1 += fractional;
4162  dx2 += fractional;
4163  fractional = h/2.0f - floorf(h/2.0f);
4164  dy1 += fractional;
4165  dy2 += fractional;
4166  }
4167 
4168  if(renderer->coordinate_mode)
4169  {
4170  float temp = dy1;
4171  dy1 = dy2;
4172  dy2 = temp;
4173  }
4174 
4175  cdata = (GPU_CONTEXT_DATA*)renderer->current_context_target->context->data;
4176 
4177  if(cdata->blit_buffer_num_vertices + 4 >= cdata->blit_buffer_max_num_vertices)
4178  {
4179  if(!growBlitBuffer(cdata, cdata->blit_buffer_num_vertices + 4))
4180  renderer->impl->FlushBlitBuffer(renderer);
4181  }
4182  if(cdata->index_buffer_num_vertices + 6 >= cdata->index_buffer_max_num_vertices)
4183  {
4184  if(!growIndexBuffer(cdata, cdata->index_buffer_num_vertices + 6))
4185  renderer->impl->FlushBlitBuffer(renderer);
4186  }
4187 
4188  blit_buffer = cdata->blit_buffer;
4189  index_buffer = cdata->index_buffer;
4190 
4191  blit_buffer_starting_index = cdata->blit_buffer_num_vertices;
4192 
4193  vert_index = GPU_BLIT_BUFFER_VERTEX_OFFSET + cdata->blit_buffer_num_vertices*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4194  tex_index = GPU_BLIT_BUFFER_TEX_COORD_OFFSET + cdata->blit_buffer_num_vertices*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4195  color_index = GPU_BLIT_BUFFER_COLOR_OFFSET + cdata->blit_buffer_num_vertices*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4196  if(target->use_color)
4197  {
4198  r = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.r, image->color.r);
4199  g = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.g, image->color.g);
4200  b = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.b, image->color.b);
4202  }
4203  else
4204  {
4205  r = image->color.r/255.0f;
4206  g = image->color.g/255.0f;
4207  b = image->color.b/255.0f;
4208  a = GET_ALPHA(image->color)/255.0f;
4209  }
4210 
4211  // 4 Quad vertices
4212  SET_TEXTURED_VERTEX_UNINDEXED(dx1, dy1, x1, y1, r, g, b, a);
4213  SET_TEXTURED_VERTEX_UNINDEXED(dx2, dy1, x2, y1, r, g, b, a);
4214  SET_TEXTURED_VERTEX_UNINDEXED(dx2, dy2, x2, y2, r, g, b, a);
4215  SET_TEXTURED_VERTEX_UNINDEXED(dx1, dy2, x1, y2, r, g, b, a);
4216 
4217  // 6 Triangle indices
4218  SET_INDEXED_VERTEX(0);
4219  SET_INDEXED_VERTEX(1);
4220  SET_INDEXED_VERTEX(2);
4221 
4222  SET_INDEXED_VERTEX(0);
4223  SET_INDEXED_VERTEX(2);
4224  SET_INDEXED_VERTEX(3);
4225 
4226  cdata->blit_buffer_num_vertices += GPU_BLIT_BUFFER_VERTICES_PER_SPRITE;
4227 }
4228 
4229 
4230 static void BlitRotate(GPU_Renderer* renderer, GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y, float degrees)
4231 {
4232  float w, h;
4233  if(image == NULL)
4234  {
4235  GPU_PushErrorCode("GPU_BlitRotate", GPU_ERROR_NULL_ARGUMENT, "image");
4236  return;
4237  }
4238  if(target == NULL)
4239  {
4240  GPU_PushErrorCode("GPU_BlitRotate", GPU_ERROR_NULL_ARGUMENT, "target");
4241  return;
4242  }
4243 
4244  w = (src_rect == NULL? image->w : src_rect->w);
4245  h = (src_rect == NULL? image->h : src_rect->h);
4246  renderer->impl->BlitTransformX(renderer, image, src_rect, target, x, y, w*image->anchor_x, h*image->anchor_y, degrees, 1.0f, 1.0f);
4247 }
4248 
4249 static void BlitScale(GPU_Renderer* renderer, GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y, float scaleX, float scaleY)
4250 {
4251  float w, h;
4252  if(image == NULL)
4253  {
4254  GPU_PushErrorCode("GPU_BlitScale", GPU_ERROR_NULL_ARGUMENT, "image");
4255  return;
4256  }
4257  if(target == NULL)
4258  {
4259  GPU_PushErrorCode("GPU_BlitScale", GPU_ERROR_NULL_ARGUMENT, "target");
4260  return;
4261  }
4262 
4263  w = (src_rect == NULL? image->w : src_rect->w);
4264  h = (src_rect == NULL? image->h : src_rect->h);
4265  renderer->impl->BlitTransformX(renderer, image, src_rect, target, x, y, w*image->anchor_x, h*image->anchor_y, 0.0f, scaleX, scaleY);
4266 }
4267 
4268 static void BlitTransform(GPU_Renderer* renderer, GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y, float degrees, float scaleX, float scaleY)
4269 {
4270  float w, h;
4271  if(image == NULL)
4272  {
4273  GPU_PushErrorCode("GPU_BlitTransform", GPU_ERROR_NULL_ARGUMENT, "image");
4274  return;
4275  }
4276  if(target == NULL)
4277  {
4278  GPU_PushErrorCode("GPU_BlitTransform", GPU_ERROR_NULL_ARGUMENT, "target");
4279  return;
4280  }
4281 
4282  w = (src_rect == NULL? image->w : src_rect->w);
4283  h = (src_rect == NULL? image->h : src_rect->h);
4284  renderer->impl->BlitTransformX(renderer, image, src_rect, target, x, y, w*image->anchor_x, h*image->anchor_y, degrees, scaleX, scaleY);
4285 }
4286 
4287 static void BlitTransformX(GPU_Renderer* renderer, GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y, float pivot_x, float pivot_y, float degrees, float scaleX, float scaleY)
4288 {
4289  Uint32 tex_w, tex_h;
4290  float x1, y1, x2, y2;
4291  float dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4;
4292  float w, h;
4293  GPU_CONTEXT_DATA* cdata;
4294  float* blit_buffer;
4295  unsigned short* index_buffer;
4296  unsigned short blit_buffer_starting_index;
4297  int vert_index;
4298  int tex_index;
4299  int color_index;
4300  float r, g, b, a;
4301 
4302  if(image == NULL)
4303  {
4304  GPU_PushErrorCode("GPU_BlitTransformX", GPU_ERROR_NULL_ARGUMENT, "image");
4305  return;
4306  }
4307  if(target == NULL)
4308  {
4309  GPU_PushErrorCode("GPU_BlitTransformX", GPU_ERROR_NULL_ARGUMENT, "target");
4310  return;
4311  }
4312  if(renderer != image->renderer || renderer != target->renderer)
4313  {
4314  GPU_PushErrorCode("GPU_BlitTransformX", GPU_ERROR_USER_ERROR, "Mismatched renderer");
4315  return;
4316  }
4317 
4318 
4319  makeContextCurrent(renderer, target);
4320 
4321  prepareToRenderToTarget(renderer, target);
4322  prepareToRenderImage(renderer, target, image);
4323 
4324  // Bind the texture to which subsequent calls refer
4325  bindTexture(renderer, image);
4326 
4327  // Bind the FBO
4328  if(!bindFramebuffer(renderer, target))
4329  {
4330  GPU_PushErrorCode("GPU_BlitTransformX", GPU_ERROR_BACKEND_ERROR, "Failed to bind framebuffer.");
4331  return;
4332  }
4333 
4334  tex_w = image->texture_w;
4335  tex_h = image->texture_h;
4336 
4338  {
4339  // Avoid rounding errors in texture sampling by insisting on integral pixel positions
4340  x = floorf(x);
4341  y = floorf(y);
4342  }
4343 
4344  /*
4345  1,1 --- 3,3
4346  | |
4347  | |
4348  4,4 --- 2,2
4349  */
4350  if(src_rect == NULL)
4351  {
4352  // Scale tex coords according to actual texture dims
4353  x1 = 0.0f;
4354  y1 = 0.0f;
4355  x2 = ((float)image->w)/tex_w;
4356  y2 = ((float)image->h)/tex_h;
4357  w = image->w;
4358  h = image->h;
4359  }
4360  else
4361  {
4362  // Scale src_rect tex coords according to actual texture dims
4363  x1 = src_rect->x/(float)tex_w;
4364  y1 = src_rect->y/(float)tex_h;
4365  x2 = (src_rect->x + src_rect->w)/(float)tex_w;
4366  y2 = (src_rect->y + src_rect->h)/(float)tex_h;
4367  w = src_rect->w;
4368  h = src_rect->h;
4369  }
4370 
4371  if(image->using_virtual_resolution)
4372  {
4373  // Scale texture coords to fit the original dims
4374  x1 *= image->base_w/(float)image->w;
4375  y1 *= image->base_h/(float)image->h;
4376  x2 *= image->base_w/(float)image->w;
4377  y2 *= image->base_h/(float)image->h;
4378  }
4379 
4380  // Create vertices about the anchor
4381  dx1 = -pivot_x;
4382  dy1 = -pivot_y;
4383  dx2 = w - pivot_x;
4384  dy2 = h - pivot_y;
4385 
4387  {
4388  // This is a little weird for rotating sprites, but oh well.
4389  float fractional;
4390  fractional = w/2.0f - floorf(w/2.0f);
4391  dx1 += fractional;
4392  dx2 += fractional;
4393  fractional = h/2.0f - floorf(h/2.0f);
4394  dy1 += fractional;
4395  dy2 += fractional;
4396  }
4397 
4398  if(renderer->coordinate_mode == 1)
4399  {
4400  float temp = dy1;
4401  dy1 = dy2;
4402  dy2 = temp;
4403  }
4404 
4405  // Apply transforms
4406 
4407  // Scale about the anchor
4408  if(scaleX != 1.0f || scaleY != 1.0f)
4409  {
4410  dx1 *= scaleX;
4411  dy1 *= scaleY;
4412  dx2 *= scaleX;
4413  dy2 *= scaleY;
4414  }
4415 
4416  // Get extra vertices for rotation
4417  dx3 = dx2;
4418  dy3 = dy1;
4419  dx4 = dx1;
4420  dy4 = dy2;
4421 
4422  // Rotate about the anchor
4423  if(degrees != 0.0f)
4424  {
4425  float cosA = cos(degrees*M_PI/180);
4426  float sinA = sin(degrees*M_PI/180);
4427  float tempX = dx1;
4428  dx1 = dx1*cosA - dy1*sinA;
4429  dy1 = tempX*sinA + dy1*cosA;
4430  tempX = dx2;
4431  dx2 = dx2*cosA - dy2*sinA;
4432  dy2 = tempX*sinA + dy2*cosA;
4433  tempX = dx3;
4434  dx3 = dx3*cosA - dy3*sinA;
4435  dy3 = tempX*sinA + dy3*cosA;
4436  tempX = dx4;
4437  dx4 = dx4*cosA - dy4*sinA;
4438  dy4 = tempX*sinA + dy4*cosA;
4439  }
4440 
4441  // Translate to final position
4442  dx1 += x;
4443  dx2 += x;
4444  dx3 += x;
4445  dx4 += x;
4446  dy1 += y;
4447  dy2 += y;
4448  dy3 += y;
4449  dy4 += y;
4450 
4451  cdata = (GPU_CONTEXT_DATA*)renderer->current_context_target->context->data;
4452 
4453  if(cdata->blit_buffer_num_vertices + 4 >= cdata->blit_buffer_max_num_vertices)
4454  {
4455  if(!growBlitBuffer(cdata, cdata->blit_buffer_num_vertices + 4))
4456  renderer->impl->FlushBlitBuffer(renderer);
4457  }
4458  if(cdata->index_buffer_num_vertices + 6 >= cdata->index_buffer_max_num_vertices)
4459  {
4460  if(!growIndexBuffer(cdata, cdata->index_buffer_num_vertices + 6))
4461  renderer->impl->FlushBlitBuffer(renderer);
4462  }
4463 
4464  blit_buffer = cdata->blit_buffer;
4465  index_buffer = cdata->index_buffer;
4466 
4467  blit_buffer_starting_index = cdata->blit_buffer_num_vertices;
4468 
4469  vert_index = GPU_BLIT_BUFFER_VERTEX_OFFSET + cdata->blit_buffer_num_vertices*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4470  tex_index = GPU_BLIT_BUFFER_TEX_COORD_OFFSET + cdata->blit_buffer_num_vertices*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4471  color_index = GPU_BLIT_BUFFER_COLOR_OFFSET + cdata->blit_buffer_num_vertices*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4472 
4473  if(target->use_color)
4474  {
4475  r = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.r, image->color.r);
4476  g = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.g, image->color.g);
4477  b = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.b, image->color.b);
4479  }
4480  else
4481  {
4482  r = image->color.r/255.0f;
4483  g = image->color.g/255.0f;
4484  b = image->color.b/255.0f;
4485  a = GET_ALPHA(image->color)/255.0f;
4486  }
4487 
4488  // 4 Quad vertices
4489  SET_TEXTURED_VERTEX_UNINDEXED(dx1, dy1, x1, y1, r, g, b, a);
4490  SET_TEXTURED_VERTEX_UNINDEXED(dx3, dy3, x2, y1, r, g, b, a);
4491  SET_TEXTURED_VERTEX_UNINDEXED(dx2, dy2, x2, y2, r, g, b, a);
4492  SET_TEXTURED_VERTEX_UNINDEXED(dx4, dy4, x1, y2, r, g, b, a);
4493 
4494  // 6 Triangle indices
4495  SET_INDEXED_VERTEX(0);
4496  SET_INDEXED_VERTEX(1);
4497  SET_INDEXED_VERTEX(2);
4498 
4499  SET_INDEXED_VERTEX(0);
4500  SET_INDEXED_VERTEX(2);
4501  SET_INDEXED_VERTEX(3);
4502 
4503  cdata->blit_buffer_num_vertices += GPU_BLIT_BUFFER_VERTICES_PER_SPRITE;
4504 }
4505 
4506 
4507 
4508 #ifdef SDL_GPU_USE_BUFFER_PIPELINE
4509 
4510 
4511 static_inline int sizeof_GPU_type(GPU_TypeEnum type)
4512 {
4513  if(type == GPU_TYPE_DOUBLE) return sizeof(double);
4514  if(type == GPU_TYPE_FLOAT) return sizeof(float);
4515  if(type == GPU_TYPE_INT) return sizeof(int);
4516  if(type == GPU_TYPE_UNSIGNED_INT) return sizeof(unsigned int);
4517  if(type == GPU_TYPE_SHORT) return sizeof(short);
4518  if(type == GPU_TYPE_UNSIGNED_SHORT) return sizeof(unsigned short);
4519  if(type == GPU_TYPE_BYTE) return sizeof(char);
4520  if(type == GPU_TYPE_UNSIGNED_BYTE) return sizeof(unsigned char);
4521  return 0;
4522 }
4523 
4524 static void refresh_attribute_data(GPU_CONTEXT_DATA* cdata)
4525 {
4526  int i;
4527  for(i = 0; i < 16; i++)
4528  {
4529  GPU_AttributeSource* a = &cdata->shader_attributes[i];
4530  if(a->attribute.values != NULL && a->attribute.location >= 0 && a->num_values > 0 && a->attribute.format.is_per_sprite)
4531  {
4532  // Expand the values to 4 vertices
4533  int n;
4534  void* storage_ptr = a->per_vertex_storage;
4535  void* values_ptr = (void*)((char*)a->attribute.values + a->attribute.format.offset_bytes);
4536  int value_size_bytes = a->attribute.format.num_elems_per_value * sizeof_GPU_type(a->attribute.format.type);
4537  for(n = 0; n < a->num_values; n+=4)
4538  {
4539  memcpy(storage_ptr, values_ptr, value_size_bytes);
4540  storage_ptr = (void*)((char*)storage_ptr + a->per_vertex_storage_stride_bytes);
4541  memcpy(storage_ptr, values_ptr, value_size_bytes);
4542  storage_ptr = (void*)((char*)storage_ptr + a->per_vertex_storage_stride_bytes);
4543  memcpy(storage_ptr, values_ptr, value_size_bytes);
4544  storage_ptr = (void*)((char*)storage_ptr + a->per_vertex_storage_stride_bytes);
4545  memcpy(storage_ptr, values_ptr, value_size_bytes);
4546  storage_ptr = (void*)((char*)storage_ptr + a->per_vertex_storage_stride_bytes);
4547 
4548  values_ptr = (void*)((char*)values_ptr + a->attribute.format.stride_bytes);
4549  }
4550  }
4551  }
4552 }
4553 
4554 static void upload_attribute_data(GPU_CONTEXT_DATA* cdata, int num_vertices)
4555 {
4556  int i;
4557  for(i = 0; i < 16; i++)
4558  {
4559  GPU_AttributeSource* a = &cdata->shader_attributes[i];
4560  if(a->attribute.values != NULL && a->attribute.location >= 0 && a->num_values > 0)
4561  {
4562  int num_values_used = num_vertices;
4563  int bytes_used;
4564 
4565  if(a->num_values < num_values_used)
4566  num_values_used = a->num_values;
4567 
4568  glBindBuffer(GL_ARRAY_BUFFER, cdata->attribute_VBO[i]);
4569 
4570  bytes_used = a->per_vertex_storage_stride_bytes * num_values_used;
4571  glBufferData(GL_ARRAY_BUFFER, bytes_used, a->next_value, GL_STREAM_DRAW);
4572 
4575 
4576  a->enabled = GPU_TRUE;
4577  // Move the data along so we use the next values for the next flush
4578  a->num_values -= num_values_used;
4579  if(a->num_values <= 0)
4581  else
4582  a->next_value = (void*)(((char*)a->next_value) + bytes_used);
4583  }
4584  }
4585 }
4586 
4587 static void disable_attribute_data(GPU_CONTEXT_DATA* cdata)
4588 {
4589  int i;
4590  for(i = 0; i < 16; i++)
4591  {
4592  GPU_AttributeSource* a = &cdata->shader_attributes[i];
4593  if(a->enabled)
4594  {
4596  a->enabled = GPU_FALSE;
4597  }
4598  }
4599 }
4600 
4601 #endif
4602 
4603 static int get_lowest_attribute_num_values(GPU_CONTEXT_DATA* cdata, int cap)
4604 {
4605  int lowest = cap;
4606 
4607 #ifdef SDL_GPU_USE_BUFFER_PIPELINE
4608  int i;
4609  for(i = 0; i < 16; i++)
4610  {
4611  GPU_AttributeSource* a = &cdata->shader_attributes[i];
4612  if(a->attribute.values != NULL && a->attribute.location >= 0)
4613  {
4614  if(a->num_values < lowest)
4615  lowest = a->num_values;
4616  }
4617  }
4618 #endif
4619 
4620  return lowest;
4621 }
4622 
4623 static_inline void submit_buffer_data(int bytes, float* values, int bytes_indices, unsigned short* indices)
4624 {
4625  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
4626  #if defined(SDL_GPU_USE_BUFFER_RESET)
4627  glBufferData(GL_ARRAY_BUFFER, bytes, values, GL_STREAM_DRAW);
4628  if(indices != NULL)
4629  glBufferData(GL_ELEMENT_ARRAY_BUFFER, bytes_indices, indices, GL_DYNAMIC_DRAW);
4630  #elif defined(SDL_GPU_USE_BUFFER_MAPPING)
4631  // NOTE: On the Raspberry Pi, you may have to use GL_DYNAMIC_DRAW instead of GL_STREAM_DRAW for buffers to work with glMapBuffer().
4632  float* data = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
4633  unsigned short* data_i = (indices == NULL? NULL : (unsigned short*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY));
4634  if(data != NULL)
4635  {
4636  memcpy(data, values, bytes);
4638  }
4639  if(data_i != NULL)
4640  {
4641  memcpy(data_i, indices, bytes_indices);
4642  glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
4643  }
4644  #elif defined(SDL_GPU_USE_BUFFER_UPDATE)
4645  glBufferSubData(GL_ARRAY_BUFFER, 0, bytes, values);
4646  if(indices != NULL)
4647  glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, bytes_indices, indices);
4648  #else
4649  #error "SDL_gpu's VBO upload needs to choose SDL_GPU_USE_BUFFER_RESET, SDL_GPU_USE_BUFFER_MAPPING, or SDL_GPU_USE_BUFFER_UPDATE and none is defined!"
4650  #endif
4651  #endif
4652 }
4653 
4654 
4655 static void SetAttributefv(GPU_Renderer* renderer, int location, int num_elements, float* value);
4656 
4657 // Assumes the right format
4658 static void TriangleBatchX(GPU_Renderer* renderer, GPU_Image* image, GPU_Target* target, unsigned short num_vertices, void* values, unsigned int num_indices, unsigned short* indices, GPU_BatchFlagEnum flags)
4659 {
4660  GPU_Context* context;
4661  GPU_CONTEXT_DATA* cdata;
4662  intptr_t stride, offset_texcoords, offset_colors;
4663  int size_vertices, size_texcoords, size_colors;
4664 
4665  GPU_bool using_texture = (image != NULL);
4666  GPU_bool use_vertices = (flags & (GPU_BATCH_XY | GPU_BATCH_XYZ));
4667  GPU_bool use_texcoords = (flags & GPU_BATCH_ST);
4668  GPU_bool use_colors = (flags & (GPU_BATCH_RGB | GPU_BATCH_RGBA | GPU_BATCH_RGB8 | GPU_BATCH_RGBA8));
4669  GPU_bool use_byte_colors = (flags & (GPU_BATCH_RGB8 | GPU_BATCH_RGBA8));
4670  GPU_bool use_z = (flags & GPU_BATCH_XYZ);
4671  GPU_bool use_a = (flags & (GPU_BATCH_RGBA | GPU_BATCH_RGBA8));
4672 
4673  if(num_vertices == 0)
4674  return;
4675 
4676  if(target == NULL)
4677  {
4678  GPU_PushErrorCode("GPU_TriangleBatchX", GPU_ERROR_NULL_ARGUMENT, "target");
4679  return;
4680  }
4681  if((image != NULL && renderer != image->renderer) || renderer != target->renderer)
4682  {
4683  GPU_PushErrorCode("GPU_TriangleBatchX", GPU_ERROR_USER_ERROR, "Mismatched renderer");
4684  return;
4685  }
4686 
4687  makeContextCurrent(renderer, target);
4688 
4689  // Bind the texture to which subsequent calls refer
4690  if(using_texture)
4691  bindTexture(renderer, image);
4692 
4693  // Bind the FBO
4694  if(!bindFramebuffer(renderer, target))
4695  {
4696  GPU_PushErrorCode("GPU_TriangleBatchX", GPU_ERROR_BACKEND_ERROR, "Failed to bind framebuffer.");
4697  return;
4698  }
4699 
4700  prepareToRenderToTarget(renderer, target);
4701  if(using_texture)
4702  prepareToRenderImage(renderer, target, image);
4703  else
4704  prepareToRenderShapes(renderer, GL_TRIANGLES);
4705  changeViewport(target);
4706  changeCamera(target);
4707 
4708  if(using_texture)
4709  changeTexturing(renderer, GPU_TRUE);
4710 
4711  setClipRect(renderer, target);
4712 
4713  #ifdef SDL_GPU_APPLY_TRANSFORMS_TO_GL_STACK
4714  if(!IsFeatureEnabled(renderer, GPU_FEATURE_VERTEX_SHADER))
4715  applyTransforms();
4716  #endif
4717 
4718 
4719  context = renderer->current_context_target->context;
4720  cdata = (GPU_CONTEXT_DATA*)context->data;
4721 
4722  renderer->impl->FlushBlitBuffer(renderer);
4723 
4724  if(cdata->index_buffer_num_vertices + num_indices >= cdata->index_buffer_max_num_vertices)
4725  {
4726  growBlitBuffer(cdata, cdata->index_buffer_num_vertices + num_indices);
4727  }
4728  if(cdata->blit_buffer_num_vertices + num_vertices >= cdata->blit_buffer_max_num_vertices)
4729  {
4730  growBlitBuffer(cdata, cdata->blit_buffer_num_vertices + num_vertices);
4731  }
4732 
4733  // Only need to check the blit buffer because of the VBO storage
4734  if(cdata->blit_buffer_num_vertices + num_vertices >= cdata->blit_buffer_max_num_vertices)
4735  {
4736  if(!growBlitBuffer(cdata, cdata->blit_buffer_num_vertices + num_vertices))
4737  {
4738  // Can't do all of these sprites! Only do some of them...
4739  num_vertices = (cdata->blit_buffer_max_num_vertices - cdata->blit_buffer_num_vertices);
4740  }
4741  }
4742  if(cdata->index_buffer_num_vertices + num_indices >= cdata->index_buffer_max_num_vertices)
4743  {
4744  if(!growIndexBuffer(cdata, cdata->index_buffer_num_vertices + num_indices))
4745  {
4746  // Can't do all of these sprites! Only do some of them...
4747  num_indices = (cdata->index_buffer_max_num_vertices - cdata->index_buffer_num_vertices);
4748  }
4749  }
4750 
4751  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
4752  refresh_attribute_data(cdata);
4753  #endif
4754 
4755  if(indices == NULL)
4756  num_indices = num_vertices;
4757 
4758  (void)stride;
4759  (void)offset_texcoords;
4760  (void)offset_colors;
4761  (void)size_vertices;
4762  (void)size_texcoords;
4763  (void)size_colors;
4764 
4765  stride = 0;
4766  offset_texcoords = offset_colors = 0;
4767  size_vertices = size_texcoords = size_colors = 0;
4768 
4769  // Determine stride, size, and offsets
4770  if(use_vertices)
4771  {
4772  if(use_z)
4773  size_vertices = 3;
4774  else
4775  size_vertices = 2;
4776 
4777  stride += size_vertices;
4778 
4779  offset_texcoords = stride;
4780  offset_colors = stride;
4781  }
4782 
4783  if(use_texcoords)
4784  {
4785  size_texcoords = 2;
4786 
4787  stride += size_texcoords;
4788 
4789  offset_colors = stride;
4790  }
4791 
4792  if(use_colors)
4793  {
4794  if(use_a)
4795  size_colors = 4;
4796  else
4797  size_colors = 3;
4798  }
4799 
4800  // Floating point color components (either 3 or 4 floats)
4801  if(use_colors && !use_byte_colors)
4802  {
4803  stride += size_colors;
4804  }
4805 
4806  // Convert offsets to a number of bytes
4807  stride *= sizeof(float);
4808  offset_texcoords *= sizeof(float);
4809  offset_colors *= sizeof(float);
4810 
4811  // Unsigned byte color components (either 3 or 4 bytes)
4812  if(use_colors && use_byte_colors)
4813  {
4814  stride += size_colors;
4815  }
4816 
4817 #ifdef SDL_GPU_USE_ARRAY_PIPELINE
4818 
4819  {
4820  // Enable
4821  if(use_vertices)
4822  glEnableClientState(GL_VERTEX_ARRAY);
4823  if(use_texcoords)
4824  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
4825  if(use_colors)
4826  glEnableClientState(GL_COLOR_ARRAY);
4827 
4828  // Set pointers
4829  if(use_vertices)
4830  glVertexPointer(size_vertices, GL_FLOAT, stride, values);
4831  if(use_texcoords)
4832  glTexCoordPointer(size_texcoords, GL_FLOAT, stride, values + offset_texcoords);
4833  if(use_colors)
4834  {
4835  if(use_byte_colors)
4836  glColorPointer(size_colors, GL_UNSIGNED_BYTE, stride, values + offset_colors);
4837  else
4838  glColorPointer(size_colors, GL_FLOAT, stride, values + offset_colors);
4839  }
4840 
4841  // Upload
4842  if(indices == NULL)
4843  glDrawArrays(GL_TRIANGLES, 0, num_indices);
4844  else
4845  glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, indices);
4846 
4847  // Disable
4848  if(use_colors)
4849  glDisableClientState(GL_COLOR_ARRAY);
4850  if(use_texcoords)
4851  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
4852  if(use_vertices)
4853  glDisableClientState(GL_VERTEX_ARRAY);
4854  }
4855 #endif
4856 
4857 
4858 
4859 #ifdef SDL_GPU_USE_BUFFER_PIPELINE_FALLBACK
4860  if(!IsFeatureEnabled(renderer, GPU_FEATURE_VERTEX_SHADER))
4861 #endif
4862 #ifdef SDL_GPU_USE_FIXED_FUNCTION_PIPELINE
4863  {
4864  if(values != NULL)
4865  {
4866  unsigned int i;
4867  unsigned int index;
4868  float* vertex_pointer = (float*)(values);
4869  float* texcoord_pointer = (float*)((char*)values + offset_texcoords);
4870 
4871  glBegin(GL_TRIANGLES);
4872  for(i = 0; i < num_indices; i++)
4873  {
4874  if(indices == NULL)
4876  else
4877  index = indices[i]*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
4878  if(use_colors)
4879  {
4880  if(use_byte_colors)
4881  {
4882  Uint8* color_pointer = (Uint8*)((char*)values + offset_colors);
4883  glColor4ub(color_pointer[index], color_pointer[index+1], color_pointer[index+2], (use_a? color_pointer[index+3] : 255));
4884  }
4885  else
4886  {
4887  float* color_pointer = (float*)((char*)values + offset_colors);
4888  glColor4f(color_pointer[index], color_pointer[index+1], color_pointer[index+2], (use_a? color_pointer[index+3] : 1.0f));
4889  }
4890  }
4891  if(use_texcoords)
4892  glTexCoord2f( texcoord_pointer[index], texcoord_pointer[index+1] );
4893  if(use_vertices)
4894  glVertex3f( vertex_pointer[index], vertex_pointer[index+1], (use_z? vertex_pointer[index+2] : 0.0f) );
4895  }
4896  glEnd();
4897  }
4898  }
4899 #endif
4900 #ifdef SDL_GPU_USE_BUFFER_PIPELINE_FALLBACK
4901  else
4902 #endif
4903 
4904 
4905 
4906 #ifdef SDL_GPU_USE_BUFFER_PIPELINE
4907  {
4908  // Skip uploads if we have no attribute location
4909  if(context->current_shader_block.position_loc < 0)
4910  use_vertices = GPU_FALSE;
4911  if(context->current_shader_block.texcoord_loc < 0)
4912  use_texcoords = GPU_FALSE;
4913  if(context->current_shader_block.color_loc < 0)
4914  use_colors = GPU_FALSE;
4915 
4916  // Update the vertex array object's buffers
4917  #if !defined(SDL_GPU_NO_VAO)
4918  glBindVertexArray(cdata->blit_VAO);
4919  #endif
4920 
4921  // Upload our modelviewprojection matrix
4923  {
4924  float mvp[16];
4925  float cam_matrix[16];
4927  get_camera_matrix(cam_matrix, cdata->last_camera);
4928 
4929  GPU_MultiplyAndAssign(mvp, cam_matrix);
4930 
4932  }
4933 
4934  if(values != NULL)
4935  {
4936  // Upload blit buffer to a single buffer object
4937  glBindBuffer(GL_ARRAY_BUFFER, cdata->blit_VBO[cdata->blit_VBO_flop]);
4938  cdata->blit_VBO_flop = !cdata->blit_VBO_flop;
4939  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cdata->blit_IBO);
4940 
4941  // Copy the whole blit buffer to the GPU
4942  submit_buffer_data(stride * num_vertices, values, sizeof(unsigned short)*num_indices, indices); // Fills GPU buffer with data.
4943 
4944  // Specify the formatting of the blit buffer
4945  if(use_vertices)
4946  {
4947  glEnableVertexAttribArray(context->current_shader_block.position_loc); // Tell GL to use client-side attribute data
4948  glVertexAttribPointer(context->current_shader_block.position_loc, size_vertices, GL_FLOAT, GL_FALSE, stride, 0); // Tell how the data is formatted
4949  }
4950  if(use_texcoords)
4951  {
4953  glVertexAttribPointer(context->current_shader_block.texcoord_loc, size_texcoords, GL_FLOAT, GL_FALSE, stride, (void*)(offset_texcoords));
4954  }
4955  if(use_colors)
4956  {
4958  if(use_byte_colors)
4959  {
4960  glVertexAttribPointer(context->current_shader_block.color_loc, size_colors, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(offset_colors));
4961  }
4962  else
4963  {
4964  glVertexAttribPointer(context->current_shader_block.color_loc, size_colors, GL_FLOAT, GL_FALSE, stride, (void*)(offset_colors));
4965  }
4966  }
4967  else
4968  {
4969  SDL_Color color = get_complete_mod_color(renderer, target, image);
4970  float default_color[4] = {color.r/255.0f, color.g/255.0f, color.b/255.0f, color.a/255.0f};
4971  SetAttributefv(renderer, context->current_shader_block.color_loc, 4, default_color);
4972  }
4973  }
4974 
4975  upload_attribute_data(cdata, num_indices);
4976 
4977  if(indices == NULL)
4978  glDrawArrays(GL_TRIANGLES, 0, num_indices);
4979  else
4980  glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (void*)0);
4981 
4982  // Disable the vertex arrays again
4983  if(use_vertices)
4985  if(use_texcoords)
4987  if(use_colors)
4989 
4990  disable_attribute_data(cdata);
4991 
4992  #if !defined(SDL_GPU_NO_VAO)
4993  glBindVertexArray(0);
4994  #endif
4995  }
4996 #endif
4997 
4998 
4999  cdata->blit_buffer_num_vertices = 0;
5000  cdata->index_buffer_num_vertices = 0;
5001 
5002  unsetClipRect(renderer, target);
5003 }
5004 
5005 static void GenerateMipmaps(GPU_Renderer* renderer, GPU_Image* image)
5006 {
5007  #ifndef __IPHONEOS__
5008  GLint filter;
5009  if(image == NULL)
5010  return;
5011 
5012  if(image->target != NULL && isCurrentTarget(renderer, image->target))
5013  renderer->impl->FlushBlitBuffer(renderer);
5014  bindTexture(renderer, image);
5015  glGenerateMipmapPROC(GL_TEXTURE_2D);
5016  image->has_mipmaps = GPU_TRUE;
5017 
5018  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &filter);
5019  if(filter == GL_LINEAR)
5020  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
5021  #endif
5022 }
5023 
5024 
5025 
5026 
5027 static GPU_Rect SetClip(GPU_Renderer* renderer, GPU_Target* target, Sint16 x, Sint16 y, Uint16 w, Uint16 h)
5028 {
5029  GPU_Rect r;
5030  if(target == NULL)
5031  {
5032  GPU_Rect r = {0,0,0,0};
5033  return r;
5034  }
5035 
5036  if(isCurrentTarget(renderer, target))
5037  renderer->impl->FlushBlitBuffer(renderer);
5038  target->use_clip_rect = GPU_TRUE;
5039 
5040  r = target->clip_rect;
5041 
5042  target->clip_rect.x = x;
5043  target->clip_rect.y = y;
5044  target->clip_rect.w = w;
5045  target->clip_rect.h = h;
5046 
5047  return r;
5048 }
5049 
5050 static void UnsetClip(GPU_Renderer* renderer, GPU_Target* target)
5051 {
5052  if(target == NULL)
5053  return;
5054 
5055  if(isCurrentTarget(renderer, target))
5056  renderer->impl->FlushBlitBuffer(renderer);
5057  // Leave the clip rect values intact so they can still be useful as storage
5058  target->use_clip_rect = GPU_FALSE;
5059 }
5060 
5061 
5062 
5063 
5064 static void swizzle_for_format(SDL_Color* color, GLenum format, unsigned char pixel[4])
5065 {
5066  switch(format)
5067  {
5068  case GL_LUMINANCE:
5069  color->b = color->g = color->r = pixel[0];
5070  GET_ALPHA(*color) = 255;
5071  break;
5072  case GL_LUMINANCE_ALPHA:
5073  color->b = color->g = color->r = pixel[0];
5074  GET_ALPHA(*color) = pixel[3];
5075  break;
5076  #ifdef GL_BGR
5077  case GL_BGR:
5078  color->b = pixel[0];
5079  color->g = pixel[1];
5080  color->r = pixel[2];
5081  GET_ALPHA(*color) = 255;
5082  break;
5083  #endif
5084  #ifdef GL_BGRA
5085  case GL_BGRA:
5086  color->b = pixel[0];
5087  color->g = pixel[1];
5088  color->r = pixel[2];
5089  GET_ALPHA(*color) = pixel[3];
5090  break;
5091  #endif
5092  #ifdef GL_ABGR
5093  case GL_ABGR:
5094  GET_ALPHA(*color) = pixel[0];
5095  color->b = pixel[1];
5096  color->g = pixel[2];
5097  color->r = pixel[3];
5098  break;
5099  #endif
5100  case GL_ALPHA:
5101  break;
5102  #ifndef SDL_GPU_USE_GLES
5103  case GL_RG:
5104  color->r = pixel[0];
5105  color->g = pixel[1];
5106  color->b = 0;
5107  GET_ALPHA(*color) = 255;
5108  break;
5109  #endif
5110  case GL_RGB:
5111  color->r = pixel[0];
5112  color->g = pixel[1];
5113  color->b = pixel[2];
5114  GET_ALPHA(*color) = 255;
5115  break;
5116  case GL_RGBA:
5117  color->r = pixel[0];
5118  color->g = pixel[1];
5119  color->b = pixel[2];
5120  GET_ALPHA(*color) = pixel[3];
5121  break;
5122  default:
5123  break;
5124  }
5125 }
5126 
5127 static SDL_Color GetPixel(GPU_Renderer* renderer, GPU_Target* target, Sint16 x, Sint16 y)
5128 {
5129  SDL_Color result = {0,0,0,0};
5130  if(target == NULL)
5131  return result;
5132  if(renderer != target->renderer)
5133  return result;
5134  if(x < 0 || y < 0 || x >= target->w || y >= target->h)
5135  return result;
5136 
5137  if(isCurrentTarget(renderer, target))
5138  renderer->impl->FlushBlitBuffer(renderer);
5139  if(bindFramebuffer(renderer, target))
5140  {
5141  unsigned char pixels[4];
5142  GLenum format = ((GPU_TARGET_DATA*)target->data)->format;
5143  glReadPixels(x, y, 1, 1, format, GL_UNSIGNED_BYTE, pixels);
5144 
5145  swizzle_for_format(&result, format, pixels);
5146  }
5147 
5148  return result;
5149 }
5150 
5151 static void SetImageFilter(GPU_Renderer* renderer, GPU_Image* image, GPU_FilterEnum filter)
5152 {
5153  GLenum minFilter, magFilter;
5154 
5155  if(image == NULL)
5156  {
5157  GPU_PushErrorCode("GPU_SetImageFilter", GPU_ERROR_NULL_ARGUMENT, "image");
5158  return;
5159  }
5160  if(renderer != image->renderer)
5161  {
5162  GPU_PushErrorCode("GPU_SetImageFilter", GPU_ERROR_USER_ERROR, "Mismatched renderer");
5163  return;
5164  }
5165 
5166  switch(filter)
5167  {
5168  case GPU_FILTER_NEAREST:
5169  minFilter = GL_NEAREST;
5170  magFilter = GL_NEAREST;
5171  break;
5172  case GPU_FILTER_LINEAR:
5173  if(image->has_mipmaps)
5174  minFilter = GL_LINEAR_MIPMAP_NEAREST;
5175  else
5176  minFilter = GL_LINEAR;
5177 
5178  magFilter = GL_LINEAR;
5179  break;
5181  if(image->has_mipmaps)
5182  minFilter = GL_LINEAR_MIPMAP_LINEAR;
5183  else
5184  minFilter = GL_LINEAR;
5185 
5186  magFilter = GL_LINEAR;
5187  break;
5188  default:
5189  GPU_PushErrorCode("GPU_SetImageFilter", GPU_ERROR_USER_ERROR, "Unsupported value for filter (0x%x)", filter);
5190  return;
5191  }
5192 
5193  flushBlitBufferIfCurrentTexture(renderer, image);
5194  bindTexture(renderer, image);
5195 
5196  image->filter_mode = filter;
5197 
5198  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
5199  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
5200 }
5201 
5202 static void SetWrapMode(GPU_Renderer* renderer, GPU_Image* image, GPU_WrapEnum wrap_mode_x, GPU_WrapEnum wrap_mode_y)
5203 {
5204  GLenum wrap_x, wrap_y;
5205 
5206  if(image == NULL)
5207  {
5208  GPU_PushErrorCode("GPU_SetWrapMode", GPU_ERROR_NULL_ARGUMENT, "image");
5209  return;
5210  }
5211  if(renderer != image->renderer)
5212  {
5213  GPU_PushErrorCode("GPU_SetWrapMode", GPU_ERROR_USER_ERROR, "Mismatched renderer");
5214  return;
5215  }
5216 
5217  switch(wrap_mode_x)
5218  {
5219  case GPU_WRAP_NONE:
5220  wrap_x = GL_CLAMP_TO_EDGE;
5221  break;
5222  case GPU_WRAP_REPEAT:
5223  wrap_x = GL_REPEAT;
5224  break;
5225  case GPU_WRAP_MIRRORED:
5226  if(renderer->enabled_features & GPU_FEATURE_WRAP_REPEAT_MIRRORED)
5227  wrap_x = GL_MIRRORED_REPEAT;
5228  else
5229  {
5230  GPU_PushErrorCode("GPU_SetWrapMode", GPU_ERROR_BACKEND_ERROR, "This renderer does not support GPU_WRAP_MIRRORED.");
5231  return;
5232  }
5233  break;
5234  default:
5235  GPU_PushErrorCode("GPU_SetWrapMode", GPU_ERROR_USER_ERROR, "Unsupported value for wrap_mode_x (0x%x)", wrap_mode_x);
5236  return;
5237  }
5238 
5239  switch(wrap_mode_y)
5240  {
5241  case GPU_WRAP_NONE:
5242  wrap_y = GL_CLAMP_TO_EDGE;
5243  break;
5244  case GPU_WRAP_REPEAT:
5245  wrap_y = GL_REPEAT;
5246  break;
5247  case GPU_WRAP_MIRRORED:
5248  if(renderer->enabled_features & GPU_FEATURE_WRAP_REPEAT_MIRRORED)
5249  wrap_y = GL_MIRRORED_REPEAT;
5250  else
5251  {
5252  GPU_PushErrorCode("GPU_SetWrapMode", GPU_ERROR_BACKEND_ERROR, "This renderer does not support GPU_WRAP_MIRRORED.");
5253  return;
5254  }
5255  break;
5256  default:
5257  GPU_PushErrorCode("GPU_SetWrapMode", GPU_ERROR_USER_ERROR, "Unsupported value for wrap_mode_y (0x%x)", wrap_mode_y);
5258  return;
5259  }
5260 
5261  flushBlitBufferIfCurrentTexture(renderer, image);
5262  bindTexture(renderer, image);
5263 
5264  image->wrap_mode_x = wrap_mode_x;
5265  image->wrap_mode_y = wrap_mode_y;
5266 
5267  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_x );
5268  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_y );
5269 }
5270 
5271 
5272 
5273 
5274 
5275 static void ClearRGBA(GPU_Renderer* renderer, GPU_Target* target, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
5276 {
5277  if(target == NULL)
5278  return;
5279  if(renderer != target->renderer)
5280  return;
5281 
5282  makeContextCurrent(renderer, target);
5283 
5284  if(isCurrentTarget(renderer, target))
5285  renderer->impl->FlushBlitBuffer(renderer);
5286  if(bindFramebuffer(renderer, target))
5287  {
5288  setClipRect(renderer, target);
5289 
5290  glClearColor(r/255.0f, g/255.0f, b/255.0f, a/255.0f);
5291  glClear(GL_COLOR_BUFFER_BIT);
5292 
5293  unsetClipRect(renderer, target);
5294  }
5295 }
5296 
5297 static void DoPartialFlush(GPU_Renderer* renderer, GPU_Target* dest, GPU_Context* context, unsigned short num_vertices, float* blit_buffer, unsigned int num_indices, unsigned short* index_buffer)
5298 {
5299  GPU_CONTEXT_DATA* cdata = (GPU_CONTEXT_DATA*)context->data;
5300  (void)renderer;
5301 #ifdef SDL_GPU_USE_ARRAY_PIPELINE
5302  glEnableClientState(GL_VERTEX_ARRAY);
5303  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
5304  glEnableClientState(GL_COLOR_ARRAY);
5305 
5306  glVertexPointer(2, GL_FLOAT, GPU_BLIT_BUFFER_STRIDE, blit_buffer + GPU_BLIT_BUFFER_VERTEX_OFFSET);
5307  glTexCoordPointer(2, GL_FLOAT, GPU_BLIT_BUFFER_STRIDE, blit_buffer + GPU_BLIT_BUFFER_TEX_COORD_OFFSET);
5308  glColorPointer(4, GL_FLOAT, GPU_BLIT_BUFFER_STRIDE, blit_buffer + GPU_BLIT_BUFFER_COLOR_OFFSET);
5309 
5310  glDrawElements(cdata->last_shape, num_indices, GL_UNSIGNED_SHORT, index_buffer);
5311 
5312  glDisableClientState(GL_COLOR_ARRAY);
5313  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
5314  glDisableClientState(GL_VERTEX_ARRAY);
5315 #endif
5316 
5317 
5318 
5319 
5320 #ifdef SDL_GPU_USE_BUFFER_PIPELINE_FALLBACK
5321  if(!IsFeatureEnabled(renderer, GPU_FEATURE_VERTEX_SHADER))
5322 #endif
5323 #ifdef SDL_GPU_USE_FIXED_FUNCTION_PIPELINE
5324  {
5325  unsigned short i;
5326  unsigned int index;
5327  float* vertex_pointer = blit_buffer + GPU_BLIT_BUFFER_VERTEX_OFFSET;
5328  float* texcoord_pointer = blit_buffer + GPU_BLIT_BUFFER_TEX_COORD_OFFSET;
5329  float* color_pointer = blit_buffer + GPU_BLIT_BUFFER_COLOR_OFFSET;
5330 
5331  glBegin(cdata->last_shape);
5332  for(i = 0; i < num_indices; i++)
5333  {
5334  index = index_buffer[i]*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
5335  glColor4f( color_pointer[index], color_pointer[index+1], color_pointer[index+2], color_pointer[index+3] );
5336  glTexCoord2f( texcoord_pointer[index], texcoord_pointer[index+1] );
5337  glVertex3f( vertex_pointer[index], vertex_pointer[index+1], 0.0f );
5338  }
5339  glEnd();
5340 
5341  return;
5342  }
5343 #endif
5344 
5345 
5346 
5347 
5348 #ifdef SDL_GPU_USE_BUFFER_PIPELINE
5349  {
5350  // Update the vertex array object's buffers
5351  #if !defined(SDL_GPU_NO_VAO)
5352  glBindVertexArray(cdata->blit_VAO);
5353  #endif
5354 
5355  // Upload our modelviewprojection matrix
5357  {
5358  float p[16];
5359  float mv[16];
5360  float mvp[16];
5361 
5364 
5365  if(dest->use_camera)
5366  {
5367  float cam_matrix[16];
5368  get_camera_matrix(cam_matrix, cdata->last_camera);
5369 
5370  GPU_MultiplyAndAssign(cam_matrix, p);
5371  GPU_MatrixCopy(p, cam_matrix);
5372  }
5373 
5374  // MVP = P * MV
5375  GPU_Multiply4x4(mvp, p, mv);
5376 
5378  }
5379 
5380  // Upload blit buffer to a single buffer object
5381  glBindBuffer(GL_ARRAY_BUFFER, cdata->blit_VBO[cdata->blit_VBO_flop]);
5382  cdata->blit_VBO_flop = !cdata->blit_VBO_flop;
5383  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cdata->blit_IBO);
5384 
5385  // Copy the whole blit buffer to the GPU
5386  submit_buffer_data(GPU_BLIT_BUFFER_STRIDE * num_vertices, blit_buffer, sizeof(unsigned short)*num_indices, index_buffer); // Fills GPU buffer with data.
5387 
5388  // Specify the formatting of the blit buffer
5389  if(context->current_shader_block.position_loc >= 0)
5390  {
5391  glEnableVertexAttribArray(context->current_shader_block.position_loc); // Tell GL to use client-side attribute data
5392  glVertexAttribPointer(context->current_shader_block.position_loc, 2, GL_FLOAT, GL_FALSE, GPU_BLIT_BUFFER_STRIDE, 0); // Tell how the data is formatted
5393  }
5394  if(context->current_shader_block.texcoord_loc >= 0)
5395  {
5397  glVertexAttribPointer(context->current_shader_block.texcoord_loc, 2, GL_FLOAT, GL_FALSE, GPU_BLIT_BUFFER_STRIDE, (void*)(GPU_BLIT_BUFFER_TEX_COORD_OFFSET * sizeof(float)));
5398  }
5399  if(context->current_shader_block.color_loc >= 0)
5400  {
5402  glVertexAttribPointer(context->current_shader_block.color_loc, 4, GL_FLOAT, GL_FALSE, GPU_BLIT_BUFFER_STRIDE, (void*)(GPU_BLIT_BUFFER_COLOR_OFFSET * sizeof(float)));
5403  }
5404 
5405  upload_attribute_data(cdata, num_vertices);
5406 
5407  glDrawElements(cdata->last_shape, num_indices, GL_UNSIGNED_SHORT, (void*)0);
5408 
5409  // Disable the vertex arrays again
5410  if(context->current_shader_block.position_loc >= 0)
5412  if(context->current_shader_block.texcoord_loc >= 0)
5414  if(context->current_shader_block.color_loc >= 0)
5416 
5417  disable_attribute_data(cdata);
5418 
5419  #if !defined(SDL_GPU_NO_VAO)
5420  glBindVertexArray(0);
5421  #endif
5422  }
5423 #endif
5424 }
5425 
5426 static void DoUntexturedFlush(GPU_Renderer* renderer, GPU_Target* dest, GPU_Context* context, unsigned short num_vertices, float* blit_buffer, unsigned int num_indices, unsigned short* index_buffer)
5427 {
5428  GPU_CONTEXT_DATA* cdata = (GPU_CONTEXT_DATA*)context->data;
5429  (void)renderer;
5430 
5431 #ifdef SDL_GPU_USE_ARRAY_PIPELINE
5432  glEnableClientState(GL_VERTEX_ARRAY);
5433  glEnableClientState(GL_COLOR_ARRAY);
5434 
5435  glVertexPointer(2, GL_FLOAT, GPU_BLIT_BUFFER_STRIDE, blit_buffer + GPU_BLIT_BUFFER_VERTEX_OFFSET);
5436  glColorPointer(4, GL_FLOAT, GPU_BLIT_BUFFER_STRIDE, blit_buffer + GPU_BLIT_BUFFER_COLOR_OFFSET);
5437 
5438  glDrawElements(cdata->last_shape, num_indices, GL_UNSIGNED_SHORT, index_buffer);
5439 
5440  glDisableClientState(GL_COLOR_ARRAY);
5441  glDisableClientState(GL_VERTEX_ARRAY);
5442 #endif
5443 
5444 
5445 #ifdef SDL_GPU_USE_BUFFER_PIPELINE_FALLBACK
5446  if(!IsFeatureEnabled(renderer, GPU_FEATURE_VERTEX_SHADER))
5447 #endif
5448 #ifdef SDL_GPU_USE_FIXED_FUNCTION_PIPELINE
5449  {
5450  unsigned short i;
5451  unsigned int index;
5452  float* vertex_pointer = blit_buffer + GPU_BLIT_BUFFER_VERTEX_OFFSET;
5453  float* color_pointer = blit_buffer + GPU_BLIT_BUFFER_COLOR_OFFSET;
5454 
5455  glBegin(cdata->last_shape);
5456  for(i = 0; i < num_indices; i++)
5457  {
5458  index = index_buffer[i]*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX;
5459  glColor4f( color_pointer[index], color_pointer[index+1], color_pointer[index+2], color_pointer[index+3] );
5460  glVertex3f( vertex_pointer[index], vertex_pointer[index+1], 0.0f );
5461  }
5462  glEnd();
5463 
5464  return;
5465  }
5466 #endif
5467 
5468 #ifdef SDL_GPU_USE_BUFFER_PIPELINE
5469  {
5470  // Update the vertex array object's buffers
5471  #if !defined(SDL_GPU_NO_VAO)
5472  glBindVertexArray(cdata->blit_VAO);
5473  #endif
5474 
5475  // Upload our modelviewprojection matrix
5477  {
5478  float p[16];
5479  float mv[16];
5480  float mvp[16];
5481 
5484 
5485  if(dest->use_camera)
5486  {
5487  float cam_matrix[16];
5488  get_camera_matrix(cam_matrix, cdata->last_camera);
5489 
5490  GPU_MultiplyAndAssign(cam_matrix, p);
5491  GPU_MatrixCopy(p, cam_matrix);
5492  }
5493 
5494  // MVP = P * MV
5495  GPU_Multiply4x4(mvp, p, mv);
5496 
5498  }
5499 
5500  // Upload blit buffer to a single buffer object
5501  glBindBuffer(GL_ARRAY_BUFFER, cdata->blit_VBO[cdata->blit_VBO_flop]);
5502  cdata->blit_VBO_flop = !cdata->blit_VBO_flop;
5503  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cdata->blit_IBO);
5504 
5505  // Copy the whole blit buffer to the GPU
5506  submit_buffer_data(GPU_BLIT_BUFFER_STRIDE * num_vertices, blit_buffer, sizeof(unsigned short)*num_indices, index_buffer); // Fills GPU buffer with data.
5507 
5508  // Specify the formatting of the blit buffer
5509  if(context->current_shader_block.position_loc >= 0)
5510  {
5511  glEnableVertexAttribArray(context->current_shader_block.position_loc); // Tell GL to use client-side attribute data
5512  glVertexAttribPointer(context->current_shader_block.position_loc, 2, GL_FLOAT, GL_FALSE, GPU_BLIT_BUFFER_STRIDE, 0); // Tell how the data is formatted
5513  }
5514  if(context->current_shader_block.color_loc >= 0)
5515  {
5517  glVertexAttribPointer(context->current_shader_block.color_loc, 4, GL_FLOAT, GL_FALSE, GPU_BLIT_BUFFER_STRIDE, (void*)(GPU_BLIT_BUFFER_COLOR_OFFSET * sizeof(float)));
5518  }
5519 
5520  upload_attribute_data(cdata, num_vertices);
5521 
5522  glDrawElements(cdata->last_shape, num_indices, GL_UNSIGNED_SHORT, (void*)0);
5523 
5524  // Disable the vertex arrays again
5525  if(context->current_shader_block.position_loc >= 0)
5527  if(context->current_shader_block.color_loc >= 0)
5529 
5530  disable_attribute_data(cdata);
5531 
5532  #if !defined(SDL_GPU_NO_VAO)
5533  glBindVertexArray(0);
5534  #endif
5535  }
5536 #endif
5537 }
5538 
5539 #define MAX(a, b) ((a) > (b)? (a) : (b))
5540 
5541 static void FlushBlitBuffer(GPU_Renderer* renderer)
5542 {
5543  GPU_Context* context;
5544  GPU_CONTEXT_DATA* cdata;
5545  if(renderer->current_context_target == NULL)
5546  return;
5547 
5548  context = renderer->current_context_target->context;
5549  cdata = (GPU_CONTEXT_DATA*)context->data;
5550  if(cdata->blit_buffer_num_vertices > 0 && cdata->last_target != NULL)
5551  {
5552  GPU_Target* dest = cdata->last_target;
5553  int num_vertices;
5554  int num_indices;
5555  float* blit_buffer;
5556  unsigned short* index_buffer;
5557 
5558  changeViewport(dest);
5559  changeCamera(dest);
5560 
5561  applyTexturing(renderer);
5562 
5563  #ifdef SDL_GPU_APPLY_TRANSFORMS_TO_GL_STACK
5564  if(!IsFeatureEnabled(renderer, GPU_FEATURE_VERTEX_SHADER))
5565  applyTransforms();
5566  #endif
5567 
5568  setClipRect(renderer, dest);
5569 
5570  #ifdef SDL_GPU_USE_BUFFER_PIPELINE
5571  refresh_attribute_data(cdata);
5572  #endif
5573 
5574  blit_buffer = cdata->blit_buffer;
5575  index_buffer = cdata->index_buffer;
5576 
5577  if(cdata->last_use_texturing)
5578  {
5579  while(cdata->blit_buffer_num_vertices > 0)
5580  {
5581  num_vertices = MAX(cdata->blit_buffer_num_vertices, get_lowest_attribute_num_values(cdata, cdata->blit_buffer_num_vertices));
5582  num_indices = num_vertices * 3 / 2; // 6 indices per sprite / 4 vertices per sprite = 3/2
5583 
5584  DoPartialFlush(renderer, dest, context, num_vertices, blit_buffer, num_indices, index_buffer);
5585 
5586  cdata->blit_buffer_num_vertices -= num_vertices;
5587  // Move our pointers ahead
5588  blit_buffer += GPU_BLIT_BUFFER_FLOATS_PER_VERTEX*num_vertices;
5589  index_buffer += num_indices;
5590  }
5591  }
5592  else
5593  {
5594  DoUntexturedFlush(renderer, dest, context, cdata->blit_buffer_num_vertices, blit_buffer, cdata->index_buffer_num_vertices, index_buffer);
5595  }
5596 
5597  cdata->blit_buffer_num_vertices = 0;
5598  cdata->index_buffer_num_vertices = 0;
5599 
5600  unsetClipRect(renderer, dest);
5601  }
5602 }
5603 
5604 static void Flip(GPU_Renderer* renderer, GPU_Target* target)
5605 {
5606  renderer->impl->FlushBlitBuffer(renderer);
5607 
5608  if(target != NULL && target->context != NULL)
5609  {
5610  makeContextCurrent(renderer, target);
5611 
5612  #ifdef SDL_GPU_USE_SDL2
5613  SDL_GL_SwapWindow(SDL_GetWindowFromID(renderer->current_context_target->context->windowID));
5614  #else
5615  SDL_GL_SwapBuffers();
5616  #endif
5617  }
5618 
5619  #ifdef SDL_GPU_USE_OPENGL
5620  if(vendor_is_Intel)
5621  apply_Intel_attrib_workaround = GPU_TRUE;
5622  #endif
5623 }
5624 
5625 
5626 
5627 
5628 // Shader API
5629 
5630 
5631 #include <string.h>
5632 
5633 // On some platforms (e.g. Android), it might not be possible to just create a rwops and get the expected #included files.
5634 // To do it, I might want to add an optional argument that specifies a base directory to prepend to #include file names.
5635 
5636 static Uint32 GetShaderSourceSize(const char* filename);
5637 static Uint32 GetShaderSource(const char* filename, char* result);
5638 
5639 static void read_until_end_of_comment(SDL_RWops* rwops, char multiline)
5640 {
5641  char buffer;
5642  while(SDL_RWread(rwops, &buffer, 1, 1) > 0)
5643  {
5644  if(!multiline)
5645  {
5646  if(buffer == '\n')
5647  break;
5648  }
5649  else
5650  {
5651  if(buffer == '*')
5652  {
5653  // If the stream ends at the next character or it is a '/', then we're done.
5654  if(SDL_RWread(rwops, &buffer, 1, 1) <= 0 || buffer == '/')
5655  break;
5656  }
5657  }
5658  }
5659 }
5660 
5661 static Uint32 GetShaderSourceSize_RW(SDL_RWops* shader_source)
5662 {
5663  Uint32 size;
5664  char last_char;
5665  char buffer[512];
5666  long len;
5667 
5668  if(shader_source == NULL)
5669  return 0;
5670 
5671  size = 0;
5672 
5673  // Read 1 byte at a time until we reach the end
5674  last_char = ' ';
5675  len = 0;
5676  while((len = SDL_RWread(shader_source, &buffer, 1, 1)) > 0)
5677  {
5678  // Follow through an #include directive?
5679  if(buffer[0] == '#')
5680  {
5681  // Get the rest of the line
5682  int line_size = 1;
5683  unsigned long line_len;
5684  char* token;
5685  while((line_len = SDL_RWread(shader_source, buffer+line_size, 1, 1)) > 0)
5686  {
5687  line_size += line_len;
5688  if(buffer[line_size - line_len] == '\n')
5689  break;
5690  }
5691  buffer[line_size] = '\0';
5692 
5693  // Is there "include" after '#'?
5694  token = strtok(buffer, "# \t");
5695 
5696  if(token != NULL && strcmp(token, "include") == 0)
5697  {
5698  // Get filename token
5699  token = strtok(NULL, "\""); // Skip the empty token before the quote
5700  if(token != NULL)
5701  {
5702  // Add the size of the included file and a newline character
5703  size += GetShaderSourceSize(token) + 1;
5704  }
5705  }
5706  else
5707  size += line_size;
5708  last_char = ' ';
5709  continue;
5710  }
5711 
5712  size += len;
5713 
5714  if(last_char == '/')
5715  {
5716  if(buffer[0] == '/')
5717  {
5718  read_until_end_of_comment(shader_source, 0);
5719  size++; // For the end of the comment
5720  }
5721  else if(buffer[0] == '*')
5722  {
5723  read_until_end_of_comment(shader_source, 1);
5724  size += 2; // For the end of the comments
5725  }
5726  last_char = ' ';
5727  }
5728  else
5729  last_char = buffer[0];
5730  }
5731 
5732  // Go back to the beginning of the stream
5733  SDL_RWseek(shader_source, 0, SEEK_SET);
5734  return size;
5735 }
5736 
5737 
5738 static Uint32 GetShaderSource_RW(SDL_RWops* shader_source, char* result)
5739 {
5740  Uint32 size;
5741  char last_char;
5742  char buffer[512];
5743  long len;
5744 
5745  if(shader_source == NULL)
5746  {
5747  result[0] = '\0';
5748  return 0;
5749  }
5750 
5751  size = 0;
5752 
5753  // Read 1 byte at a time until we reach the end
5754  last_char = ' ';
5755  len = 0;
5756  while((len = SDL_RWread(shader_source, &buffer, 1, 1)) > 0)
5757  {
5758  // Follow through an #include directive?
5759  if(buffer[0] == '#')
5760  {
5761  // Get the rest of the line
5762  int line_size = 1;
5763  unsigned long line_len;
5764  char token_buffer[512]; // strtok() is destructive
5765  char* token;
5766  while((line_len = SDL_RWread(shader_source, buffer+line_size, 1, 1)) > 0)
5767  {
5768  line_size += line_len;
5769  if(buffer[line_size - line_len] == '\n')
5770  break;
5771  }
5772 
5773  // Is there "include" after '#'?
5774  memcpy(token_buffer, buffer, line_size+1);
5775  token_buffer[line_size] = '\0';
5776  token = strtok(token_buffer, "# \t");
5777 
5778  if(token != NULL && strcmp(token, "include") == 0)
5779  {
5780  // Get filename token
5781  token = strtok(NULL, "\""); // Skip the empty token before the quote
5782  if(token != NULL)
5783  {
5784  // Add the size of the included file and a newline character
5785  size += GetShaderSource(token, result + size);
5786  result[size] = '\n';
5787  size++;
5788  }
5789  }
5790  else
5791  {
5792  memcpy(result + size, buffer, line_size);
5793  size += line_size;
5794  }
5795  last_char = ' ';
5796  continue;
5797  }
5798 
5799  memcpy(result + size, buffer, len);
5800  size += len;
5801 
5802  if(last_char == '/')
5803  {
5804  if(buffer[0] == '/')
5805  {
5806  read_until_end_of_comment(shader_source, 0);
5807  memcpy(result + size, "\n", 1);
5808  size++;
5809  }
5810  else if(buffer[0] == '*')
5811  {
5812  read_until_end_of_comment(shader_source, 1);
5813  memcpy(result + size, "*/", 2);
5814  size += 2;
5815  }
5816  last_char = ' ';
5817  }
5818  else
5819  last_char = buffer[0];
5820  }
5821  result[size] = '\0';
5822 
5823  // Go back to the beginning of the stream
5824  SDL_RWseek(shader_source, 0, SEEK_SET);
5825  return size;
5826 }
5827 
5828 static Uint32 GetShaderSource(const char* filename, char* result)
5829 {
5830  SDL_RWops* rwops;
5831  Uint32 size;
5832 
5833  if(filename == NULL)
5834  return 0;
5835  rwops = SDL_RWFromFile(filename, "r");
5836 
5837  size = GetShaderSource_RW(rwops, result);
5838 
5839  SDL_RWclose(rwops);
5840  return size;
5841 }
5842 
5843 static Uint32 GetShaderSourceSize(const char* filename)
5844 {
5845  SDL_RWops* rwops;
5846  Uint32 result;
5847 
5848  if(filename == NULL)
5849  return 0;
5850  rwops = SDL_RWFromFile(filename, "r");
5851 
5852  result = GetShaderSourceSize_RW(rwops);
5853 
5854  SDL_RWclose(rwops);
5855  return result;
5856 }
5857 
5858 
5859 static Uint32 compile_shader_source(GPU_ShaderEnum shader_type, const char* shader_source)
5860 {
5861  // Create the proper new shader object
5862  GLuint shader_object = 0;
5863  (void)shader_type;
5864  (void)shader_source;
5865 
5866  #ifndef SDL_GPU_DISABLE_SHADERS
5867  GLint compiled;
5868 
5869  switch(shader_type)
5870  {
5871  case GPU_VERTEX_SHADER:
5872  shader_object = glCreateShader(GL_VERTEX_SHADER);
5873  break;
5874  case GPU_FRAGMENT_SHADER:
5875  shader_object = glCreateShader(GL_FRAGMENT_SHADER);
5876  break;
5877  case GPU_GEOMETRY_SHADER:
5878  #ifdef GL_GEOMETRY_SHADER
5879  shader_object = glCreateShader(GL_GEOMETRY_SHADER);
5880  #else
5881  GPU_PushErrorCode("GPU_CompileShader", GPU_ERROR_BACKEND_ERROR, "Hardware does not support GPU_GEOMETRY_SHADER.");
5882  snprintf(shader_message, 256, "Failed to create geometry shader object.\n");
5883  return 0;
5884  #endif
5885  break;
5886  }
5887 
5888  if(shader_object == 0)
5889  {
5890  GPU_PushErrorCode("GPU_CompileShader", GPU_ERROR_BACKEND_ERROR, "Failed to create new shader object");
5891  snprintf(shader_message, 256, "Failed to create new shader object.\n");
5892  return 0;
5893  }
5894 
5895  glShaderSource(shader_object, 1, &shader_source, NULL);
5896 
5897  // Compile the shader source
5898 
5899  glCompileShader(shader_object);
5900 
5901  glGetShaderiv(shader_object, GL_COMPILE_STATUS, &compiled);
5902  if(!compiled)
5903  {
5904  GPU_PushErrorCode("GPU_CompileShader", GPU_ERROR_DATA_ERROR, "Failed to compile shader source");
5905  glGetShaderInfoLog(shader_object, 256, NULL, shader_message);
5906  glDeleteShader(shader_object);
5907  return 0;
5908  }
5909 
5910  #endif
5911 
5912  return shader_object;
5913 }
5914 
5915 
5916 static Uint32 CompileShader_RW(GPU_Renderer* renderer, GPU_ShaderEnum shader_type, SDL_RWops* shader_source, GPU_bool free_rwops)
5917 {
5918  // Read in the shader source code
5919  Uint32 size = GetShaderSourceSize_RW(shader_source);
5920  char* source_string = (char*)SDL_malloc(size+1);
5921  int result = GetShaderSource_RW(shader_source, source_string);
5922  Uint32 result2;
5923  (void)renderer;
5924 
5925  if(free_rwops)
5926  SDL_RWclose(shader_source);
5927 
5928  if(!result)
5929  {
5930  GPU_PushErrorCode("GPU_CompileShader", GPU_ERROR_DATA_ERROR, "Failed to read shader source");
5931  snprintf(shader_message, 256, "Failed to read shader source.\n");
5932  SDL_free(source_string);
5933  return 0;
5934  }
5935 
5936  result2 = compile_shader_source(shader_type, source_string);
5937  SDL_free(source_string);
5938 
5939  return result2;
5940 }
5941 
5942 static Uint32 CompileShader(GPU_Renderer* renderer, GPU_ShaderEnum shader_type, const char* shader_source)
5943 {
5944  Uint32 size = (Uint32)strlen(shader_source);
5945  SDL_RWops* rwops;
5946  if(size == 0)
5947  return 0;
5948  rwops = SDL_RWFromConstMem(shader_source, size);
5949  return renderer->impl->CompileShader_RW(renderer, shader_type, rwops, 1);
5950 }
5951 
5952 static Uint32 CreateShaderProgram(GPU_Renderer* renderer)
5953 {
5954  #ifndef SDL_GPU_DISABLE_SHADERS
5955  GLuint p;
5956 
5957  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
5958  return 0;
5959 
5960  p = glCreateProgram();
5961 
5962  return p;
5963  #else
5964  (void)renderer;
5965  return 0;
5966  #endif
5967 }
5968 
5969 static GPU_bool LinkShaderProgram(GPU_Renderer* renderer, Uint32 program_object)
5970 {
5971  #ifndef SDL_GPU_DISABLE_SHADERS
5972  int linked;
5973 
5974  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
5975  return GPU_FALSE;
5976 
5977  // Bind the position attribute to location 0.
5978  // We always pass position data (right?), but on some systems (e.g. GL 2 on OS X), color is bound to 0
5979  // and the shader won't run when TriangleBatch uses GPU_BATCH_XY_ST (no color array). Guess they didn't consider default attribute values...
5980  glBindAttribLocation(program_object, 0, "gpu_Vertex");
5981  glLinkProgram(program_object);
5982 
5983  glGetProgramiv(program_object, GL_LINK_STATUS, &linked);
5984 
5985  if(!linked)
5986  {
5987  GPU_PushErrorCode("GPU_LinkShaderProgram", GPU_ERROR_BACKEND_ERROR, "Failed to link shader program");
5988  glGetProgramInfoLog(program_object, 256, NULL, shader_message);
5989  glDeleteProgram(program_object);
5990  return GPU_FALSE;
5991  }
5992 
5993  return GPU_TRUE;
5994 
5995  #else
5996  (void)renderer;
5997  (void)program_object;
5998  return GPU_FALSE;
5999 
6000  #endif
6001 }
6002 
6003 static void FreeShader(GPU_Renderer* renderer, Uint32 shader_object)
6004 {
6005  (void)renderer;
6006  (void)shader_object;
6007  #ifndef SDL_GPU_DISABLE_SHADERS
6008  if(IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6009  glDeleteShader(shader_object);
6010  #endif
6011 }
6012 
6013 static void FreeShaderProgram(GPU_Renderer* renderer, Uint32 program_object)
6014 {
6015  (void)renderer;
6016  (void)program_object;
6017  #ifndef SDL_GPU_DISABLE_SHADERS
6018  if(IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6019  glDeleteProgram(program_object);
6020  #endif
6021 }
6022 
6023 static void AttachShader(GPU_Renderer* renderer, Uint32 program_object, Uint32 shader_object)
6024 {
6025  (void)renderer;
6026  (void)program_object;
6027  (void)shader_object;
6028  #ifndef SDL_GPU_DISABLE_SHADERS
6029  if(IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6030  glAttachShader(program_object, shader_object);
6031  #endif
6032 }
6033 
6034 static void DetachShader(GPU_Renderer* renderer, Uint32 program_object, Uint32 shader_object)
6035 {
6036  (void)renderer;
6037  (void)program_object;
6038  (void)shader_object;
6039  #ifndef SDL_GPU_DISABLE_SHADERS
6040  if(IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6041  glDetachShader(program_object, shader_object);
6042  #endif
6043 }
6044 
6045 static void ActivateShaderProgram(GPU_Renderer* renderer, Uint32 program_object, GPU_ShaderBlock* block)
6046 {
6047  GPU_Target* target = renderer->current_context_target;
6048  (void)block;
6049  #ifndef SDL_GPU_DISABLE_SHADERS
6050  if(IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6051  {
6052  if(program_object == 0) // Implies default shader
6053  {
6054  // Already using a default shader?
6057  return;
6058 
6059  program_object = target->context->default_untextured_shader_program;
6060  }
6061 
6062  renderer->impl->FlushBlitBuffer(renderer);
6063  glUseProgram(program_object);
6064 
6065  {
6066  // Set up our shader attribute and uniform locations
6067  if(block == NULL)
6068  {
6069  if(program_object == target->context->default_textured_shader_program)
6071  else if(program_object == target->context->default_untextured_shader_program)
6073  else
6074  {
6075  GPU_ShaderBlock b;
6076  b.position_loc = -1;
6077  b.texcoord_loc = -1;
6078  b.color_loc = -1;
6079  b.modelViewProjection_loc = -1;
6080  target->context->current_shader_block = b;
6081  }
6082  }
6083  else
6084  target->context->current_shader_block = *block;
6085  }
6086  }
6087  #endif
6088 
6089  target->context->current_shader_program = program_object;
6090 }
6091 
6092 static void DeactivateShaderProgram(GPU_Renderer* renderer)
6093 {
6094  renderer->impl->ActivateShaderProgram(renderer, 0, NULL);
6095 }
6096 
6097 static const char* GetShaderMessage(GPU_Renderer* renderer)
6098 {
6099  (void)renderer;
6100  return shader_message;
6101 }
6102 
6103 static int GetAttributeLocation(GPU_Renderer* renderer, Uint32 program_object, const char* attrib_name)
6104 {
6105  #ifndef SDL_GPU_DISABLE_SHADERS
6106  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6107  return -1;
6108  program_object = get_proper_program_id(renderer, program_object);
6109  if(program_object == 0)
6110  return -1;
6111  return glGetAttribLocation(program_object, attrib_name);
6112  #else
6113  (void)renderer;
6114  (void)program_object;
6115  (void)attrib_name;
6116  return -1;
6117  #endif
6118 }
6119 
6120 static int GetUniformLocation(GPU_Renderer* renderer, Uint32 program_object, const char* uniform_name)
6121 {
6122  #ifndef SDL_GPU_DISABLE_SHADERS
6123  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6124  return -1;
6125  program_object = get_proper_program_id(renderer, program_object);
6126  if(program_object == 0)
6127  return -1;
6128  return glGetUniformLocation(program_object, uniform_name);
6129  #else
6130  (void)renderer;
6131  (void)program_object;
6132  (void)uniform_name;
6133  return -1;
6134  #endif
6135 }
6136 
6137 static GPU_ShaderBlock LoadShaderBlock(GPU_Renderer* renderer, Uint32 program_object, const char* position_name, const char* texcoord_name, const char* color_name, const char* modelViewMatrix_name)
6138 {
6139  GPU_ShaderBlock b;
6140  program_object = get_proper_program_id(renderer, program_object);
6141  if(program_object == 0 || !IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6142  {
6143  b.position_loc = -1;
6144  b.texcoord_loc = -1;
6145  b.color_loc = -1;
6146  b.modelViewProjection_loc = -1;
6147  return b;
6148  }
6149 
6150  if(position_name == NULL)
6151  b.position_loc = -1;
6152  else
6153  b.position_loc = renderer->impl->GetAttributeLocation(renderer, program_object, position_name);
6154 
6155  if(texcoord_name == NULL)
6156  b.texcoord_loc = -1;
6157  else
6158  b.texcoord_loc = renderer->impl->GetAttributeLocation(renderer, program_object, texcoord_name);
6159 
6160  if(color_name == NULL)
6161  b.color_loc = -1;
6162  else
6163  b.color_loc = renderer->impl->GetAttributeLocation(renderer, program_object, color_name);
6164 
6165  if(modelViewMatrix_name == NULL)
6166  b.modelViewProjection_loc = -1;
6167  else
6168  b.modelViewProjection_loc = renderer->impl->GetUniformLocation(renderer, program_object, modelViewMatrix_name);
6169 
6170  return b;
6171 }
6172 
6173 static void SetShaderImage(GPU_Renderer* renderer, GPU_Image* image, int location, int image_unit)
6174 {
6175  // TODO: OpenGL 1 needs to check for ARB_multitexture to use glActiveTexture().
6176  #ifndef SDL_GPU_DISABLE_SHADERS
6177  Uint32 new_texture;
6178 
6179  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6180  return;
6181 
6182  renderer->impl->FlushBlitBuffer(renderer);
6183  if(renderer->current_context_target->context->current_shader_program == 0 || image_unit < 0)
6184  return;
6185 
6186  new_texture = 0;
6187  if(image != NULL)
6188  new_texture = ((GPU_IMAGE_DATA*)image->data)->handle;
6189 
6190  // Set the new image unit
6191  glUniform1i(location, image_unit);
6192  glActiveTexture(GL_TEXTURE0 + image_unit);
6193  glBindTexture(GL_TEXTURE_2D, new_texture);
6194 
6195  if(image_unit != 0)
6197 
6198  #endif
6199 
6200  (void)renderer;
6201  (void)image;
6202  (void)location;
6203  (void)image_unit;
6204 }
6205 
6206 
6207 static void GetUniformiv(GPU_Renderer* renderer, Uint32 program_object, int location, int* values)
6208 {
6209  (void)renderer;
6210  (void)program_object;
6211  (void)location;
6212  (void)values;
6213 
6214  #ifndef SDL_GPU_DISABLE_SHADERS
6215  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6216  return;
6217  program_object = get_proper_program_id(renderer, program_object);
6218  if(program_object != 0)
6219  glGetUniformiv(program_object, location, values);
6220  #endif
6221 }
6222 
6223 static void SetUniformi(GPU_Renderer* renderer, int location, int value)
6224 {
6225  (void)renderer;
6226  (void)location;
6227  (void)value;
6228 
6229  #ifndef SDL_GPU_DISABLE_SHADERS
6230  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6231  return;
6232  renderer->impl->FlushBlitBuffer(renderer);
6234  return;
6235  glUniform1i(location, value);
6236  #endif
6237 }
6238 
6239 static void SetUniformiv(GPU_Renderer* renderer, int location, int num_elements_per_value, int num_values, int* values)
6240 {
6241  (void)renderer;
6242  (void)location;
6243  (void)num_elements_per_value;
6244  (void)num_values;
6245  (void)values;
6246 
6247  #ifndef SDL_GPU_DISABLE_SHADERS
6248  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6249  return;
6250  renderer->impl->FlushBlitBuffer(renderer);
6252  return;
6253  switch(num_elements_per_value)
6254  {
6255  case 1:
6256  glUniform1iv(location, num_values, values);
6257  break;
6258  case 2:
6259  glUniform2iv(location, num_values, values);
6260  break;
6261  case 3:
6262  glUniform3iv(location, num_values, values);
6263  break;
6264  case 4:
6265  glUniform4iv(location, num_values, values);
6266  break;
6267  }
6268  #endif
6269 }
6270 
6271 
6272 static void GetUniformuiv(GPU_Renderer* renderer, Uint32 program_object, int location, unsigned int* values)
6273 {
6274  (void)renderer;
6275  (void)program_object;
6276  (void)location;
6277  (void)values;
6278 
6279  #ifndef SDL_GPU_DISABLE_SHADERS
6280  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6281  return;
6282  program_object = get_proper_program_id(renderer, program_object);
6283  if(program_object != 0)
6284  #if defined(SDL_GPU_USE_GLES) && SDL_GPU_GLES_MAJOR_VERSION < 3
6285  glGetUniformiv(program_object, location, (int*)values);
6286  #else
6287  glGetUniformuiv(program_object, location, values);
6288  #endif
6289  #endif
6290 }
6291 
6292 static void SetUniformui(GPU_Renderer* renderer, int location, unsigned int value)
6293 {
6294  (void)renderer;
6295  (void)location;
6296  (void)value;
6297 
6298  #ifndef SDL_GPU_DISABLE_SHADERS
6299  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6300  return;
6301  renderer->impl->FlushBlitBuffer(renderer);
6303  return;
6304  #if defined(SDL_GPU_USE_GLES) && SDL_GPU_GLES_MAJOR_VERSION < 3
6305  glUniform1i(location, (int)value);
6306  #else
6307  glUniform1ui(location, value);
6308  #endif
6309  #endif
6310 }
6311 
6312 static void SetUniformuiv(GPU_Renderer* renderer, int location, int num_elements_per_value, int num_values, unsigned int* values)
6313 {
6314  (void)renderer;
6315  (void)location;
6316  (void)num_elements_per_value;
6317  (void)num_values;
6318  (void)values;
6319 
6320  #ifndef SDL_GPU_DISABLE_SHADERS
6321  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6322  return;
6323  renderer->impl->FlushBlitBuffer(renderer);
6325  return;
6326  #if defined(SDL_GPU_USE_GLES) && SDL_GPU_GLES_MAJOR_VERSION < 3
6327  switch(num_elements_per_value)
6328  {
6329  case 1:
6330  glUniform1iv(location, num_values, (int*)values);
6331  break;
6332  case 2:
6333  glUniform2iv(location, num_values, (int*)values);
6334  break;
6335  case 3:
6336  glUniform3iv(location, num_values, (int*)values);
6337  break;
6338  case 4:
6339  glUniform4iv(location, num_values, (int*)values);
6340  break;
6341  }
6342  #else
6343  switch(num_elements_per_value)
6344  {
6345  case 1:
6346  glUniform1uiv(location, num_values, values);
6347  break;
6348  case 2:
6349  glUniform2uiv(location, num_values, values);
6350  break;
6351  case 3:
6352  glUniform3uiv(location, num_values, values);
6353  break;
6354  case 4:
6355  glUniform4uiv(location, num_values, values);
6356  break;
6357  }
6358  #endif
6359  #endif
6360 }
6361 
6362 
6363 static void GetUniformfv(GPU_Renderer* renderer, Uint32 program_object, int location, float* values)
6364 {
6365  (void)renderer;
6366  (void)program_object;
6367  (void)location;
6368  (void)values;
6369 
6370  #ifndef SDL_GPU_DISABLE_SHADERS
6371  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6372  return;
6373  program_object = get_proper_program_id(renderer, program_object);
6374  if(program_object != 0)
6375  glGetUniformfv(program_object, location, values);
6376  #endif
6377 }
6378 
6379 static void SetUniformf(GPU_Renderer* renderer, int location, float value)
6380 {
6381  (void)renderer;
6382  (void)location;
6383  (void)value;
6384 
6385  #ifndef SDL_GPU_DISABLE_SHADERS
6386  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6387  return;
6388  renderer->impl->FlushBlitBuffer(renderer);
6390  return;
6391  glUniform1f(location, value);
6392  #endif
6393 }
6394 
6395 static void SetUniformfv(GPU_Renderer* renderer, int location, int num_elements_per_value, int num_values, float* values)
6396 {
6397  (void)renderer;
6398  (void)location;
6399  (void)num_elements_per_value;
6400  (void)num_values;
6401  (void)values;
6402 
6403  #ifndef SDL_GPU_DISABLE_SHADERS
6404  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6405  return;
6406  renderer->impl->FlushBlitBuffer(renderer);
6408  return;
6409  switch(num_elements_per_value)
6410  {
6411  case 1:
6412  glUniform1fv(location, num_values, values);
6413  break;
6414  case 2:
6415  glUniform2fv(location, num_values, values);
6416  break;
6417  case 3:
6418  glUniform3fv(location, num_values, values);
6419  break;
6420  case 4:
6421  glUniform4fv(location, num_values, values);
6422  break;
6423  }
6424  #endif
6425 }
6426 
6427 static void SetUniformMatrixfv(GPU_Renderer* renderer, int location, int num_matrices, int num_rows, int num_columns, GPU_bool transpose, float* values)
6428 {
6429  (void)renderer;
6430  (void)location;
6431  (void)num_matrices;
6432  (void)num_rows;
6433  (void)num_columns;
6434  (void)transpose;
6435  (void)values;
6436 
6437  #ifndef SDL_GPU_DISABLE_SHADERS
6438  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6439  return;
6440  renderer->impl->FlushBlitBuffer(renderer);
6442  return;
6443  if(num_rows < 2 || num_rows > 4 || num_columns < 2 || num_columns > 4)
6444  {
6445  GPU_PushErrorCode("GPU_SetUniformMatrixfv", GPU_ERROR_DATA_ERROR, "Given invalid dimensions (%dx%d)", num_rows, num_columns);
6446  return;
6447  }
6448  #if defined(SDL_GPU_USE_GLES)
6449  // Hide these symbols so it compiles, but make sure they never get called because GLES only supports square matrices.
6450  #define glUniformMatrix2x3fv glUniformMatrix2fv
6451  #define glUniformMatrix2x4fv glUniformMatrix2fv
6452  #define glUniformMatrix3x2fv glUniformMatrix2fv
6453  #define glUniformMatrix3x4fv glUniformMatrix2fv
6454  #define glUniformMatrix4x2fv glUniformMatrix2fv
6455  #define glUniformMatrix4x3fv glUniformMatrix2fv
6456  if(num_rows != num_columns)
6457  {
6458  GPU_PushErrorCode("GPU_SetUniformMatrixfv", GPU_ERROR_DATA_ERROR, "GLES renderers do not accept non-square matrices (given %dx%d)", num_rows, num_columns);
6459  return;
6460  }
6461  #endif
6462 
6463  switch(num_rows)
6464  {
6465  case 2:
6466  if(num_columns == 2)
6467  glUniformMatrix2fv(location, num_matrices, transpose, values);
6468  else if(num_columns == 3)
6469  glUniformMatrix2x3fv(location, num_matrices, transpose, values);
6470  else if(num_columns == 4)
6471  glUniformMatrix2x4fv(location, num_matrices, transpose, values);
6472  break;
6473  case 3:
6474  if(num_columns == 2)
6475  glUniformMatrix3x2fv(location, num_matrices, transpose, values);
6476  else if(num_columns == 3)
6477  glUniformMatrix3fv(location, num_matrices, transpose, values);
6478  else if(num_columns == 4)
6479  glUniformMatrix3x4fv(location, num_matrices, transpose, values);
6480  break;
6481  case 4:
6482  if(num_columns == 2)
6483  glUniformMatrix4x2fv(location, num_matrices, transpose, values);
6484  else if(num_columns == 3)
6485  glUniformMatrix4x3fv(location, num_matrices, transpose, values);
6486  else if(num_columns == 4)
6487  glUniformMatrix4fv(location, num_matrices, transpose, values);
6488  break;
6489  }
6490  #endif
6491 }
6492 
6493 
6494 static void SetAttributef(GPU_Renderer* renderer, int location, float value)
6495 {
6496  (void)renderer;
6497  (void)location;
6498  (void)value;
6499 
6500  #ifndef SDL_GPU_DISABLE_SHADERS
6501  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6502  return;
6503  renderer->impl->FlushBlitBuffer(renderer);
6505  return;
6506 
6507  #ifdef SDL_GPU_USE_OPENGL
6508  if(apply_Intel_attrib_workaround && location == 0)
6509  {
6510  apply_Intel_attrib_workaround = GPU_FALSE;
6511  glBegin(GL_TRIANGLES);
6512  glEnd();
6513  }
6514  #endif
6515 
6516  glVertexAttrib1f(location, value);
6517 
6518  #endif
6519 }
6520 
6521 static void SetAttributei(GPU_Renderer* renderer, int location, int value)
6522 {
6523  (void)renderer;
6524  (void)location;
6525  (void)value;
6526 
6527  #ifndef SDL_GPU_DISABLE_SHADERS
6528  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6529  return;
6530  renderer->impl->FlushBlitBuffer(renderer);
6532  return;
6533 
6534  #ifdef SDL_GPU_USE_OPENGL
6535  if(apply_Intel_attrib_workaround && location == 0)
6536  {
6537  apply_Intel_attrib_workaround = GPU_FALSE;
6538  glBegin(GL_TRIANGLES);
6539  glEnd();
6540  }
6541  #endif
6542 
6543  glVertexAttribI1i(location, value);
6544 
6545  #endif
6546 }
6547 
6548 static void SetAttributeui(GPU_Renderer* renderer, int location, unsigned int value)
6549 {
6550  (void)renderer;
6551  (void)location;
6552  (void)value;
6553 
6554  #ifndef SDL_GPU_DISABLE_SHADERS
6555  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6556  return;
6557  renderer->impl->FlushBlitBuffer(renderer);
6559  return;
6560 
6561  #ifdef SDL_GPU_USE_OPENGL
6562  if(apply_Intel_attrib_workaround && location == 0)
6563  {
6564  apply_Intel_attrib_workaround = GPU_FALSE;
6565  glBegin(GL_TRIANGLES);
6566  glEnd();
6567  }
6568  #endif
6569 
6570  glVertexAttribI1ui(location, value);
6571 
6572  #endif
6573 }
6574 
6575 
6576 static void SetAttributefv(GPU_Renderer* renderer, int location, int num_elements, float* value)
6577 {
6578  (void)renderer;
6579  (void)location;
6580  (void)num_elements;
6581  (void)value;
6582 
6583  #ifndef SDL_GPU_DISABLE_SHADERS
6584  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6585  return;
6586  renderer->impl->FlushBlitBuffer(renderer);
6588  return;
6589 
6590  #ifdef SDL_GPU_USE_OPENGL
6591  if(apply_Intel_attrib_workaround && location == 0)
6592  {
6593  apply_Intel_attrib_workaround = GPU_FALSE;
6594  glBegin(GL_TRIANGLES);
6595  glEnd();
6596  }
6597  #endif
6598 
6599  switch(num_elements)
6600  {
6601  case 1:
6602  glVertexAttrib1f(location, value[0]);
6603  break;
6604  case 2:
6605  glVertexAttrib2f(location, value[0], value[1]);
6606  break;
6607  case 3:
6608  glVertexAttrib3f(location, value[0], value[1], value[2]);
6609  break;
6610  case 4:
6611  glVertexAttrib4f(location, value[0], value[1], value[2], value[3]);
6612  break;
6613  }
6614 
6615  #endif
6616 }
6617 
6618 static void SetAttributeiv(GPU_Renderer* renderer, int location, int num_elements, int* value)
6619 {
6620  (void)renderer;
6621  (void)location;
6622  (void)num_elements;
6623  (void)value;
6624  #ifndef SDL_GPU_DISABLE_SHADERS
6625  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6626  return;
6627  renderer->impl->FlushBlitBuffer(renderer);
6629  return;
6630 
6631  #ifdef SDL_GPU_USE_OPENGL
6632  if(apply_Intel_attrib_workaround && location == 0)
6633  {
6634  apply_Intel_attrib_workaround = GPU_FALSE;
6635  glBegin(GL_TRIANGLES);
6636  glEnd();
6637  }
6638  #endif
6639 
6640  switch(num_elements)
6641  {
6642  case 1:
6643  glVertexAttribI1i(location, value[0]);
6644  break;
6645  case 2:
6646  glVertexAttribI2i(location, value[0], value[1]);
6647  break;
6648  case 3:
6649  glVertexAttribI3i(location, value[0], value[1], value[2]);
6650  break;
6651  case 4:
6652  glVertexAttribI4i(location, value[0], value[1], value[2], value[3]);
6653  break;
6654  }
6655 
6656  #endif
6657 }
6658 
6659 static void SetAttributeuiv(GPU_Renderer* renderer, int location, int num_elements, unsigned int* value)
6660 {
6661  (void)renderer;
6662  (void)location;
6663  (void)num_elements;
6664  (void)value;
6665 
6666  #ifndef SDL_GPU_DISABLE_SHADERS
6667  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6668  return;
6669  renderer->impl->FlushBlitBuffer(renderer);
6671  return;
6672 
6673  #ifdef SDL_GPU_USE_OPENGL
6674  if(apply_Intel_attrib_workaround && location == 0)
6675  {
6676  apply_Intel_attrib_workaround = GPU_FALSE;
6677  glBegin(GL_TRIANGLES);
6678  glEnd();
6679  }
6680  #endif
6681 
6682  switch(num_elements)
6683  {
6684  case 1:
6685  glVertexAttribI1ui(location, value[0]);
6686  break;
6687  case 2:
6688  glVertexAttribI2ui(location, value[0], value[1]);
6689  break;
6690  case 3:
6691  glVertexAttribI3ui(location, value[0], value[1], value[2]);
6692  break;
6693  case 4:
6694  glVertexAttribI4ui(location, value[0], value[1], value[2], value[3]);
6695  break;
6696  }
6697 
6698  #endif
6699 }
6700 
6701 static void SetAttributeSource(GPU_Renderer* renderer, int num_values, GPU_Attribute source)
6702 {
6703  #ifndef SDL_GPU_DISABLE_SHADERS
6704  GPU_CONTEXT_DATA* cdata;
6706 
6707  if(!IsFeatureEnabled(renderer, GPU_FEATURE_BASIC_SHADERS))
6708  return;
6709  if(source.location < 0 || source.location >= 16)
6710  return;
6711 
6712  FlushBlitBuffer(renderer);
6713  cdata = (GPU_CONTEXT_DATA*)renderer->current_context_target->context->data;
6714  a = &cdata->shader_attributes[source.location];
6715  if(source.format.is_per_sprite)
6716  {
6717  int needed_size;
6718 
6720  a->per_vertex_storage_stride_bytes = source.format.num_elems_per_value * sizeof_GPU_type(source.format.type);
6721  a->num_values = 4 * num_values; // 4 vertices now
6722  needed_size = a->num_values * a->per_vertex_storage_stride_bytes;
6723 
6724  // Make sure we have enough room for converted per-vertex data
6725  if(a->per_vertex_storage_size < needed_size)
6726  {
6727  SDL_free(a->per_vertex_storage);
6728  a->per_vertex_storage = SDL_malloc(needed_size);
6729  a->per_vertex_storage_size = needed_size;
6730  }
6731  }
6732  else if(a->per_vertex_storage_size > 0)
6733  {
6734  SDL_free(a->per_vertex_storage);
6735  a->per_vertex_storage = NULL;
6736  a->per_vertex_storage_size = 0;
6737  }
6738 
6739  a->enabled = GPU_FALSE;
6740  a->attribute = source;
6741 
6742  if(!source.format.is_per_sprite)
6743  {
6744  a->per_vertex_storage = source.values;
6745  a->num_values = num_values;
6748  }
6749 
6751 
6752  #endif
6753 
6754  (void)renderer;
6755  (void)num_values;
6756  (void)source;
6757 }
6758 
6759 
6760 
6761 #define SET_COMMON_FUNCTIONS(impl) \
6762  impl->Init = &Init; \
6763  impl->CreateTargetFromWindow = &CreateTargetFromWindow; \
6764  impl->CreateAliasTarget = &CreateAliasTarget; \
6765  impl->MakeCurrent = &MakeCurrent; \
6766  impl->SetAsCurrent = &SetAsCurrent; \
6767  impl->ResetRendererState = &ResetRendererState; \
6768  impl->SetWindowResolution = &SetWindowResolution; \
6769  impl->SetVirtualResolution = &SetVirtualResolution; \
6770  impl->UnsetVirtualResolution = &UnsetVirtualResolution; \
6771  impl->Quit = &Quit; \
6772  \
6773  impl->SetFullscreen = &SetFullscreen; \
6774  impl->SetCamera = &SetCamera; \
6775  \
6776  impl->CreateImage = &CreateImage; \
6777  impl->CreateImageUsingTexture = &CreateImageUsingTexture; \
6778  impl->CreateAliasImage = &CreateAliasImage; \
6779  impl->SaveImage = &SaveImage; \
6780  impl->CopyImage = &CopyImage; \
6781  impl->UpdateImage = &UpdateImage; \
6782  impl->UpdateImageBytes = &UpdateImageBytes; \
6783  impl->ReplaceImage = &ReplaceImage; \
6784  impl->CopyImageFromSurface = &CopyImageFromSurface; \
6785  impl->CopyImageFromTarget = &CopyImageFromTarget; \
6786  impl->CopySurfaceFromTarget = &CopySurfaceFromTarget; \
6787  impl->CopySurfaceFromImage = &CopySurfaceFromImage; \
6788  impl->FreeImage = &FreeImage; \
6789  \
6790  impl->GetTarget = &GetTarget; \
6791  impl->FreeTarget = &FreeTarget; \
6792  \
6793  impl->Blit = &Blit; \
6794  impl->BlitRotate = &BlitRotate; \
6795  impl->BlitScale = &BlitScale; \
6796  impl->BlitTransform = &BlitTransform; \
6797  impl->BlitTransformX = &BlitTransformX; \
6798  impl->TriangleBatchX = &TriangleBatchX; \
6799  \
6800  impl->GenerateMipmaps = &GenerateMipmaps; \
6801  \
6802  impl->SetClip = &SetClip; \
6803  impl->UnsetClip = &UnsetClip; \
6804  \
6805  impl->GetPixel = &GetPixel; \
6806  impl->SetImageFilter = &SetImageFilter; \
6807  impl->SetWrapMode = &SetWrapMode; \
6808  \
6809  impl->ClearRGBA = &ClearRGBA; \
6810  impl->FlushBlitBuffer = &FlushBlitBuffer; \
6811  impl->Flip = &Flip; \
6812  \
6813  impl->CompileShader_RW = &CompileShader_RW; \
6814  impl->CompileShader = &CompileShader; \
6815  impl->CreateShaderProgram = &CreateShaderProgram; \
6816  impl->LinkShaderProgram = &LinkShaderProgram; \
6817  impl->FreeShader = &FreeShader; \
6818  impl->FreeShaderProgram = &FreeShaderProgram; \
6819  impl->AttachShader = &AttachShader; \
6820  impl->DetachShader = &DetachShader; \
6821  impl->ActivateShaderProgram = &ActivateShaderProgram; \
6822  impl->DeactivateShaderProgram = &DeactivateShaderProgram; \
6823  impl->GetShaderMessage = &GetShaderMessage; \
6824  impl->GetAttributeLocation = &GetAttributeLocation; \
6825  impl->GetUniformLocation = &GetUniformLocation; \
6826  impl->LoadShaderBlock = &LoadShaderBlock; \
6827  impl->SetShaderImage = &SetShaderImage; \
6828  impl->GetUniformiv = &GetUniformiv; \
6829  impl->SetUniformi = &SetUniformi; \
6830  impl->SetUniformiv = &SetUniformiv; \
6831  impl->GetUniformuiv = &GetUniformuiv; \
6832  impl->SetUniformui = &SetUniformui; \
6833  impl->SetUniformuiv = &SetUniformuiv; \
6834  impl->GetUniformfv = &GetUniformfv; \
6835  impl->SetUniformf = &SetUniformf; \
6836  impl->SetUniformfv = &SetUniformfv; \
6837  impl->SetUniformMatrixfv = &SetUniformMatrixfv; \
6838  impl->SetAttributef = &SetAttributef; \
6839  impl->SetAttributei = &SetAttributei; \
6840  impl->SetAttributeui = &SetAttributeui; \
6841  impl->SetAttributefv = &SetAttributefv; \
6842  impl->SetAttributeiv = &SetAttributeiv; \
6843  impl->SetAttributeuiv = &SetAttributeuiv; \
6844  impl->SetAttributeSource = &SetAttributeSource; \
6845  \
6846  /* Shape rendering */ \
6847  \
6848  impl->SetLineThickness = &SetLineThickness; \
6849  impl->GetLineThickness = &GetLineThickness; \
6850  impl->Pixel = &Pixel; \
6851  impl->Line = &Line; \
6852  impl->Arc = &Arc; \
6853  impl->ArcFilled = &ArcFilled; \
6854  impl->Circle = &Circle; \
6855  impl->CircleFilled = &CircleFilled; \
6856  impl->Ellipse = &Ellipse; \
6857  impl->EllipseFilled = &EllipseFilled; \
6858  impl->Sector = &Sector; \
6859  impl->SectorFilled = &SectorFilled; \
6860  impl->Tri = &Tri; \
6861  impl->TriFilled = &TriFilled; \
6862  impl->Rectangle = &Rectangle; \
6863  impl->RectangleFilled = &RectangleFilled; \
6864  impl->RectangleRound = &RectangleRound; \
6865  impl->RectangleRoundFilled = &RectangleRoundFilled; \
6866  impl->Polygon = &Polygon; \
6867  impl->PolygonFilled = &PolygonFilled;
6868 
GPU_Image *SDLCALL * CopyImageFromSurface(GPU_Renderer *renderer, SDL_Surface *surface)
#define glVertexAttribI1i
struct GPU_Renderer * renderer
Definition: SDL_gpu.h:405
int minor_version
Definition: SDL_gpu.h:124
Uint16 w
Definition: SDL_gpu.h:409
GPU_Target * context_target
Definition: SDL_gpu.h:269
#define glGetProgramInfoLog
#define glVertexAttribI3ui
DECLSPEC Uint32 SDLCALL GPU_GetInitWindow(void)
Definition: SDL_gpu.c:215
GPU_Target *SDLCALL * CreateTargetFromWindow(GPU_Renderer *renderer, Uint32 windowID, GPU_Target *target)
#define glGenBuffers
void * values
Definition: SDL_gpu.h:581
GPU_FilterEnum
Definition: SDL_gpu.h:193
GPU_FileFormatEnum
Definition: SDL_gpu.h:247
Uint16 base_h
Definition: SDL_gpu.h:276
GPU_WrapEnum
Definition: SDL_gpu.h:216
GPU_BlendFuncEnum dest_alpha
Definition: SDL_gpu.h:164
#define glDeleteShader
DECLSPEC void SDLCALL GPU_MatrixOrtho(float *result, float left, float right, float bottom, float top, float near, float far)
DECLSPEC void SDLCALL GPU_MakeCurrent(GPU_Target *target, Uint32 windowID)
Definition: SDL_gpu.c:497
int location
Definition: SDL_gpu.h:580
static_inline void flushAndClearBlitBufferIfCurrentFramebuffer(GPU_Renderer *renderer, GPU_Target *target)
#define SDL_GPU_GLSL_VERSION
static GLenum GLenum textarget
GPU_BlendEqEnum color_equation
Definition: SDL_gpu.h:166
static_inline void flushAndClearBlitBufferIfCurrentTexture(GPU_Renderer *renderer, GPU_Image *image)
int position_loc
Definition: SDL_gpu.h:319
DECLSPEC GPU_bool SDLCALL GPU_SaveSurface(SDL_Surface *surface, const char *filename, GPU_FileFormatEnum format)
Definition: SDL_gpu.c:1149
#define GPU_BLIT_BUFFER_COLOR_OFFSET
Uint16 base_w
Definition: SDL_gpu.h:276
#define glGetProgramiv
GPU_bool use_clip_rect
Definition: SDL_gpu.h:412
DECLSPEC float *SDLCALL GPU_GetProjection(void)
GPU_RendererID requested_id
Definition: SDL_gpu.h:657
DECLSPEC const char *SDLCALL GPU_GetShaderMessage(void)
Definition: SDL_gpu.c:2215
Uint16 h
Definition: SDL_gpu.h:271
#define glUniform1i
Uint32 windowID
Definition: SDL_gpu.h:355
int drawable_h
Definition: SDL_gpu.h:363
static_inline Uint32 get_window_id(SDL_Surface *window)
GPU_Image *SDLCALL * CreateImage(GPU_Renderer *renderer, Uint16 w, Uint16 h, GPU_FormatEnum format)
GPU_SnapEnum snap_mode
Definition: SDL_gpu.h:287
static_inline Uint32 getPixel(SDL_Surface *Surface, int x, int y)
#define glVertexAttrib1f
DECLSPEC void SDLCALL GPU_SetColor(GPU_Image *image, SDL_Color color)
Definition: SDL_gpu.c:1623
#define GL_VERTEX_SHADER
static_inline GPU_bool get_fullscreen_state(SDL_Window *window)
#define glUniform1f
DECLSPEC GPU_InitFlagEnum SDLCALL GPU_GetPreInitFlags(void)
Definition: SDL_gpu.c:225
GPU_Attribute attribute
Definition: SDL_gpu.h:596
#define glActiveTexture
#define glVertexAttrib4f
GPU_bool enabled
Definition: SDL_gpu.h:588
Uint32 current_shader_program
Definition: SDL_gpu.h:370
float matrix[GPU_MATRIX_STACK_MAX][16]
Definition: SDL_gpu.h:342
#define glDeleteProgram
DECLSPEC void SDLCALL GPU_SetImageFilter(GPU_Image *image, GPU_FilterEnum filter)
Definition: SDL_gpu.c:1895
GPU_Rect viewport
Definition: SDL_gpu.h:417
int per_vertex_storage_size
Definition: SDL_gpu.h:594
GPU_TypeEnum type
Definition: SDL_gpu.h:571
GPU_ShaderBlock default_untextured_shader_block
Definition: SDL_gpu.h:376
#define glDeleteFramebuffers
#define glBufferData
#define GPU_DEFAULT_TEXTURED_VERTEX_SHADER_SOURCE
#define GL_MIRRORED_REPEAT
struct GPU_Renderer * renderer
Definition: SDL_gpu.h:268
#define glVertexAttribI2i
DECLSPEC float *SDLCALL GPU_GetModelView(void)
static_inline void upload_texture(const void *pixels, GPU_Rect update_rect, Uint32 format, int alignment, int row_length, unsigned int pitch, int bytes_per_pixel)
#define glShaderSource
static_inline void upload_new_texture(void *pixels, GPU_Rect update_rect, Uint32 format, int alignment, int row_length, int bytes_per_pixel)
float zoom
Definition: SDL_gpu.h:307
#define GPU_FEATURE_BASIC_SHADERS
Definition: SDL_gpu.h:454
#define glUniform4fv
GPU_RendererID id
Definition: SDL_gpu.h:656
int modelViewProjection_loc
Definition: SDL_gpu.h:323
float line_thickness
Definition: SDL_gpu.h:380
int window_w
Definition: SDL_gpu.h:358
Uint32 GPU_InitFlagEnum
Definition: SDL_gpu.h:466
GPU_MatrixStack modelview_matrix
Definition: SDL_gpu.h:385
SDL_Color color
Definition: SDL_gpu.h:283
#define SDL_GPU_GLES_MAJOR_VERSION
GPU_BlendMode shapes_blend_mode
Definition: SDL_gpu.h:379
DECLSPEC void SDLCALL GPU_SetShaderBlock(GPU_ShaderBlock block)
Definition: SDL_gpu.c:2275
#define glUniform1fv
GPU_bool shapes_use_blending
Definition: SDL_gpu.h:378
DECLSPEC GPU_Target *SDLCALL GPU_GetContextTarget(void)
Definition: SDL_gpu.c:1293
#define glGetAttribLocation
#define glVertexAttrib3f
float w
Definition: SDL_gpu.h:92
int max_shader_version
Definition: SDL_gpu.h:663
#define GL_FRAGMENT_SHADER
#define glGetShaderInfoLog
GPU_BlendFuncEnum source_color
Definition: SDL_gpu.h:161
DECLSPEC void SDLCALL GPU_SetBlending(GPU_Image *image, GPU_bool enable)
Definition: SDL_gpu.c:1726
GPU_WindowFlagEnum SDL_init_flags
Definition: SDL_gpu.h:658
DECLSPEC void SDLCALL GPU_MatrixRotate(float *result, float degrees, float x, float y, float z)
int bytes_per_pixel
Definition: SDL_gpu.h:275
DECLSPEC GPU_FeatureEnum SDLCALL GPU_GetRequiredFeatures(void)
Definition: SDL_gpu.c:235
GPU_bool using_virtual_resolution
Definition: SDL_gpu.h:272
#define SDL_Window
#define GPU_TRUE
Definition: SDL_gpu.h:63
int gpu_strcasecmp(const char *s1, const char *s2)
Definition: SDL_gpu.c:2512
GPU_Target * current_context_target
Definition: SDL_gpu.h:667
#define GPU_BLIT_BUFFER_INIT_MAX_NUM_VERTICES
static_inline void flushAndBindTexture(GPU_Renderer *renderer, GLuint handle)
#define glFramebufferTexture2D
#define glUniformMatrix4fv
#define GPU_IMAGE_DATA
#define glVertexAttribI2ui
#define glUniform2fv
float y
Definition: SDL_gpu.h:91
int refcount
Definition: SDL_gpu.h:292
GPU_bool normalize
Definition: SDL_gpu.h:572
#define GL_TEXTURE0
Uint32 GPU_BatchFlagEnum
Definition: SDL_gpu.h:485
#define glVertexAttribI3i
#define GPU_BLIT_BUFFER_STRIDE
#define glGenFramebuffers
Uint16 base_w
Definition: SDL_gpu.h:411
#define glEnableVertexAttribArray
#define SET_INDEXED_VERTEX(offset)
DECLSPEC void SDLCALL GPU_AddWindowMapping(GPU_Target *target)
Definition: SDL_gpu.c:271
#define glCreateProgram
DECLSPEC void SDLCALL GPU_MultiplyAndAssign(float *result, float *B)
DECLSPEC void SDLCALL GPU_UnsetImageVirtualResolution(GPU_Image *image)
Definition: SDL_gpu.c:589
float x
Definition: SDL_gpu.h:91
#define glVertexAttribPointer
static_inline void get_target_window_dimensions(GPU_Target *target, int *w, int *h)
void * data
Definition: SDL_gpu.h:389
DECLSPEC void SDLCALL GPU_UnsetClip(GPU_Target *target)
Definition: SDL_gpu.c:1550
DECLSPEC void SDLCALL GPU_FreeImage(GPU_Image *image)
Definition: SDL_gpu.c:1284
float x
Definition: SDL_gpu.h:305
static_inline void get_target_drawable_dimensions(GPU_Target *target, int *w, int *h)
#define GPU_TARGET_DATA
#define GPU_DEFAULT_UNTEXTURED_VERTEX_SHADER_SOURCE
const char * name
Definition: SDL_gpu.h:121
DECLSPEC void SDLCALL GPU_GenerateMipmaps(GPU_Image *image)
Definition: SDL_gpu.c:1517
void * context
Definition: SDL_gpu.h:351
static GLenum GLenum GLuint GLint level
#define glUniform4iv
float y
Definition: SDL_gpu.h:305
GPU_FormatEnum
Definition: SDL_gpu.h:226
int stored_window_w
Definition: SDL_gpu.h:366
GPU_bool use_camera
Definition: SDL_gpu.h:421
DECLSPEC void SDLCALL GPU_GetModelViewProjection(float *result)
GPU_bool is_alias
Definition: SDL_gpu.h:426
GPU_AttributeFormat format
Definition: SDL_gpu.h:582
GPU_bool coordinate_mode
Definition: SDL_gpu.h:670
unsigned int size
Definition: SDL_gpu.h:341
#define glVertexAttribI1ui
GPU_MatrixStack projection_matrix
Definition: SDL_gpu.h:384
int stored_window_h
Definition: SDL_gpu.h:367
#define glDisableVertexAttribArray
GPU_bool use_blending
Definition: SDL_gpu.h:284
GPU_bool is_alias
Definition: SDL_gpu.h:293
static GLenum GLenum GLuint texture
Uint16 w
Definition: SDL_gpu.h:271
SDL_Surface *SDLCALL * CopySurfaceFromImage(GPU_Renderer *renderer, GPU_Image *image)
#define SDL_GPU_GLSL_VERSION_CORE
int matrix_mode
Definition: SDL_gpu.h:383
#define GL_FRAMEBUFFER_COMPLETE
#define GET_ALPHA(sdl_color)
int texcoord_loc
Definition: SDL_gpu.h:320
#define glUnmapBuffer
#define SDL_GPU_DISABLE_SHADERS
#define GPU_DEFAULT_TEXTURED_VERTEX_SHADER_SOURCE_CORE
Uint32 GPU_WindowFlagEnum
Definition: SDL_gpu.h:458
GPU_ShaderBlock current_shader_block
Definition: SDL_gpu.h:374
#define GL_LINK_STATUS
#define GPU_DEFAULT_TEXTURED_FRAGMENT_SHADER_SOURCE
GPU_BlendMode blend_mode
Definition: SDL_gpu.h:285
#define SET_TEXTURED_VERTEX_UNINDEXED(x, y, s, t, r, g, b, a)
DECLSPEC void SDLCALL GPU_MatrixTranslate(float *result, float x, float y, float z)
GPU_Target *SDLCALL * GetTarget(GPU_Renderer *renderer, GPU_Image *image)
#define glBlendEquation
#define GL_WRITE_ONLY
#define glCreateShader
static GLuint framebuffer
#define glUseProgram
int major_version
Definition: SDL_gpu.h:123
DECLSPEC void SDLCALL GPU_LogError(const char *format,...)
Definition: SDL_gpu.c:175
#define glGetShaderiv
#define glGetUniformiv
#define MAX(a, b)
float anchor_y
Definition: SDL_gpu.h:281
static_inline void submit_buffer_data(int bytes, float *values, int bytes_indices, unsigned short *indices)
GPU_FilterEnum filter_mode
Definition: SDL_gpu.h:286
int num_layers
Definition: SDL_gpu.h:274
GPU_FormatEnum format
Definition: SDL_gpu.h:273
#define GPU_CONTEXT_DATA
void * per_vertex_storage
Definition: SDL_gpu.h:595
int window_h
Definition: SDL_gpu.h:359
static_inline void fast_upload_texture(const void *pixels, GPU_Rect update_rect, Uint32 format, int alignment, int row_length)
GPU_bool is_per_sprite
Definition: SDL_gpu.h:569
DECLSPEC GPU_bool SDLCALL GPU_GetCoordinateMode(void)
Definition: SDL_gpu.c:105
GPU_InitFlagEnum GPU_init_flags
Definition: SDL_gpu.h:659
static_inline void get_drawable_dimensions(SDL_Window *window, int *w, int *h)
#define MIX_COLOR_COMPONENT(a, b)
Uint32 default_untextured_shader_program
Definition: SDL_gpu.h:372
Uint32 GPU_TypeEnum
Definition: SDL_gpu.h:523
#define GPU_BLIT_BUFFER_ABSOLUTE_MAX_VERTICES
#define GL_COLOR_ATTACHMENT0
#define GLAPIENTRY
GPU_bool failed
Definition: SDL_gpu.h:352
#define glLinkProgram
GPU_WrapEnum wrap_mode_y
Definition: SDL_gpu.h:289
float default_image_anchor_y
Definition: SDL_gpu.h:674
static const GLuint * framebuffers
#define M_PI
#define GPU_MODELVIEW
Definition: SDL_gpu.h:330
static_inline void get_window_dimensions(SDL_Window *window, int *w, int *h)
#define glGenerateMipmap
#define GL_FRAMEBUFFER
static_inline unsigned int getNearestPowerOf2(unsigned int n)
#define glDeleteBuffers
#define glVertexAttribI4ui
static GLenum attachment
static_inline GPU_bool isCurrentTarget(GPU_Renderer *renderer, GPU_Target *target)
void * data
Definition: SDL_gpu.h:408
DECLSPEC void SDLCALL GPU_RemoveWindowMappingByTarget(GPU_Target *target)
Definition: SDL_gpu.c:350
int per_vertex_storage_stride_bytes
Definition: SDL_gpu.h:592
SDL_Color color
Definition: SDL_gpu.h:415
GPU_bool using_virtual_resolution
Definition: SDL_gpu.h:410
DECLSPEC void SDLCALL GPU_UnsetColor(GPU_Image *image)
Definition: SDL_gpu.c:1659
#define glUniform3fv
#define GPU_BLIT_BUFFER_TEX_COORD_OFFSET
GPU_Target * context_target
Definition: SDL_gpu.h:406
SDL_Surface *SDLCALL * CopySurfaceFromTarget(GPU_Renderer *renderer, GPU_Target *target)
#define GPU_BLIT_BUFFER_FLOATS_PER_VERTEX
#define glBlendFuncSeparate
static_inline void flushAndBindFramebuffer(GPU_Renderer *renderer, GLuint handle)
#define glUniform2iv
GPU_BlendEqEnum alpha_equation
Definition: SDL_gpu.h:167
#define glGetUniformLocation
GPU_bool has_mipmaps
Definition: SDL_gpu.h:278
DECLSPEC void SDLCALL GPU_MatrixCopy(float *result, const float *A)
static_inline void resize_window(GPU_Target *target, int w, int h)
int min_shader_version
Definition: SDL_gpu.h:662
GPU_Image * image
Definition: SDL_gpu.h:407
#define glCompileShader
#define glVertexAttrib2f
Uint16 base_h
Definition: SDL_gpu.h:411
#define GPU_DEFAULT_UNTEXTURED_FRAGMENT_SHADER_SOURCE_CORE
GPU_bool use_texturing
Definition: SDL_gpu.h:381
#define GPU_DEFAULT_UNTEXTURED_FRAGMENT_SHADER_SOURCE
int refcount
Definition: SDL_gpu.h:387
#define glBindFramebuffer
#define glCheckFramebufferStatus
struct GPU_RendererImpl * impl
Definition: SDL_gpu.h:676
float anchor_x
Definition: SDL_gpu.h:280
#define static_inline
#define GPU_BLIT_BUFFER_VERTICES_PER_SPRITE
static GLuint * ids
#define glVertexAttribI4i
void * data
Definition: SDL_gpu.h:291
GPU_BlendFuncEnum source_alpha
Definition: SDL_gpu.h:163
#define MIX_COLOR_COMPONENT_NORMALIZED_RESULT(a, b)
DECLSPEC void SDLCALL GPU_MatrixIdentity(float *result)
static_inline void flushBlitBufferIfCurrentTexture(GPU_Renderer *renderer, GPU_Image *image)
#define glAttachShader
#define glUniform1iv
Uint16 texture_w
Definition: SDL_gpu.h:277
#define GPU_FALSE
Definition: SDL_gpu.h:62
DECLSPEC void SDLCALL GPU_SetInitWindow(Uint32 windowID)
Definition: SDL_gpu.c:210
GPU_bool use_color
Definition: SDL_gpu.h:414
float z
Definition: SDL_gpu.h:305
int drawable_w
Definition: SDL_gpu.h:362
GPU_BlendFuncEnum dest_color
Definition: SDL_gpu.h:162
#define GL_ARRAY_BUFFER
DECLSPEC GPU_Rect SDLCALL GPU_MakeRect(float x, float y, float w, float h)
Definition: SDL_gpu.c:822
float default_image_anchor_x
Definition: SDL_gpu.h:673
#define GPU_DEFAULT_TEXTURED_FRAGMENT_SHADER_SOURCE_CORE
DECLSPEC GPU_BlendMode SDLCALL GPU_GetBlendModeFromPreset(GPU_BlendPresetEnum preset)
Definition: SDL_gpu.c:1743
DECLSPEC void SDLCALL GPU_SetWrapMode(GPU_Image *image, GPU_WrapEnum wrap_mode_x, GPU_WrapEnum wrap_mode_y)
Definition: SDL_gpu.c:1964
DECLSPEC void SDLCALL GPU_PushErrorCode(const char *function, GPU_ErrorEnum error, const char *details,...)
Definition: SDL_gpu.c:692
DECLSPEC void SDLCALL GPU_SetSnapMode(GPU_Image *image, GPU_SnapEnum mode)
Definition: SDL_gpu.c:1956
#define SDL_GPU_GL_MAJOR_VERSION
#define glBindBuffer
#define intptr_t
DECLSPEC void SDLCALL GPU_MatrixScale(float *result, float sx, float sy, float sz)
Uint16 texture_h
Definition: SDL_gpu.h:277
DECLSPEC GPU_Camera SDLCALL GPU_GetDefaultCamera(void)
Definition: SDL_gpu.c:867
#define glBlendEquationSeparate
#define GL_COMPILE_STATUS
GPU_FeatureEnum enabled_features
Definition: SDL_gpu.h:664
Uint16 h
Definition: SDL_gpu.h:409
float h
Definition: SDL_gpu.h:92
Uint32 GPU_FeatureEnum
Definition: SDL_gpu.h:434
GPU_Context * context
Definition: SDL_gpu.h:424
DECLSPEC GPU_Target *SDLCALL GPU_GetTarget(GPU_Image *image)
Definition: SDL_gpu.c:1313
float angle
Definition: SDL_gpu.h:306
static_inline GPU_bool has_colorkey(SDL_Surface *surface)
GPU_ShaderEnum
Definition: SDL_gpu.h:545
GPU_Rect clip_rect
Definition: SDL_gpu.h:413
DECLSPEC void SDLCALL GPU_Multiply4x4(float *result, float *A, float *B)
#define GPU_BLIT_BUFFER_VERTEX_OFFSET
GPU_WrapEnum wrap_mode_x
Definition: SDL_gpu.h:288
DECLSPEC void SDLCALL GPU_RemoveWindowMapping(Uint32 windowID)
Definition: SDL_gpu.c:319
#define GL_FRAMEBUFFER_BINDING
GPU_ShaderBlock default_textured_shader_block
Definition: SDL_gpu.h:375
GPU_Target * target
Definition: SDL_gpu.h:270
DECLSPEC GPU_ShaderBlock SDLCALL GPU_LoadShaderBlock(Uint32 program_object, const char *position_name, const char *texcoord_name, const char *color_name, const char *modelViewMatrix_name)
Definition: SDL_gpu.c:2260
static_inline SDL_Window * get_window(Uint32 windowID)
#define glBufferSubData
Uint32 default_textured_shader_program
Definition: SDL_gpu.h:371
GPU_Camera camera
Definition: SDL_gpu.h:420
int refcount
Definition: SDL_gpu.h:425
DECLSPEC void SDLCALL GPU_SetImageVirtualResolution(GPU_Image *image, Uint16 w, Uint16 h)
Definition: SDL_gpu.c:576
#define GPU_bool
Definition: SDL_gpu.h:59
#define glUniform3iv
#define glMapBuffer
static_inline GPU_bool isPowerOfTwo(unsigned int x)
int per_vertex_storage_offset_bytes
Definition: SDL_gpu.h:593
#define GPU_DEFAULT_UNTEXTURED_VERTEX_SHADER_SOURCE_CORE
#define GPU_INDEX_BUFFER_ABSOLUTE_MAX_VERTICES