this repo has no description
1#include "SDL_gpu.h"
2#include "SDL_gpu_RendererImpl.h"
3#include "SDL_platform.h"
4#include "stb_image.h"
5#include "stb_image_write.h"
6#include <stdlib.h>
7#include <string.h>
8
9#ifdef __ANDROID__
10#include <android/log.h>
11#endif
12
13#ifdef _MSC_VER
14 #define __func__ __FUNCTION__
15 #pragma warning(push)
16 // Visual Studio wants to complain about while(0)
17 #pragma warning(disable: 4127)
18#endif
19
20#include "stb_image.h"
21
22#ifdef SDL_GPU_USE_SDL2
23 #define GET_ALPHA(sdl_color) ((sdl_color).a)
24#else
25 #define GET_ALPHA(sdl_color) ((sdl_color).unused)
26#endif
27
28#define CHECK_RENDERER (_gpu_current_renderer != NULL)
29#define MAKE_CURRENT_IF_NONE(target) do{ if(_gpu_current_renderer->current_context_target == NULL && target != NULL && target->context != NULL) GPU_MakeCurrent(target, target->context->windowID); } while(0)
30#define CHECK_CONTEXT (_gpu_current_renderer->current_context_target != NULL)
31#define RETURN_ERROR(code, details) do{ GPU_PushErrorCode(__func__, code, "%s", details); return; } while(0)
32
33int gpu_strcasecmp(const char* s1, const char* s2);
34
35void gpu_init_renderer_register(void);
36void gpu_free_renderer_register(void);
37GPU_Renderer* gpu_create_and_add_renderer(GPU_RendererID id);
38
39int gpu_default_print(GPU_LogLevelEnum log_level, const char* format, va_list args);
40
41/*! A mapping of windowID to a GPU_Target to facilitate GPU_GetWindowTarget(). */
42typedef struct GPU_WindowMapping
43{
44 Uint32 windowID;
45 GPU_Target* target;
46} GPU_WindowMapping;
47
48static GPU_Renderer* _gpu_current_renderer = NULL;
49
50static GPU_DebugLevelEnum _gpu_debug_level = GPU_DEBUG_LEVEL_0;
51
52#define GPU_DEFAULT_MAX_NUM_ERRORS 20
53#define GPU_ERROR_FUNCTION_STRING_MAX 128
54#define GPU_ERROR_DETAILS_STRING_MAX 512
55static GPU_ErrorObject* _gpu_error_code_queue = NULL;
56static unsigned int _gpu_num_error_codes = 0;
57static unsigned int _gpu_error_code_queue_size = GPU_DEFAULT_MAX_NUM_ERRORS;
58static GPU_ErrorObject _gpu_error_code_result;
59
60#define GPU_INITIAL_WINDOW_MAPPINGS_SIZE 10
61static GPU_WindowMapping* _gpu_window_mappings = NULL;
62static int _gpu_window_mappings_size = 0;
63static int _gpu_num_window_mappings = 0;
64
65static Uint32 _gpu_init_windowID = 0;
66
67static GPU_InitFlagEnum _gpu_preinit_flags = GPU_DEFAULT_INIT_FLAGS;
68static GPU_InitFlagEnum _gpu_required_features = 0;
69
70static Uint8 _gpu_initialized_SDL_core = 0;
71static Uint8 _gpu_initialized_SDL = 0;
72
73static int (*_gpu_print)(GPU_LogLevelEnum log_level, const char* format, va_list args) = &gpu_default_print;
74
75
76SDL_version GPU_GetLinkedVersion(void)
77{
78 return GPU_GetCompiledVersion();
79}
80
81void GPU_SetCurrentRenderer(GPU_RendererID id)
82{
83 _gpu_current_renderer = GPU_GetRenderer(id);
84
85 if(_gpu_current_renderer != NULL)
86 _gpu_current_renderer->impl->SetAsCurrent(_gpu_current_renderer);
87}
88
89void GPU_ResetRendererState(void)
90{
91 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
92 return;
93
94 _gpu_current_renderer->impl->ResetRendererState(_gpu_current_renderer);
95}
96
97void GPU_SetCoordinateMode(Uint8 use_math_coords)
98{
99 if(_gpu_current_renderer == NULL)
100 return;
101
102 _gpu_current_renderer->coordinate_mode = use_math_coords;
103}
104
105Uint8 GPU_GetCoordinateMode(void)
106{
107 if(_gpu_current_renderer == NULL)
108 return 0;
109
110 return _gpu_current_renderer->coordinate_mode;
111}
112
113GPU_Renderer* GPU_GetCurrentRenderer(void)
114{
115 return _gpu_current_renderer;
116}
117
118Uint32 GPU_GetCurrentShaderProgram(void)
119{
120 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
121 return 0;
122
123 return _gpu_current_renderer->current_context_target->context->current_shader_program;
124}
125
126
127int gpu_default_print(GPU_LogLevelEnum log_level, const char* format, va_list args)
128{
129 switch(log_level)
130 {
131#ifdef __ANDROID__
132 case GPU_LOG_INFO:
133 return __android_log_vprint((GPU_GetDebugLevel() >= GPU_DEBUG_LEVEL_3? ANDROID_LOG_ERROR : ANDROID_LOG_INFO), "APPLICATION", format, args);
134 case GPU_LOG_WARNING:
135 return __android_log_vprint((GPU_GetDebugLevel() >= GPU_DEBUG_LEVEL_2? ANDROID_LOG_ERROR : ANDROID_LOG_WARN), "APPLICATION", format, args);
136 case GPU_LOG_ERROR:
137 return __android_log_vprint(ANDROID_LOG_ERROR, "APPLICATION", format, args);
138#else
139 case GPU_LOG_INFO:
140 return vfprintf((GPU_GetDebugLevel() >= GPU_DEBUG_LEVEL_3? stderr : stdout), format, args);
141 case GPU_LOG_WARNING:
142 return vfprintf((GPU_GetDebugLevel() >= GPU_DEBUG_LEVEL_2? stderr : stdout), format, args);
143 case GPU_LOG_ERROR:
144 return vfprintf(stderr, format, args);
145#endif
146 default:
147 return 0;
148 }
149}
150
151void GPU_SetLogCallback(int (*callback)(GPU_LogLevelEnum log_level, const char* format, va_list args))
152{
153 if(callback == NULL)
154 _gpu_print = &gpu_default_print;
155 else
156 _gpu_print = callback;
157}
158
159void GPU_LogInfo(const char* format, ...)
160{
161 va_list args;
162 va_start(args, format);
163 _gpu_print(GPU_LOG_INFO, format, args);
164 va_end(args);
165}
166
167void GPU_LogWarning(const char* format, ...)
168{
169 va_list args;
170 va_start(args, format);
171 _gpu_print(GPU_LOG_WARNING, format, args);
172 va_end(args);
173}
174
175void GPU_LogError(const char* format, ...)
176{
177 va_list args;
178 va_start(args, format);
179 _gpu_print(GPU_LOG_ERROR, format, args);
180 va_end(args);
181}
182
183
184static Uint8 gpu_init_SDL(void)
185{
186 if(!_gpu_initialized_SDL)
187 {
188 if(!_gpu_initialized_SDL_core && !SDL_WasInit(SDL_INIT_EVERYTHING))
189 {
190 // Nothing has been set up, so init SDL and the video subsystem.
191 if(SDL_Init(SDL_INIT_VIDEO) < 0)
192 {
193 GPU_PushErrorCode("GPU_Init", GPU_ERROR_BACKEND_ERROR, "Failed to initialize SDL video subsystem");
194 return 0;
195 }
196 _gpu_initialized_SDL_core = 1;
197 }
198
199 // SDL is definitely ready now, but we're going to init the video subsystem to be sure that SDL_gpu keeps it available until GPU_Quit().
200 if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
201 {
202 GPU_PushErrorCode("GPU_Init", GPU_ERROR_BACKEND_ERROR, "Failed to initialize SDL video subsystem");
203 return 0;
204 }
205 _gpu_initialized_SDL = 1;
206 }
207 return 1;
208}
209
210void GPU_SetInitWindow(Uint32 windowID)
211{
212 _gpu_init_windowID = windowID;
213}
214
215Uint32 GPU_GetInitWindow(void)
216{
217 return _gpu_init_windowID;
218}
219
220void GPU_SetPreInitFlags(GPU_InitFlagEnum GPU_flags)
221{
222 _gpu_preinit_flags = GPU_flags;
223}
224
225GPU_InitFlagEnum GPU_GetPreInitFlags(void)
226{
227 return _gpu_preinit_flags;
228}
229
230void GPU_SetRequiredFeatures(GPU_FeatureEnum features)
231{
232 _gpu_required_features = features;
233}
234
235GPU_FeatureEnum GPU_GetRequiredFeatures(void)
236{
237 return _gpu_required_features;
238}
239
240static void gpu_init_error_queue(void)
241{
242 if(_gpu_error_code_queue == NULL)
243 {
244 unsigned int i;
245 _gpu_error_code_queue = (GPU_ErrorObject*)SDL_malloc(sizeof(GPU_ErrorObject)*_gpu_error_code_queue_size);
246
247 for(i = 0; i < _gpu_error_code_queue_size; i++)
248 {
249 _gpu_error_code_queue[i].function = (char*)SDL_malloc(GPU_ERROR_FUNCTION_STRING_MAX+1);
250 _gpu_error_code_queue[i].error = GPU_ERROR_NONE;
251 _gpu_error_code_queue[i].details = (char*)SDL_malloc(GPU_ERROR_DETAILS_STRING_MAX+1);
252 }
253 _gpu_num_error_codes = 0;
254
255 _gpu_error_code_result.function = (char*)SDL_malloc(GPU_ERROR_FUNCTION_STRING_MAX+1);
256 _gpu_error_code_result.error = GPU_ERROR_NONE;
257 _gpu_error_code_result.details = (char*)SDL_malloc(GPU_ERROR_DETAILS_STRING_MAX+1);
258 }
259}
260
261static void gpu_init_window_mappings(void)
262{
263 if(_gpu_window_mappings == NULL)
264 {
265 _gpu_window_mappings_size = GPU_INITIAL_WINDOW_MAPPINGS_SIZE;
266 _gpu_window_mappings = (GPU_WindowMapping*)SDL_malloc(_gpu_window_mappings_size * sizeof(GPU_WindowMapping));
267 _gpu_num_window_mappings = 0;
268 }
269}
270
271void GPU_AddWindowMapping(GPU_Target* target)
272{
273 Uint32 windowID;
274 int i;
275
276 if(_gpu_window_mappings == NULL)
277 gpu_init_window_mappings();
278
279 if(target == NULL || target->context == NULL)
280 return;
281
282 windowID = target->context->windowID;
283 if(windowID == 0) // Invalid window ID
284 return;
285
286 // Check for duplicates
287 for(i = 0; i < _gpu_num_window_mappings; i++)
288 {
289 if(_gpu_window_mappings[i].windowID == windowID)
290 {
291 if(_gpu_window_mappings[i].target != target)
292 GPU_PushErrorCode(__func__, GPU_ERROR_DATA_ERROR, "WindowID %u already has a mapping.", windowID);
293 return;
294 }
295 // Don't check the target because it's okay for a single target to be used with multiple windows
296 }
297
298 // Check if list is big enough to hold another
299 if(_gpu_num_window_mappings >= _gpu_window_mappings_size)
300 {
301 GPU_WindowMapping* new_array;
302 _gpu_window_mappings_size *= 2;
303 new_array = (GPU_WindowMapping*)SDL_malloc(_gpu_window_mappings_size * sizeof(GPU_WindowMapping));
304 memcpy(new_array, _gpu_window_mappings, _gpu_num_window_mappings * sizeof(GPU_WindowMapping));
305 SDL_free(_gpu_window_mappings);
306 _gpu_window_mappings = new_array;
307 }
308
309 // Add to end of list
310 {
311 GPU_WindowMapping m;
312 m.windowID = windowID;
313 m.target = target;
314 _gpu_window_mappings[_gpu_num_window_mappings] = m;
315 }
316 _gpu_num_window_mappings++;
317}
318
319void GPU_RemoveWindowMapping(Uint32 windowID)
320{
321 int i;
322
323 if(_gpu_window_mappings == NULL)
324 gpu_init_window_mappings();
325
326 if(windowID == 0) // Invalid window ID
327 return;
328
329 // Find the occurrence
330 for(i = 0; i < _gpu_num_window_mappings; i++)
331 {
332 if(_gpu_window_mappings[i].windowID == windowID)
333 {
334 int num_to_move;
335
336 // Unset the target's window
337 _gpu_window_mappings[i].target->context->windowID = 0;
338
339 // Move the remaining entries to replace the removed one
340 _gpu_num_window_mappings--;
341 num_to_move = _gpu_num_window_mappings - i;
342 if(num_to_move > 0)
343 memmove(&_gpu_window_mappings[i], &_gpu_window_mappings[i+1], num_to_move * sizeof(GPU_WindowMapping));
344 return;
345 }
346 }
347
348}
349
350void GPU_RemoveWindowMappingByTarget(GPU_Target* target)
351{
352 Uint32 windowID;
353 int i;
354
355 if(_gpu_window_mappings == NULL)
356 gpu_init_window_mappings();
357
358 if(target == NULL || target->context == NULL)
359 return;
360
361 windowID = target->context->windowID;
362 if(windowID == 0) // Invalid window ID
363 return;
364
365 // Unset the target's window
366 target->context->windowID = 0;
367
368 // Find the occurrences
369 for(i = 0; i < _gpu_num_window_mappings; )
370 {
371 if(_gpu_window_mappings[i].target == target)
372 {
373 // Move the remaining entries to replace the removed one
374 int num_to_move;
375 _gpu_num_window_mappings--;
376 num_to_move = _gpu_num_window_mappings - i;
377 if(num_to_move > 0)
378 memmove(&_gpu_window_mappings[i], &_gpu_window_mappings[i+1], num_to_move * sizeof(GPU_WindowMapping));
379 return;
380 }
381 else
382 i++;
383 }
384
385}
386
387GPU_Target* GPU_GetWindowTarget(Uint32 windowID)
388{
389 int i;
390
391 if(_gpu_window_mappings == NULL)
392 gpu_init_window_mappings();
393
394 if(windowID == 0) // Invalid window ID
395 return NULL;
396
397 // Find the occurrence
398 for(i = 0; i < _gpu_num_window_mappings; i++)
399 {
400 if(_gpu_window_mappings[i].windowID == windowID)
401 return _gpu_window_mappings[i].target;
402 }
403
404 return NULL;
405}
406
407GPU_Target* GPU_Init(Uint16 w, Uint16 h, GPU_WindowFlagEnum SDL_flags)
408{
409 int renderer_order_size;
410 int i;
411 GPU_RendererID renderer_order[GPU_RENDERER_ORDER_MAX];
412
413 gpu_init_error_queue();
414
415 gpu_init_renderer_register();
416
417 if(!gpu_init_SDL())
418 return NULL;
419
420 renderer_order_size = 0;
421 GPU_GetRendererOrder(&renderer_order_size, renderer_order);
422
423 // Init the renderers in order
424 for(i = 0; i < renderer_order_size; i++)
425 {
426 GPU_Target* screen = GPU_InitRendererByID(renderer_order[i], w, h, SDL_flags);
427 if(screen != NULL)
428 return screen;
429 }
430
431 GPU_PushErrorCode("GPU_Init", GPU_ERROR_BACKEND_ERROR, "No renderer out of %d was able to initialize properly", renderer_order_size);
432 return NULL;
433}
434
435GPU_Target* GPU_InitRenderer(GPU_RendererEnum renderer_enum, Uint16 w, Uint16 h, GPU_WindowFlagEnum SDL_flags)
436{
437 // Search registry for this renderer and use that id
438 return GPU_InitRendererByID(GPU_GetRendererID(renderer_enum), w, h, SDL_flags);
439}
440
441GPU_Target* GPU_InitRendererByID(GPU_RendererID renderer_request, Uint16 w, Uint16 h, GPU_WindowFlagEnum SDL_flags)
442{
443 GPU_Renderer* renderer;
444 GPU_Target* screen;
445
446 gpu_init_error_queue();
447 gpu_init_renderer_register();
448
449 if(!gpu_init_SDL())
450 return NULL;
451
452 renderer = gpu_create_and_add_renderer(renderer_request);
453 if(renderer == NULL)
454 return NULL;
455
456 GPU_SetCurrentRenderer(renderer->id);
457
458 screen = renderer->impl->Init(renderer, renderer_request, w, h, SDL_flags);
459 if(screen == NULL)
460 {
461 GPU_PushErrorCode("GPU_InitRendererByID", GPU_ERROR_BACKEND_ERROR, "Renderer %s failed to initialize properly", renderer->id.name);
462 // Init failed, destroy the renderer...
463 // Erase the window mappings
464 _gpu_num_window_mappings = 0;
465 GPU_CloseCurrentRenderer();
466 }
467 else
468 GPU_SetInitWindow(0);
469 return screen;
470}
471
472Uint8 GPU_IsFeatureEnabled(GPU_FeatureEnum feature)
473{
474 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
475 return 0;
476
477 return ((_gpu_current_renderer->enabled_features & feature) == feature);
478}
479
480GPU_Target* GPU_CreateTargetFromWindow(Uint32 windowID)
481{
482 if(_gpu_current_renderer == NULL)
483 return NULL;
484
485 return _gpu_current_renderer->impl->CreateTargetFromWindow(_gpu_current_renderer, windowID, NULL);
486}
487
488GPU_Target* GPU_CreateAliasTarget(GPU_Target* target)
489{
490 if(!CHECK_RENDERER)
491 return NULL;
492 MAKE_CURRENT_IF_NONE(target);
493 if(!CHECK_CONTEXT)
494 return NULL;
495
496 return _gpu_current_renderer->impl->CreateAliasTarget(_gpu_current_renderer, target);
497}
498
499void GPU_MakeCurrent(GPU_Target* target, Uint32 windowID)
500{
501 if(_gpu_current_renderer == NULL)
502 return;
503
504 _gpu_current_renderer->impl->MakeCurrent(_gpu_current_renderer, target, windowID);
505}
506
507Uint8 GPU_SetFullscreen(Uint8 enable_fullscreen, Uint8 use_desktop_resolution)
508{
509 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
510 return 0;
511
512 return _gpu_current_renderer->impl->SetFullscreen(_gpu_current_renderer, enable_fullscreen, use_desktop_resolution);
513}
514
515Uint8 GPU_GetFullscreen(void)
516{
517#ifdef SDL_GPU_USE_SDL2
518 GPU_Target* target = GPU_GetContextTarget();
519 if(target == NULL)
520 return 0;
521 return (Uint8)(SDL_GetWindowFlags(SDL_GetWindowFromID(target->context->windowID))
522 & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP));
523#else
524 SDL_Surface* surf = SDL_GetVideoSurface();
525 if(surf == NULL)
526 return 0;
527 return (surf->flags & SDL_FULLSCREEN);
528#endif
529}
530
531Uint8 GPU_SetWindowResolution(Uint16 w, Uint16 h)
532{
533 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL || w == 0 || h == 0)
534 return 0;
535
536 return _gpu_current_renderer->impl->SetWindowResolution(_gpu_current_renderer, w, h);
537}
538
539
540void GPU_GetVirtualResolution(GPU_Target* target, Uint16* w, Uint16* h)
541{
542 // No checking here for NULL w or h... Should we?
543 if (target == NULL)
544 {
545 *w = 0;
546 *h = 0;
547 }
548 else {
549 *w = target->w;
550 *h = target->h;
551 }
552}
553
554void GPU_SetVirtualResolution(GPU_Target* target, Uint16 w, Uint16 h)
555{
556 if(!CHECK_RENDERER)
557 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
558 MAKE_CURRENT_IF_NONE(target);
559 if(!CHECK_CONTEXT)
560 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
561 if(w == 0 || h == 0)
562 return;
563
564 _gpu_current_renderer->impl->SetVirtualResolution(_gpu_current_renderer, target, w, h);
565}
566
567void GPU_UnsetVirtualResolution(GPU_Target* target)
568{
569 if(!CHECK_RENDERER)
570 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
571 MAKE_CURRENT_IF_NONE(target);
572 if(!CHECK_CONTEXT)
573 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
574
575 _gpu_current_renderer->impl->UnsetVirtualResolution(_gpu_current_renderer, target);
576}
577
578void GPU_SetImageVirtualResolution(GPU_Image* image, Uint16 w, Uint16 h)
579{
580 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL || w == 0 || h == 0)
581 return;
582
583 if(image == NULL)
584 return;
585
586 image->w = w;
587 image->h = h;
588 image->using_virtual_resolution = 1;
589}
590
591void GPU_UnsetImageVirtualResolution(GPU_Image* image)
592{
593 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
594 return;
595
596 if(image == NULL)
597 return;
598
599 image->w = image->base_w;
600 image->h = image->base_h;
601 image->using_virtual_resolution = 0;
602}
603
604void gpu_free_error_queue(void)
605{
606 unsigned int i;
607 // Free the error queue
608 for(i = 0; i < _gpu_error_code_queue_size; i++)
609 {
610 SDL_free(_gpu_error_code_queue[i].function);
611 _gpu_error_code_queue[i].function = NULL;
612 SDL_free(_gpu_error_code_queue[i].details);
613 _gpu_error_code_queue[i].details = NULL;
614 }
615 SDL_free(_gpu_error_code_queue);
616 _gpu_error_code_queue = NULL;
617 _gpu_num_error_codes = 0;
618
619 SDL_free(_gpu_error_code_result.function);
620 _gpu_error_code_result.function = NULL;
621 SDL_free(_gpu_error_code_result.details);
622 _gpu_error_code_result.details = NULL;
623}
624
625// Deletes all existing errors
626void GPU_SetErrorQueueMax(unsigned int max)
627{
628 gpu_free_error_queue();
629
630 // Reallocate with new size
631 _gpu_error_code_queue_size = max;
632 gpu_init_error_queue();
633}
634
635void GPU_CloseCurrentRenderer(void)
636{
637 if(_gpu_current_renderer == NULL)
638 return;
639
640 _gpu_current_renderer->impl->Quit(_gpu_current_renderer);
641 GPU_FreeRenderer(_gpu_current_renderer);
642}
643
644void GPU_Quit(void)
645{
646 if(_gpu_num_error_codes > 0 && GPU_GetDebugLevel() >= GPU_DEBUG_LEVEL_1)
647 GPU_LogError("GPU_Quit: %d uncleared error%s.\n", _gpu_num_error_codes, (_gpu_num_error_codes > 1? "s" : ""));
648
649 gpu_free_error_queue();
650
651 if(_gpu_current_renderer == NULL)
652 return;
653
654 _gpu_current_renderer->impl->Quit(_gpu_current_renderer);
655 GPU_FreeRenderer(_gpu_current_renderer);
656 // FIXME: Free all renderers
657 _gpu_current_renderer = NULL;
658
659 _gpu_init_windowID = 0;
660
661 // Free window mappings
662 SDL_free(_gpu_window_mappings);
663 _gpu_window_mappings = NULL;
664 _gpu_window_mappings_size = 0;
665 _gpu_num_window_mappings = 0;
666
667 gpu_free_renderer_register();
668
669 if(_gpu_initialized_SDL)
670 {
671 SDL_QuitSubSystem(SDL_INIT_VIDEO);
672 _gpu_initialized_SDL = 0;
673
674 if(_gpu_initialized_SDL_core)
675 {
676 SDL_Quit();
677 _gpu_initialized_SDL_core = 0;
678 }
679 }
680}
681
682void GPU_SetDebugLevel(GPU_DebugLevelEnum level)
683{
684 if(level > GPU_DEBUG_LEVEL_MAX)
685 level = GPU_DEBUG_LEVEL_MAX;
686 _gpu_debug_level = level;
687}
688
689GPU_DebugLevelEnum GPU_GetDebugLevel(void)
690{
691 return _gpu_debug_level;
692}
693
694void GPU_PushErrorCode(const char* function, GPU_ErrorEnum error, const char* details, ...)
695{
696 gpu_init_error_queue();
697
698 if(GPU_GetDebugLevel() >= GPU_DEBUG_LEVEL_1)
699 {
700 // Print the message
701 if(details != NULL)
702 {
703 char buf[GPU_ERROR_DETAILS_STRING_MAX];
704 va_list lst;
705 va_start(lst, details);
706 vsnprintf(buf, GPU_ERROR_DETAILS_STRING_MAX, details, lst);
707 va_end(lst);
708
709 GPU_LogError("%s: %s - %s\n", (function == NULL? "NULL" : function), GPU_GetErrorString(error), buf);
710 }
711 else
712 GPU_LogError("%s: %s\n", (function == NULL? "NULL" : function), GPU_GetErrorString(error));
713 }
714
715 if(_gpu_num_error_codes < _gpu_error_code_queue_size)
716 {
717 if(function == NULL)
718 _gpu_error_code_queue[_gpu_num_error_codes].function[0] = '\0';
719 else
720 {
721 strncpy(_gpu_error_code_queue[_gpu_num_error_codes].function, function, GPU_ERROR_FUNCTION_STRING_MAX);
722 _gpu_error_code_queue[_gpu_num_error_codes].function[GPU_ERROR_FUNCTION_STRING_MAX] = '\0';
723 }
724 _gpu_error_code_queue[_gpu_num_error_codes].error = error;
725 if(details == NULL)
726 _gpu_error_code_queue[_gpu_num_error_codes].details[0] = '\0';
727 else
728 {
729 va_list lst;
730 va_start(lst, details);
731 vsnprintf(_gpu_error_code_queue[_gpu_num_error_codes].details, GPU_ERROR_DETAILS_STRING_MAX, details, lst);
732 va_end(lst);
733 }
734 _gpu_num_error_codes++;
735 }
736}
737
738GPU_ErrorObject GPU_PopErrorCode(void)
739{
740 unsigned int i;
741 GPU_ErrorObject result = {NULL, GPU_ERROR_NONE, NULL};
742
743 gpu_init_error_queue();
744
745 if(_gpu_num_error_codes <= 0)
746 return result;
747
748 // Pop the oldest
749 strcpy(_gpu_error_code_result.function, _gpu_error_code_queue[0].function);
750 _gpu_error_code_result.error = _gpu_error_code_queue[0].error;
751 strcpy(_gpu_error_code_result.details, _gpu_error_code_queue[0].details);
752
753 // We'll be returning that one
754 result = _gpu_error_code_result;
755
756 // Move the rest down
757 _gpu_num_error_codes--;
758 for(i = 0; i < _gpu_num_error_codes; i++)
759 {
760 strcpy(_gpu_error_code_queue[i].function, _gpu_error_code_queue[i+1].function);
761 _gpu_error_code_queue[i].error = _gpu_error_code_queue[i+1].error;
762 strcpy(_gpu_error_code_queue[i].details, _gpu_error_code_queue[i+1].details);
763 }
764 return result;
765}
766
767const char* GPU_GetErrorString(GPU_ErrorEnum error)
768{
769 switch(error)
770 {
771 case GPU_ERROR_NONE:
772 return "NO ERROR";
773 case GPU_ERROR_BACKEND_ERROR:
774 return "BACKEND ERROR";
775 case GPU_ERROR_DATA_ERROR:
776 return "DATA ERROR";
777 case GPU_ERROR_USER_ERROR:
778 return "USER ERROR";
779 case GPU_ERROR_UNSUPPORTED_FUNCTION:
780 return "UNSUPPORTED FUNCTION";
781 case GPU_ERROR_NULL_ARGUMENT:
782 return "NULL ARGUMENT";
783 case GPU_ERROR_FILE_NOT_FOUND:
784 return "FILE NOT FOUND";
785 }
786 return "UNKNOWN ERROR";
787}
788
789
790void GPU_GetVirtualCoords(GPU_Target* target, float* x, float* y, float displayX, float displayY)
791{
792 if(target == NULL)
793 return;
794
795 if(target->context != NULL)
796 {
797 if(x != NULL)
798 *x = (displayX*target->w)/target->context->window_w;
799 if(y != NULL)
800 *y = (displayY*target->h)/target->context->window_h;
801 }
802 else if(target->image != NULL)
803 {
804 if(x != NULL)
805 *x = (displayX*target->w)/target->image->w;
806 if(y != NULL)
807 *y = (displayY*target->h)/target->image->h;
808 }
809 else
810 {
811 if(x != NULL)
812 *x = displayX;
813 if(y != NULL)
814 *y = displayY;
815 }
816}
817
818GPU_Rect GPU_MakeRect(float x, float y, float w, float h)
819{
820 GPU_Rect r;
821 r.x = x;
822 r.y = y;
823 r.w = w;
824 r.h = h;
825
826 return r;
827}
828
829SDL_Color GPU_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
830{
831 SDL_Color c;
832 c.r = r;
833 c.g = g;
834 c.b = b;
835 GET_ALPHA(c) = a;
836
837 return c;
838}
839
840GPU_RendererID GPU_MakeRendererID(const char* name, GPU_RendererEnum renderer, int major_version, int minor_version)
841{
842 GPU_RendererID r;
843 r.name = name;
844 r.renderer = renderer;
845 r.major_version = major_version;
846 r.minor_version = minor_version;
847
848 return r;
849}
850
851void GPU_SetViewport(GPU_Target* target, GPU_Rect viewport)
852{
853 if(target != NULL)
854 target->viewport = viewport;
855}
856
857void GPU_UnsetViewport(GPU_Target* target)
858{
859 if(target != NULL)
860 target->viewport = GPU_MakeRect(0, 0, target->w, target->h);
861}
862
863GPU_Camera GPU_GetDefaultCamera(void)
864{
865 GPU_Camera cam = {0.0f, 0.0f, -10.0f, 0.0f, 1.0f};
866 return cam;
867}
868
869GPU_Camera GPU_GetCamera(GPU_Target* target)
870{
871 if(target == NULL)
872 return GPU_GetDefaultCamera();
873 return target->camera;
874}
875
876GPU_Camera GPU_SetCamera(GPU_Target* target, GPU_Camera* cam)
877{
878 if(_gpu_current_renderer == NULL)
879 return GPU_GetDefaultCamera();
880 MAKE_CURRENT_IF_NONE(target);
881 if(_gpu_current_renderer->current_context_target == NULL)
882 return GPU_GetDefaultCamera();
883
884 return _gpu_current_renderer->impl->SetCamera(_gpu_current_renderer, target, cam);
885}
886
887GPU_Image* GPU_CreateImage(Uint16 w, Uint16 h, GPU_FormatEnum format)
888{
889 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
890 return NULL;
891
892 return _gpu_current_renderer->impl->CreateImage(_gpu_current_renderer, w, h, format);
893}
894
895GPU_Image* GPU_CreateImageUsingTexture(Uint32 handle, Uint8 take_ownership)
896{
897 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
898 return NULL;
899
900 return _gpu_current_renderer->impl->CreateImageUsingTexture(_gpu_current_renderer, handle, take_ownership);
901}
902
903GPU_Image* GPU_LoadImage(const char* filename)
904{
905 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
906 return NULL;
907
908 return _gpu_current_renderer->impl->LoadImage(_gpu_current_renderer, filename);
909}
910
911GPU_Image* GPU_CreateAliasImage(GPU_Image* image)
912{
913 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
914 return NULL;
915
916 return _gpu_current_renderer->impl->CreateAliasImage(_gpu_current_renderer, image);
917}
918
919Uint8 GPU_SaveImage(GPU_Image* image, const char* filename, GPU_FileFormatEnum format)
920{
921 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
922 return 0;
923
924 return _gpu_current_renderer->impl->SaveImage(_gpu_current_renderer, image, filename, format);
925}
926
927GPU_Image* GPU_CopyImage(GPU_Image* image)
928{
929 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
930 return NULL;
931
932 return _gpu_current_renderer->impl->CopyImage(_gpu_current_renderer, image);
933}
934
935void GPU_UpdateImage(GPU_Image* image, const GPU_Rect* image_rect, SDL_Surface* surface, const GPU_Rect* surface_rect)
936{
937 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
938 return;
939
940 _gpu_current_renderer->impl->UpdateImage(_gpu_current_renderer, image, image_rect, surface, surface_rect);
941}
942
943void GPU_UpdateImageBytes(GPU_Image* image, const GPU_Rect* image_rect, const unsigned char* bytes, int bytes_per_row)
944{
945 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
946 return;
947
948 _gpu_current_renderer->impl->UpdateImageBytes(_gpu_current_renderer, image, image_rect, bytes, bytes_per_row);
949}
950
951Uint8 GPU_ReplaceImage(GPU_Image* image, SDL_Surface* surface, const GPU_Rect* surface_rect)
952{
953 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
954 return 0;
955
956 return _gpu_current_renderer->impl->ReplaceImage(_gpu_current_renderer, image, surface, surface_rect);
957}
958
959static SDL_Surface* gpu_copy_raw_surface_data(unsigned char* data, int width, int height, int channels)
960{
961 int i;
962 Uint32 Rmask, Gmask, Bmask, Amask = 0;
963 SDL_Surface* result;
964
965 if(data == NULL)
966 {
967 GPU_PushErrorCode(__func__, GPU_ERROR_DATA_ERROR, "Got NULL data");
968 return NULL;
969 }
970
971 switch(channels)
972 {
973 case 1:
974 Rmask = Gmask = Bmask = 0; // Use default RGB masks for 8-bit
975 break;
976 case 2:
977 Rmask = Gmask = Bmask = 0; // Use default RGB masks for 16-bit
978 break;
979 case 3:
980 // These are reversed from what SDL_image uses... That is bad. :( Needs testing.
981#if SDL_BYTEORDER == SDL_BIG_ENDIAN
982 Rmask = 0xff0000;
983 Gmask = 0x00ff00;
984 Bmask = 0x0000ff;
985#else
986 Rmask = 0x0000ff;
987 Gmask = 0x00ff00;
988 Bmask = 0xff0000;
989#endif
990 break;
991 case 4:
992 Rmask = 0x000000ff;
993 Gmask = 0x0000ff00;
994 Bmask = 0x00ff0000;
995 Amask = 0xff000000;
996 break;
997 default:
998 Rmask = Gmask = Bmask = 0;
999 GPU_PushErrorCode(__func__, GPU_ERROR_DATA_ERROR, "Invalid number of channels: %d", channels);
1000 return NULL;
1001 break;
1002 }
1003
1004 result = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, channels*8, Rmask, Gmask, Bmask, Amask);
1005 if(result == NULL)
1006 {
1007 GPU_PushErrorCode(__func__, GPU_ERROR_DATA_ERROR, "Failed to create new %dx%d surface", width, height);
1008 return NULL;
1009 }
1010
1011 // Copy row-by-row in case the pitch doesn't match
1012 for(i = 0; i < height; ++i)
1013 {
1014 memcpy((Uint8*)result->pixels + i*result->pitch, data + channels*width*i, channels*width);
1015 }
1016
1017 if(result != NULL && result->format->palette != NULL)
1018 {
1019 // SDL_CreateRGBSurface has no idea what palette to use, so it uses a blank one.
1020 // We'll at least create a grayscale one, but it's not ideal...
1021 // Better would be to get the palette from stbi, but stbi doesn't do that!
1022 SDL_Color colors[256];
1023 int i;
1024
1025 for(i = 0; i < 256; i++)
1026 {
1027 colors[i].r = colors[i].g = colors[i].b = (Uint8)i;
1028 }
1029
1030 /* Set palette */
1031#ifdef SDL_GPU_USE_SDL2
1032 SDL_SetPaletteColors(result->format->palette, colors, 0, 256);
1033#else
1034 SDL_SetPalette(result, SDL_LOGPAL, colors, 0, 256);
1035#endif
1036 }
1037
1038 return result;
1039}
1040
1041SDL_Surface* GPU_LoadSurface_RW(SDL_RWops* rwops, Uint8 free_rwops)
1042{
1043 int width, height, channels;
1044 unsigned char* data;
1045 SDL_Surface* result;
1046
1047 int data_bytes;
1048 unsigned char* c_data;
1049
1050 if(rwops == NULL)
1051 {
1052 GPU_PushErrorCode(__func__, GPU_ERROR_NULL_ARGUMENT, "rwops");
1053 return NULL;
1054 }
1055
1056 // Get count of bytes
1057 SDL_RWseek(rwops, 0, SEEK_SET);
1058 data_bytes = SDL_RWseek(rwops, 0, SEEK_END);
1059 SDL_RWseek(rwops, 0, SEEK_SET);
1060
1061 // Read in the rwops data
1062 c_data = (unsigned char*)SDL_malloc(data_bytes);
1063 SDL_RWread(rwops, c_data, 1, data_bytes);
1064
1065 // Load image
1066 data = stbi_load_from_memory(c_data, data_bytes, &width, &height, &channels, 0);
1067
1068 // Clean up temp data
1069 SDL_free(c_data);
1070 if(free_rwops)
1071 SDL_RWclose(rwops);
1072
1073 if(data == NULL)
1074 {
1075 GPU_PushErrorCode(__func__, GPU_ERROR_DATA_ERROR, "Failed to load from rwops: %s", stbi_failure_reason());
1076 return NULL;
1077 }
1078
1079 // Copy into a surface
1080 result = gpu_copy_raw_surface_data(data, width, height, channels);
1081
1082 stbi_image_free(data);
1083
1084 return result;
1085}
1086
1087SDL_Surface* GPU_LoadSurface(const char* filename)
1088{
1089 int width, height, channels;
1090 unsigned char* data;
1091 SDL_Surface* result;
1092
1093 if(filename == NULL)
1094 {
1095 GPU_PushErrorCode("GPU_LoadSurface", GPU_ERROR_NULL_ARGUMENT, "filename");
1096 return NULL;
1097 }
1098
1099#ifdef __ANDROID__
1100 // Must use SDL_RWops to access the assets directory automatically
1101 if(strlen(filename) > 0 && filename[0] != '/')
1102 return GPU_LoadSurface_RW(SDL_RWFromFile(filename, "r"), 1);
1103#endif
1104
1105 data = stbi_load(filename, &width, &height, &channels, 0);
1106
1107 if(data == NULL)
1108 {
1109 GPU_PushErrorCode(__func__, GPU_ERROR_DATA_ERROR, "Failed to load \"%s\": %s", filename, stbi_failure_reason());
1110 return NULL;
1111 }
1112
1113 result = gpu_copy_raw_surface_data(data, width, height, channels);
1114
1115 stbi_image_free(data);
1116
1117 return result;
1118}
1119
1120// From http://stackoverflow.com/questions/5309471/getting-file-extension-in-c
1121static const char *get_filename_ext(const char *filename)
1122{
1123 const char *dot = strrchr(filename, '.');
1124 if(!dot || dot == filename)
1125 return "";
1126 return dot + 1;
1127}
1128
1129Uint8 GPU_SaveSurface(SDL_Surface* surface, const char* filename, GPU_FileFormatEnum format)
1130{
1131 Uint8 result;
1132 unsigned char* data;
1133
1134 if(surface == NULL || filename == NULL ||
1135 surface->w < 1 || surface->h < 1)
1136 {
1137 return 0;
1138 }
1139
1140
1141 data = surface->pixels;
1142
1143 if(format == GPU_FILE_AUTO)
1144 {
1145 const char* extension = get_filename_ext(filename);
1146 if(gpu_strcasecmp(extension, "png") == 0)
1147 format = GPU_FILE_PNG;
1148 else if(gpu_strcasecmp(extension, "bmp") == 0)
1149 format = GPU_FILE_BMP;
1150 else if(gpu_strcasecmp(extension, "tga") == 0)
1151 format = GPU_FILE_TGA;
1152 else
1153 {
1154 GPU_PushErrorCode(__func__, GPU_ERROR_DATA_ERROR, "Could not detect output file format from file name");
1155 return 0;
1156 }
1157 }
1158
1159 switch(format)
1160 {
1161 case GPU_FILE_PNG:
1162 result = (stbi_write_png(filename, surface->w, surface->h, surface->format->BytesPerPixel, (const unsigned char *const)data, 0) > 0);
1163 break;
1164 case GPU_FILE_BMP:
1165 result = (stbi_write_bmp(filename, surface->w, surface->h, surface->format->BytesPerPixel, (void*)data) > 0);
1166 break;
1167 case GPU_FILE_TGA:
1168 result = (stbi_write_tga(filename, surface->w, surface->h, surface->format->BytesPerPixel, (void*)data) > 0);
1169 break;
1170 default:
1171 GPU_PushErrorCode(__func__, GPU_ERROR_DATA_ERROR, "Unsupported output file format");
1172 result = 0;
1173 break;
1174 }
1175
1176 return result;
1177}
1178
1179GPU_Image* GPU_CopyImageFromSurface(SDL_Surface* surface)
1180{
1181 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1182 return NULL;
1183
1184 return _gpu_current_renderer->impl->CopyImageFromSurface(_gpu_current_renderer, surface);
1185}
1186
1187GPU_Image* GPU_CopyImageFromTarget(GPU_Target* target)
1188{
1189 if(_gpu_current_renderer == NULL)
1190 return NULL;
1191 MAKE_CURRENT_IF_NONE(target);
1192 if(_gpu_current_renderer->current_context_target == NULL)
1193 return NULL;
1194
1195 return _gpu_current_renderer->impl->CopyImageFromTarget(_gpu_current_renderer, target);
1196}
1197
1198SDL_Surface* GPU_CopySurfaceFromTarget(GPU_Target* target)
1199{
1200 if(_gpu_current_renderer == NULL)
1201 return NULL;
1202 MAKE_CURRENT_IF_NONE(target);
1203 if(_gpu_current_renderer->current_context_target == NULL)
1204 return NULL;
1205
1206 return _gpu_current_renderer->impl->CopySurfaceFromTarget(_gpu_current_renderer, target);
1207}
1208
1209SDL_Surface* GPU_CopySurfaceFromImage(GPU_Image* image)
1210{
1211 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1212 return NULL;
1213
1214 return _gpu_current_renderer->impl->CopySurfaceFromImage(_gpu_current_renderer, image);
1215}
1216
1217void GPU_FreeImage(GPU_Image* image)
1218{
1219 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1220 return;
1221
1222 _gpu_current_renderer->impl->FreeImage(_gpu_current_renderer, image);
1223}
1224
1225
1226GPU_Target* GPU_GetContextTarget(void)
1227{
1228 if(_gpu_current_renderer == NULL)
1229 return NULL;
1230
1231 return _gpu_current_renderer->current_context_target;
1232}
1233
1234
1235GPU_Target* GPU_LoadTarget(GPU_Image* image)
1236{
1237 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1238 return NULL;
1239
1240 return _gpu_current_renderer->impl->LoadTarget(_gpu_current_renderer, image);
1241}
1242
1243
1244
1245void GPU_FreeTarget(GPU_Target* target)
1246{
1247 if(_gpu_current_renderer == NULL)
1248 return;
1249
1250 _gpu_current_renderer->impl->FreeTarget(_gpu_current_renderer, target);
1251}
1252
1253
1254
1255void GPU_Blit(GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y)
1256{
1257 if(!CHECK_RENDERER)
1258 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1259 MAKE_CURRENT_IF_NONE(target);
1260 if(!CHECK_CONTEXT)
1261 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1262
1263 if(image == NULL)
1264 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "image");
1265 if(target == NULL)
1266 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "target");
1267
1268 _gpu_current_renderer->impl->Blit(_gpu_current_renderer, image, src_rect, target, x, y);
1269}
1270
1271
1272void GPU_BlitRotate(GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y, float angle)
1273{
1274 if(!CHECK_RENDERER)
1275 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1276 MAKE_CURRENT_IF_NONE(target);
1277 if(!CHECK_CONTEXT)
1278 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1279
1280 if(image == NULL)
1281 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "image");
1282 if(target == NULL)
1283 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "target");
1284
1285 _gpu_current_renderer->impl->BlitRotate(_gpu_current_renderer, image, src_rect, target, x, y, angle);
1286}
1287
1288void GPU_BlitScale(GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y, float scaleX, float scaleY)
1289{
1290 if(!CHECK_RENDERER)
1291 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1292 MAKE_CURRENT_IF_NONE(target);
1293 if(!CHECK_CONTEXT)
1294 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1295
1296 if(image == NULL)
1297 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "image");
1298 if(target == NULL)
1299 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "target");
1300
1301 _gpu_current_renderer->impl->BlitScale(_gpu_current_renderer, image, src_rect, target, x, y, scaleX, scaleY);
1302}
1303
1304void GPU_BlitTransform(GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y, float angle, float scaleX, float scaleY)
1305{
1306 if(!CHECK_RENDERER)
1307 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1308 MAKE_CURRENT_IF_NONE(target);
1309 if(!CHECK_CONTEXT)
1310 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1311
1312 if(image == NULL)
1313 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "image");
1314 if(target == NULL)
1315 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "target");
1316
1317 _gpu_current_renderer->impl->BlitTransform(_gpu_current_renderer, image, src_rect, target, x, y, angle, scaleX, scaleY);
1318}
1319
1320void GPU_BlitTransformX(GPU_Image* image, GPU_Rect* src_rect, GPU_Target* target, float x, float y, float pivot_x, float pivot_y, float angle, float scaleX, float scaleY)
1321{
1322 if(!CHECK_RENDERER)
1323 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1324 MAKE_CURRENT_IF_NONE(target);
1325 if(!CHECK_CONTEXT)
1326 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1327
1328 if(image == NULL)
1329 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "image");
1330 if(target == NULL)
1331 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "target");
1332
1333 _gpu_current_renderer->impl->BlitTransformX(_gpu_current_renderer, image, src_rect, target, x, y, pivot_x, pivot_y, angle, scaleX, scaleY);
1334}
1335
1336void GPU_TriangleBatch(GPU_Image* image, GPU_Target* target, unsigned short num_vertices, float* values, unsigned int num_indices, unsigned short* indices, GPU_BatchFlagEnum flags)
1337{
1338 if(!CHECK_RENDERER)
1339 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1340 MAKE_CURRENT_IF_NONE(target);
1341 if(!CHECK_CONTEXT)
1342 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1343
1344 if(target == NULL)
1345 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "target");
1346
1347 if(num_vertices == 0)
1348 return;
1349
1350
1351 _gpu_current_renderer->impl->TriangleBatch(_gpu_current_renderer, image, target, num_vertices, values, num_indices, indices, flags);
1352}
1353
1354
1355
1356
1357void GPU_GenerateMipmaps(GPU_Image* image)
1358{
1359 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1360 return;
1361
1362 _gpu_current_renderer->impl->GenerateMipmaps(_gpu_current_renderer, image);
1363}
1364
1365
1366
1367
1368GPU_Rect GPU_SetClipRect(GPU_Target* target, GPU_Rect rect)
1369{
1370 if(target == NULL || _gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1371 {
1372 GPU_Rect r = {0,0,0,0};
1373 return r;
1374 }
1375
1376 return _gpu_current_renderer->impl->SetClip(_gpu_current_renderer, target, (Sint16)rect.x, (Sint16)rect.y, (Uint16)rect.w, (Uint16)rect.h);
1377}
1378
1379GPU_Rect GPU_SetClip(GPU_Target* target, Sint16 x, Sint16 y, Uint16 w, Uint16 h)
1380{
1381 if(target == NULL || _gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1382 {
1383 GPU_Rect r = {0,0,0,0};
1384 return r;
1385 }
1386
1387 return _gpu_current_renderer->impl->SetClip(_gpu_current_renderer, target, x, y, w, h);
1388}
1389
1390void GPU_UnsetClip(GPU_Target* target)
1391{
1392 if(target == NULL || _gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1393 return;
1394
1395 _gpu_current_renderer->impl->UnsetClip(_gpu_current_renderer, target);
1396}
1397
1398
1399
1400SDL_Color GPU_GetColor(GPU_Image* image)
1401{
1402 return image->color;
1403}
1404
1405
1406
1407void GPU_SetColor(GPU_Image* image, SDL_Color color)
1408{
1409 if(image == NULL)
1410 return;
1411
1412 image->color = color;
1413}
1414
1415void GPU_SetRGB(GPU_Image* image, Uint8 r, Uint8 g, Uint8 b)
1416{
1417 SDL_Color c;
1418 c.r = r;
1419 c.g = g;
1420 c.b = b;
1421 GET_ALPHA(c) = 255;
1422
1423 if(image == NULL)
1424 return;
1425
1426 image->color = c;
1427}
1428
1429void GPU_SetRGBA(GPU_Image* image, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1430{
1431 SDL_Color c;
1432 c.r = r;
1433 c.g = g;
1434 c.b = b;
1435 GET_ALPHA(c) = a;
1436
1437 if(image == NULL)
1438 return;
1439
1440 image->color = c;
1441}
1442
1443void GPU_UnsetColor(GPU_Image* image)
1444{
1445 SDL_Color c = {255, 255, 255, 255};
1446 if(image == NULL)
1447 return;
1448
1449 image->color = c;
1450}
1451
1452void GPU_SetTargetColor(GPU_Target* target, SDL_Color color)
1453{
1454 if(target == NULL)
1455 return;
1456
1457 target->use_color = 1;
1458 target->color = color;
1459}
1460
1461void GPU_SetTargetRGB(GPU_Target* target, Uint8 r, Uint8 g, Uint8 b)
1462{
1463 SDL_Color c;
1464 c.r = r;
1465 c.g = g;
1466 c.b = b;
1467 GET_ALPHA(c) = 255;
1468
1469 if(target == NULL)
1470 return;
1471
1472 target->use_color = !(r == 255 && g == 255 && b == 255);
1473 target->color = c;
1474}
1475
1476void GPU_SetTargetRGBA(GPU_Target* target, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1477{
1478 SDL_Color c;
1479 c.r = r;
1480 c.g = g;
1481 c.b = b;
1482 GET_ALPHA(c) = a;
1483
1484 if(target == NULL)
1485 return;
1486
1487 target->use_color = !(r == 255 && g == 255 && b == 255 && a == 255);
1488 target->color = c;
1489}
1490
1491void GPU_UnsetTargetColor(GPU_Target* target)
1492{
1493 SDL_Color c = {255, 255, 255, 255};
1494 if(target == NULL)
1495 return;
1496
1497 target->use_color = 0;
1498 target->color = c;
1499}
1500
1501Uint8 GPU_GetBlending(GPU_Image* image)
1502{
1503 if(image == NULL)
1504 return 0;
1505
1506 return image->use_blending;
1507}
1508
1509
1510void GPU_SetBlending(GPU_Image* image, Uint8 enable)
1511{
1512 if(image == NULL)
1513 return;
1514
1515 image->use_blending = enable;
1516}
1517
1518void GPU_SetShapeBlending(Uint8 enable)
1519{
1520 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1521 return;
1522
1523 _gpu_current_renderer->current_context_target->context->shapes_use_blending = enable;
1524}
1525
1526
1527GPU_BlendMode GPU_GetBlendModeFromPreset(GPU_BlendPresetEnum preset)
1528{
1529 switch(preset)
1530 {
1531 case GPU_BLEND_NORMAL:
1532 {
1533 GPU_BlendMode b = {GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_EQ_ADD, GPU_EQ_ADD};
1534 return b;
1535 }
1536 break;
1537 case GPU_BLEND_PREMULTIPLIED_ALPHA:
1538 {
1539 GPU_BlendMode b = {GPU_FUNC_ONE, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_FUNC_ONE, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_EQ_ADD, GPU_EQ_ADD};
1540 return b;
1541 }
1542 break;
1543 case GPU_BLEND_MULTIPLY:
1544 {
1545 GPU_BlendMode b = {GPU_FUNC_DST_COLOR, GPU_FUNC_ZERO, GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_EQ_ADD, GPU_EQ_ADD};
1546 return b;
1547 }
1548 break;
1549 case GPU_BLEND_ADD:
1550 {
1551 GPU_BlendMode b = {GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE, GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE, GPU_EQ_ADD, GPU_EQ_ADD};
1552 return b;
1553 }
1554 break;
1555 case GPU_BLEND_SUBTRACT:
1556 // FIXME: Use src alpha for source components?
1557 {
1558 GPU_BlendMode b = {GPU_FUNC_ONE, GPU_FUNC_ONE, GPU_FUNC_ONE, GPU_FUNC_ONE, GPU_EQ_SUBTRACT, GPU_EQ_SUBTRACT};
1559 return b;
1560 }
1561 break;
1562 case GPU_BLEND_MOD_ALPHA:
1563 // Don't disturb the colors, but multiply the dest alpha by the src alpha
1564 {
1565 GPU_BlendMode b = {GPU_FUNC_ZERO, GPU_FUNC_ONE, GPU_FUNC_ZERO, GPU_FUNC_SRC_ALPHA, GPU_EQ_ADD, GPU_EQ_ADD};
1566 return b;
1567 }
1568 break;
1569 case GPU_BLEND_SET_ALPHA:
1570 // Don't disturb the colors, but set the alpha to the src alpha
1571 {
1572 GPU_BlendMode b = {GPU_FUNC_ZERO, GPU_FUNC_ONE, GPU_FUNC_ONE, GPU_FUNC_ZERO, GPU_EQ_ADD, GPU_EQ_ADD};
1573 return b;
1574 }
1575 break;
1576 case GPU_BLEND_SET:
1577 {
1578 GPU_BlendMode b = {GPU_FUNC_ONE, GPU_FUNC_ZERO, GPU_FUNC_ONE, GPU_FUNC_ZERO, GPU_EQ_ADD, GPU_EQ_ADD};
1579 return b;
1580 }
1581 break;
1582 case GPU_BLEND_NORMAL_KEEP_ALPHA:
1583 {
1584 GPU_BlendMode b = {GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_FUNC_ZERO, GPU_FUNC_ONE, GPU_EQ_ADD, GPU_EQ_ADD};
1585 return b;
1586 }
1587 break;
1588 case GPU_BLEND_NORMAL_ADD_ALPHA:
1589 {
1590 GPU_BlendMode b = {GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_FUNC_ONE, GPU_FUNC_ONE, GPU_EQ_ADD, GPU_EQ_ADD};
1591 return b;
1592 }
1593 break;
1594 default:
1595 GPU_PushErrorCode(__func__, GPU_ERROR_USER_ERROR, "Blend preset not supported: %d", preset);
1596 {
1597 GPU_BlendMode b = {GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_FUNC_SRC_ALPHA, GPU_FUNC_ONE_MINUS_SRC_ALPHA, GPU_EQ_ADD, GPU_EQ_ADD};
1598 return b;
1599 }
1600 break;
1601 }
1602}
1603
1604
1605void GPU_SetBlendFunction(GPU_Image* image, GPU_BlendFuncEnum source_color, GPU_BlendFuncEnum dest_color, GPU_BlendFuncEnum source_alpha, GPU_BlendFuncEnum dest_alpha)
1606{
1607 if(image == NULL)
1608 return;
1609
1610 image->blend_mode.source_color = source_color;
1611 image->blend_mode.dest_color = dest_color;
1612 image->blend_mode.source_alpha = source_alpha;
1613 image->blend_mode.dest_alpha = dest_alpha;
1614}
1615
1616void GPU_SetBlendEquation(GPU_Image* image, GPU_BlendEqEnum color_equation, GPU_BlendEqEnum alpha_equation)
1617{
1618 if(image == NULL)
1619 return;
1620
1621 image->blend_mode.color_equation = color_equation;
1622 image->blend_mode.alpha_equation = alpha_equation;
1623}
1624
1625void GPU_SetBlendMode(GPU_Image* image, GPU_BlendPresetEnum preset)
1626{
1627 GPU_BlendMode b;
1628 if(image == NULL)
1629 return;
1630
1631 b = GPU_GetBlendModeFromPreset(preset);
1632 GPU_SetBlendFunction(image, b.source_color, b.dest_color, b.source_alpha, b.dest_alpha);
1633 GPU_SetBlendEquation(image, b.color_equation, b.alpha_equation);
1634}
1635
1636void GPU_SetShapeBlendFunction(GPU_BlendFuncEnum source_color, GPU_BlendFuncEnum dest_color, GPU_BlendFuncEnum source_alpha, GPU_BlendFuncEnum dest_alpha)
1637{
1638 GPU_Context* context;
1639 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1640 return;
1641
1642 context = _gpu_current_renderer->current_context_target->context;
1643
1644 context->shapes_blend_mode.source_color = source_color;
1645 context->shapes_blend_mode.dest_color = dest_color;
1646 context->shapes_blend_mode.source_alpha = source_alpha;
1647 context->shapes_blend_mode.dest_alpha = dest_alpha;
1648}
1649
1650void GPU_SetShapeBlendEquation(GPU_BlendEqEnum color_equation, GPU_BlendEqEnum alpha_equation)
1651{
1652 GPU_Context* context;
1653 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1654 return;
1655
1656 context = _gpu_current_renderer->current_context_target->context;
1657
1658 context->shapes_blend_mode.color_equation = color_equation;
1659 context->shapes_blend_mode.alpha_equation = alpha_equation;
1660}
1661
1662void GPU_SetShapeBlendMode(GPU_BlendPresetEnum preset)
1663{
1664 GPU_BlendMode b;
1665 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1666 return;
1667
1668 b = GPU_GetBlendModeFromPreset(preset);
1669 GPU_SetShapeBlendFunction(b.source_color, b.dest_color, b.source_alpha, b.dest_alpha);
1670 GPU_SetShapeBlendEquation(b.color_equation, b.alpha_equation);
1671}
1672
1673void GPU_SetImageFilter(GPU_Image* image, GPU_FilterEnum filter)
1674{
1675 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1676 return;
1677 if(image == NULL)
1678 return;
1679
1680 _gpu_current_renderer->impl->SetImageFilter(_gpu_current_renderer, image, filter);
1681}
1682
1683GPU_SnapEnum GPU_GetSnapMode(GPU_Image* image)
1684{
1685 if(image == NULL)
1686 return 0;
1687
1688 return image->snap_mode;
1689}
1690
1691void GPU_SetSnapMode(GPU_Image* image, GPU_SnapEnum mode)
1692{
1693 if(image == NULL)
1694 return;
1695
1696 image->snap_mode = mode;
1697}
1698
1699void GPU_SetWrapMode(GPU_Image* image, GPU_WrapEnum wrap_mode_x, GPU_WrapEnum wrap_mode_y)
1700{
1701 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1702 return;
1703 if(image == NULL)
1704 return;
1705
1706 _gpu_current_renderer->impl->SetWrapMode(_gpu_current_renderer, image, wrap_mode_x, wrap_mode_y);
1707}
1708
1709
1710SDL_Color GPU_GetPixel(GPU_Target* target, Sint16 x, Sint16 y)
1711{
1712 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1713 {
1714 SDL_Color c = {0,0,0,0};
1715 return c;
1716 }
1717
1718 return _gpu_current_renderer->impl->GetPixel(_gpu_current_renderer, target, x, y);
1719}
1720
1721
1722
1723
1724
1725
1726
1727void GPU_Clear(GPU_Target* target)
1728{
1729 if(!CHECK_RENDERER)
1730 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1731 MAKE_CURRENT_IF_NONE(target);
1732 if(!CHECK_CONTEXT)
1733 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1734
1735 _gpu_current_renderer->impl->ClearRGBA(_gpu_current_renderer, target, 0, 0, 0, 0);
1736}
1737
1738void GPU_ClearColor(GPU_Target* target, SDL_Color color)
1739{
1740 if(!CHECK_RENDERER)
1741 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1742 MAKE_CURRENT_IF_NONE(target);
1743 if(!CHECK_CONTEXT)
1744 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1745
1746 _gpu_current_renderer->impl->ClearRGBA(_gpu_current_renderer, target, color.r, color.g, color.b, GET_ALPHA(color));
1747}
1748
1749void GPU_ClearRGB(GPU_Target* target, Uint8 r, Uint8 g, Uint8 b)
1750{
1751 if(!CHECK_RENDERER)
1752 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1753 MAKE_CURRENT_IF_NONE(target);
1754 if(!CHECK_CONTEXT)
1755 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1756
1757 _gpu_current_renderer->impl->ClearRGBA(_gpu_current_renderer, target, r, g, b, 255);
1758}
1759
1760void GPU_ClearRGBA(GPU_Target* target, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1761{
1762 if(!CHECK_RENDERER)
1763 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1764 MAKE_CURRENT_IF_NONE(target);
1765 if(!CHECK_CONTEXT)
1766 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1767
1768 _gpu_current_renderer->impl->ClearRGBA(_gpu_current_renderer, target, r, g, b, a);
1769}
1770
1771void GPU_FlushBlitBuffer(void)
1772{
1773 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1774 return;
1775
1776 _gpu_current_renderer->impl->FlushBlitBuffer(_gpu_current_renderer);
1777}
1778
1779void GPU_Flip(GPU_Target* target)
1780{
1781 if(!CHECK_RENDERER)
1782 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
1783 MAKE_CURRENT_IF_NONE(target);
1784 if(!CHECK_CONTEXT)
1785 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
1786
1787 _gpu_current_renderer->impl->Flip(_gpu_current_renderer, target);
1788}
1789
1790
1791
1792
1793
1794// Shader API
1795
1796
1797Uint32 GPU_CompileShader_RW(GPU_ShaderEnum shader_type, SDL_RWops* shader_source, Uint8 free_rwops)
1798{
1799 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1800 {
1801 if(free_rwops)
1802 SDL_RWclose(shader_source);
1803 return 0;
1804 }
1805
1806 return _gpu_current_renderer->impl->CompileShader_RW(_gpu_current_renderer, shader_type, shader_source, free_rwops);
1807}
1808
1809Uint32 GPU_LoadShader(GPU_ShaderEnum shader_type, const char* filename)
1810{
1811 SDL_RWops* rwops;
1812
1813 if(filename == NULL)
1814 {
1815 GPU_PushErrorCode(__func__, GPU_ERROR_NULL_ARGUMENT, "filename");
1816 return 0;
1817 }
1818
1819 rwops = SDL_RWFromFile(filename, "r");
1820 if(rwops == NULL)
1821 {
1822 GPU_PushErrorCode(__func__, GPU_ERROR_FILE_NOT_FOUND, "%s", filename);
1823 return 0;
1824 }
1825
1826 return GPU_CompileShader_RW(shader_type, rwops, 1);
1827}
1828
1829Uint32 GPU_CompileShader(GPU_ShaderEnum shader_type, const char* shader_source)
1830{
1831 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1832 return 0;
1833
1834 return _gpu_current_renderer->impl->CompileShader(_gpu_current_renderer, shader_type, shader_source);
1835}
1836
1837Uint8 GPU_LinkShaderProgram(Uint32 program_object)
1838{
1839 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1840 return 0;
1841
1842 return _gpu_current_renderer->impl->LinkShaderProgram(_gpu_current_renderer, program_object);
1843}
1844
1845Uint32 GPU_CreateShaderProgram(void)
1846{
1847 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1848 return 0;
1849
1850 return _gpu_current_renderer->impl->CreateShaderProgram(_gpu_current_renderer);
1851}
1852
1853Uint32 GPU_LinkShaders(Uint32 shader_object1, Uint32 shader_object2)
1854{
1855 Uint32 p;
1856
1857 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1858 return 0;
1859
1860 if((_gpu_current_renderer->enabled_features & GPU_FEATURE_BASIC_SHADERS) != GPU_FEATURE_BASIC_SHADERS)
1861 return 0;
1862
1863 p = _gpu_current_renderer->impl->CreateShaderProgram(_gpu_current_renderer);
1864
1865 _gpu_current_renderer->impl->AttachShader(_gpu_current_renderer, p, shader_object1);
1866 _gpu_current_renderer->impl->AttachShader(_gpu_current_renderer, p, shader_object2);
1867
1868 if(_gpu_current_renderer->impl->LinkShaderProgram(_gpu_current_renderer, p))
1869 return p;
1870
1871 _gpu_current_renderer->impl->FreeShaderProgram(_gpu_current_renderer, p);
1872 return 0;
1873}
1874
1875void GPU_FreeShader(Uint32 shader_object)
1876{
1877 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1878 return;
1879
1880 _gpu_current_renderer->impl->FreeShader(_gpu_current_renderer, shader_object);
1881}
1882
1883void GPU_FreeShaderProgram(Uint32 program_object)
1884{
1885 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1886 return;
1887
1888 _gpu_current_renderer->impl->FreeShaderProgram(_gpu_current_renderer, program_object);
1889}
1890
1891void GPU_AttachShader(Uint32 program_object, Uint32 shader_object)
1892{
1893 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1894 return;
1895
1896 _gpu_current_renderer->impl->AttachShader(_gpu_current_renderer, program_object, shader_object);
1897}
1898
1899void GPU_DetachShader(Uint32 program_object, Uint32 shader_object)
1900{
1901 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1902 return;
1903
1904 _gpu_current_renderer->impl->DetachShader(_gpu_current_renderer, program_object, shader_object);
1905}
1906
1907Uint8 GPU_IsDefaultShaderProgram(Uint32 program_object)
1908{
1909 GPU_Context* context;
1910
1911 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1912 return 0;
1913
1914 context = _gpu_current_renderer->current_context_target->context;
1915 return (program_object == context->default_textured_shader_program || program_object == context->default_untextured_shader_program);
1916}
1917
1918void GPU_ActivateShaderProgram(Uint32 program_object, GPU_ShaderBlock* block)
1919{
1920 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1921 return;
1922
1923 _gpu_current_renderer->impl->ActivateShaderProgram(_gpu_current_renderer, program_object, block);
1924}
1925
1926void GPU_DeactivateShaderProgram(void)
1927{
1928 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1929 return;
1930
1931 _gpu_current_renderer->impl->DeactivateShaderProgram(_gpu_current_renderer);
1932}
1933
1934const char* GPU_GetShaderMessage(void)
1935{
1936 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1937 return NULL;
1938
1939 return _gpu_current_renderer->impl->GetShaderMessage(_gpu_current_renderer);
1940}
1941
1942int GPU_GetAttributeLocation(Uint32 program_object, const char* attrib_name)
1943{
1944 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1945 return 0;
1946
1947 return _gpu_current_renderer->impl->GetAttributeLocation(_gpu_current_renderer, program_object, attrib_name);
1948}
1949
1950GPU_AttributeFormat GPU_MakeAttributeFormat(int num_elems_per_vertex, GPU_TypeEnum type, Uint8 normalize, int stride_bytes, int offset_bytes)
1951{
1952 GPU_AttributeFormat f;
1953 f.is_per_sprite = 0;
1954 f.num_elems_per_value = num_elems_per_vertex;
1955 f.type = type;
1956 f.normalize = normalize;
1957 f.stride_bytes = stride_bytes;
1958 f.offset_bytes = offset_bytes;
1959 return f;
1960}
1961
1962GPU_Attribute GPU_MakeAttribute(int location, void* values, GPU_AttributeFormat format)
1963{
1964 GPU_Attribute a;
1965 a.location = location;
1966 a.values = values;
1967 a.format = format;
1968 return a;
1969}
1970
1971int GPU_GetUniformLocation(Uint32 program_object, const char* uniform_name)
1972{
1973 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1974 return 0;
1975
1976 return _gpu_current_renderer->impl->GetUniformLocation(_gpu_current_renderer, program_object, uniform_name);
1977}
1978
1979GPU_ShaderBlock GPU_LoadShaderBlock(Uint32 program_object, const char* position_name, const char* texcoord_name, const char* color_name, const char* modelViewMatrix_name)
1980{
1981 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1982 {
1983 GPU_ShaderBlock b;
1984 b.position_loc = -1;
1985 b.texcoord_loc = -1;
1986 b.color_loc = -1;
1987 b.modelViewProjection_loc = -1;
1988 return b;
1989 }
1990
1991 return _gpu_current_renderer->impl->LoadShaderBlock(_gpu_current_renderer, program_object, position_name, texcoord_name, color_name, modelViewMatrix_name);
1992}
1993
1994void GPU_SetShaderBlock(GPU_ShaderBlock block)
1995{
1996 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
1997 return;
1998
1999 _gpu_current_renderer->impl->SetShaderBlock(_gpu_current_renderer, block);
2000}
2001
2002void GPU_SetShaderImage(GPU_Image* image, int location, int image_unit)
2003{
2004 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2005 return;
2006
2007 _gpu_current_renderer->impl->SetShaderImage(_gpu_current_renderer, image, location, image_unit);
2008}
2009
2010GPU_MultitextureBlock GPU_LoadMultitextureBlock(int count, char** image_names, char** texcoord_names)
2011{
2012 GPU_MultitextureBlock result;
2013 result.image_names = (char**)SDL_malloc(count * sizeof(char*));
2014 result.texcoord_names = (char**)SDL_malloc(count * sizeof(char*));
2015 for (int i = 0; i < count; ++i)
2016 {
2017 result.image_names[i] = (char*)SDL_malloc(strlen(image_names[i]) + 1);
2018 result.texcoord_names[i] = (char*)SDL_malloc(strlen(texcoord_names[i]) + 1);
2019 strcpy(result.image_names[i], image_names[i]);
2020 strcpy(result.texcoord_names[i], texcoord_names[i]);
2021 }
2022 result.num_textures = count;
2023 return result;
2024}
2025
2026void GPU_FreeMultitextureBlock(GPU_MultitextureBlock* value)
2027{
2028 int count = value->num_textures;
2029 for (int i = 0; i < count; ++i)
2030 {
2031 SDL_free(value->image_names[i]);
2032 SDL_free(value->texcoord_names[i]);
2033 }
2034 SDL_free(value->image_names);
2035 SDL_free(value->texcoord_names);
2036}
2037
2038void GPU_SetMultitextureBlock(GPU_MultitextureBlock* value)
2039{
2040 _gpu_current_renderer->multitexture_block = value;
2041}
2042
2043void GPU_MultitextureBlit(GPU_Image** images, GPU_Rect* rects, GPU_Target* target, float x, float y)
2044{
2045 if (!CHECK_RENDERER)
2046 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL renderer");
2047 MAKE_CURRENT_IF_NONE(target);
2048 if (!CHECK_CONTEXT)
2049 RETURN_ERROR(GPU_ERROR_USER_ERROR, "NULL context");
2050
2051 if (images == NULL)
2052 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "images");
2053 if (rects == NULL)
2054 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "rects");
2055 if (target == NULL)
2056 RETURN_ERROR(GPU_ERROR_NULL_ARGUMENT, "target");
2057
2058 _gpu_current_renderer->impl->MultitextureBlit(_gpu_current_renderer, images, rects, target, x, y);
2059}
2060
2061void GPU_BlitBatch(GPU_Image* image, GPU_Target* target, Uint32 num_sprites,
2062 float* values, GPU_BatchFlagEnum flags)
2063{}
2064
2065void GPU_BlitBatchSeparate(GPU_Image* image, GPU_Target* target, Uint32 num_sprites,
2066 float* positions, float* src_rects, float* colors, GPU_BatchFlagEnum flags)
2067{
2068}
2069
2070void GPU_GetUniformiv(Uint32 program_object, int location, int* values)
2071{
2072 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2073 return;
2074
2075 _gpu_current_renderer->impl->GetUniformiv(_gpu_current_renderer, program_object, location, values);
2076}
2077
2078void GPU_SetUniformi(int location, int value)
2079{
2080 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2081 return;
2082
2083 _gpu_current_renderer->impl->SetUniformi(_gpu_current_renderer, location, value);
2084}
2085
2086void GPU_SetUniformiv(int location, int num_elements_per_value, int num_values, int* values)
2087{
2088 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2089 return;
2090
2091 _gpu_current_renderer->impl->SetUniformiv(_gpu_current_renderer, location, num_elements_per_value, num_values, values);
2092}
2093
2094
2095void GPU_GetUniformuiv(Uint32 program_object, int location, unsigned int* values)
2096{
2097 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2098 return;
2099
2100 _gpu_current_renderer->impl->GetUniformuiv(_gpu_current_renderer, program_object, location, values);
2101}
2102
2103void GPU_SetUniformui(int location, unsigned int value)
2104{
2105 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2106 return;
2107
2108 _gpu_current_renderer->impl->SetUniformui(_gpu_current_renderer, location, value);
2109}
2110
2111void GPU_SetUniformuiv(int location, int num_elements_per_value, int num_values, unsigned int* values)
2112{
2113 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2114 return;
2115
2116 _gpu_current_renderer->impl->SetUniformuiv(_gpu_current_renderer, location, num_elements_per_value, num_values, values);
2117}
2118
2119
2120void GPU_GetUniformfv(Uint32 program_object, int location, float* values)
2121{
2122 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2123 return;
2124
2125 _gpu_current_renderer->impl->GetUniformfv(_gpu_current_renderer, program_object, location, values);
2126}
2127
2128void GPU_SetUniformf(int location, float value)
2129{
2130 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2131 return;
2132
2133 _gpu_current_renderer->impl->SetUniformf(_gpu_current_renderer, location, value);
2134}
2135
2136void GPU_SetUniformfv(int location, int num_elements_per_value, int num_values, float* values)
2137{
2138 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2139 return;
2140
2141 _gpu_current_renderer->impl->SetUniformfv(_gpu_current_renderer, location, num_elements_per_value, num_values, values);
2142}
2143
2144// Same as GPU_GetUniformfv()
2145void GPU_GetUniformMatrixfv(Uint32 program_object, int location, float* values)
2146{
2147 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2148 return;
2149
2150 _gpu_current_renderer->impl->GetUniformfv(_gpu_current_renderer, program_object, location, values);
2151}
2152
2153void GPU_SetUniformMatrixfv(int location, int num_matrices, int num_rows, int num_columns, Uint8 transpose, float* values)
2154{
2155 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2156 return;
2157
2158 _gpu_current_renderer->impl->SetUniformMatrixfv(_gpu_current_renderer, location, num_matrices, num_rows, num_columns, transpose, values);
2159}
2160
2161
2162void GPU_SetAttributef(int location, float value)
2163{
2164 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2165 return;
2166
2167 _gpu_current_renderer->impl->SetAttributef(_gpu_current_renderer, location, value);
2168}
2169
2170void GPU_SetAttributei(int location, int value)
2171{
2172 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2173 return;
2174
2175 _gpu_current_renderer->impl->SetAttributei(_gpu_current_renderer, location, value);
2176}
2177
2178void GPU_SetAttributeui(int location, unsigned int value)
2179{
2180 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2181 return;
2182
2183 _gpu_current_renderer->impl->SetAttributeui(_gpu_current_renderer, location, value);
2184}
2185
2186void GPU_SetAttributefv(int location, int num_elements, float* value)
2187{
2188 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2189 return;
2190
2191 _gpu_current_renderer->impl->SetAttributefv(_gpu_current_renderer, location, num_elements, value);
2192}
2193
2194void GPU_SetAttributeiv(int location, int num_elements, int* value)
2195{
2196 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2197 return;
2198
2199 _gpu_current_renderer->impl->SetAttributeiv(_gpu_current_renderer, location, num_elements, value);
2200}
2201
2202void GPU_SetAttributeuiv(int location, int num_elements, unsigned int* value)
2203{
2204 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2205 return;
2206
2207 _gpu_current_renderer->impl->SetAttributeuiv(_gpu_current_renderer, location, num_elements, value);
2208}
2209
2210void GPU_SetAttributeSource(int num_values, GPU_Attribute source)
2211{
2212 if(_gpu_current_renderer == NULL || _gpu_current_renderer->current_context_target == NULL)
2213 return;
2214
2215 _gpu_current_renderer->impl->SetAttributeSource(_gpu_current_renderer, num_values, source);
2216}
2217
2218
2219
2220
2221// gpu_strcasecmp()
2222// A portable strcasecmp() from UC Berkeley
2223/*
2224 * Copyright (c) 1987 Regents of the University of California.
2225 * All rights reserved.
2226 *
2227 * Redistribution and use in source and binary forms are permitted
2228 * provided that this notice is preserved and that due credit is given
2229 * to the University of California at Berkeley. The name of the University
2230 * may not be used to endorse or promote products derived from this
2231 * software without specific written prior permission. This software
2232 * is provided ``as is'' without express or implied warranty.
2233 */
2234
2235/*
2236 * This array is designed for mapping upper and lower case letter
2237 * together for a case independent comparison. The mappings are
2238 * based upon ascii character sequences.
2239 */
2240static const unsigned char caseless_charmap[] =
2241{
2242 '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
2243 '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
2244 '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
2245 '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
2246 '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
2247 '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
2248 '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
2249 '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
2250 '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
2251 '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
2252 '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
2253 '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
2254 '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
2255 '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
2256 '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
2257 '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
2258 '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
2259 '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
2260 '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
2261 '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
2262 '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
2263 '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
2264 '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
2265 '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
2266 '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
2267 '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
2268 '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
2269 '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
2270 '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
2271 '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
2272 '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
2273 '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
2274};
2275
2276int gpu_strcasecmp(const char* s1, const char* s2)
2277{
2278 unsigned char u1, u2;
2279
2280 for (;;)
2281 {
2282 u1 = (unsigned char) *s1++;
2283 u2 = (unsigned char) *s2++;
2284 if (caseless_charmap[u1] != caseless_charmap[u2])
2285 return caseless_charmap[u1] - caseless_charmap[u2];
2286 if (u1 == '\0')
2287 return 0;
2288 }
2289 return 0;
2290}
2291
2292
2293#ifdef _MSC_VER
2294 #pragma warning(pop)
2295#endif
2296