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