Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
  • master
2 results

Target

Select target project
  • et2-stoker/assignment2020resit
1 result
Select Git revision
Show changes
Showing
with 5685 additions and 0 deletions
File added
File added
File added
File added
File added
File added
File added
File added
/*
SDL_FontCache: A font cache for SDL and SDL_ttf
by Jonathan Dearborn
See SDL_FontCache.h for license info.
*/
#include "SDL_FontCache.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Visual C does not support static inline
#ifndef static_inline
#ifdef _MSC_VER
#define static_inline static
#else
#define static_inline static inline
#endif
#endif
#if SDL_VERSION_ATLEAST(2,0,0)
#define FC_GET_ALPHA(sdl_color) ((sdl_color).a)
#else
#define FC_GET_ALPHA(sdl_color) ((sdl_color).unused)
#endif
// Need SDL_RenderIsClipEnabled() for proper clipping support
#if SDL_VERSION_ATLEAST(2,0,4)
#define ENABLE_SDL_CLIPPING
#endif
#define FC_MIN(a,b) ((a) < (b)? (a) : (b))
#define FC_MAX(a,b) ((a) > (b)? (a) : (b))
// vsnprintf replacement from Valentin Milea:
// http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf c99_snprintf
#define vsnprintf c99_vsnprintf
__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
{
int count = -1;
if (size != 0)
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);
return count;
}
__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf(outBuf, size, format, ap);
va_end(ap);
return count;
}
#endif
#define FC_EXTRACT_VARARGS(buffer, start_args) \
{ \
va_list lst; \
va_start(lst, start_args); \
vsnprintf(buffer, fc_buffer_size, start_args, lst); \
va_end(lst); \
}
// Extra pixels of padding around each glyph to avoid linear filtering artifacts
#define FC_CACHE_PADDING 1
static Uint8 has_clip(FC_Target* dest)
{
#ifdef FC_USE_SDL_GPU
return dest->use_clip_rect;
#elif defined(ENABLE_SDL_CLIPPING)
return SDL_RenderIsClipEnabled(dest);
#else
return 0;
#endif
}
static FC_Rect get_clip(FC_Target* dest)
{
#ifdef FC_USE_SDL_GPU
return dest->clip_rect;
#elif defined(ENABLE_SDL_CLIPPING)
SDL_Rect r;
SDL_RenderGetClipRect(dest, &r);
return r;
#else
SDL_Rect r = {0, 0, 0, 0};
return r;
#endif
}
static void set_clip(FC_Target* dest, FC_Rect* rect)
{
#ifdef FC_USE_SDL_GPU
if(rect != NULL)
GPU_SetClipRect(dest, *rect);
else
GPU_UnsetClip(dest);
#elif defined(ENABLE_SDL_CLIPPING)
SDL_RenderSetClipRect(dest, rect);
#endif
}
static void set_color(FC_Image* src, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
#ifdef FC_USE_SDL_GPU
GPU_SetRGBA(src, r, g, b, a);
#else
SDL_SetTextureColorMod(src, r, g, b);
SDL_SetTextureAlphaMod(src, a);
#endif
}
static char* new_concat(const char* a, const char* b)
{
// Create new buffer
unsigned int size = strlen(a) + strlen(b);
char* new_string = (char*)malloc(size+1);
// Concatenate strings in the new buffer
strcpy(new_string, a);
strcat(new_string, b);
return new_string;
}
static char* replace_concat(char** a, const char* b)
{
char* new_string = new_concat(*a, b);
free(*a);
*a = new_string;
return *a;
}
// Width of a tab in units of the space width (sorry, no tab alignment!)
static unsigned int fc_tab_width = 4;
// Shared buffer for variadic text
static char* fc_buffer = NULL;
static unsigned int fc_buffer_size = 1024;
static Uint8 fc_has_render_target_support = 0;
// The number of fonts that has been created but not freed
static int NUM_EXISTING_FONTS = 0;
// Globals for GetString functions
static char* ASCII_STRING = NULL;
static char* LATIN_1_STRING = NULL;
static char* ASCII_LATIN_1_STRING = NULL;
char* FC_GetStringASCII(void)
{
if(ASCII_STRING == NULL)
{
int i;
char c;
ASCII_STRING = (char*)malloc(512);
memset(ASCII_STRING, 0, 512);
i = 0;
c = 32;
while(1)
{
ASCII_STRING[i] = c;
if(c == 126)
break;
++i;
++c;
}
}
return U8_strdup(ASCII_STRING);
}
char* FC_GetStringLatin1(void)
{
if(LATIN_1_STRING == NULL)
{
int i;
unsigned char c;
LATIN_1_STRING = (char*)malloc(512);
memset(LATIN_1_STRING, 0, 512);
i = 0;
c = 0xA0;
while(1)
{
LATIN_1_STRING[i] = 0xC2;
LATIN_1_STRING[i+1] = c;
if(c == 0xBF)
break;
i += 2;
++c;
}
i += 2;
c = 0x80;
while(1)
{
LATIN_1_STRING[i] = 0xC3;
LATIN_1_STRING[i+1] = c;
if(c == 0xBF)
break;
i += 2;
++c;
}
}
return U8_strdup(LATIN_1_STRING);
}
char* FC_GetStringASCII_Latin1(void)
{
if(ASCII_LATIN_1_STRING == NULL)
ASCII_LATIN_1_STRING = new_concat(FC_GetStringASCII(), FC_GetStringLatin1());
return U8_strdup(ASCII_LATIN_1_STRING);
}
FC_Rect FC_MakeRect(float x, float y, float w, float h)
{
FC_Rect r = {x, y, w, h};
return r;
}
FC_Scale FC_MakeScale(float x, float y)
{
FC_Scale s = {x, y};
return s;
}
SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
SDL_Color c = {r, g, b, a};
return c;
}
FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color)
{
FC_Effect e;
e.alignment = alignment;
e.scale = scale;
e.color = color;
return e;
}
FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h)
{
FC_GlyphData gd;
gd.rect.x = x;
gd.rect.y = y;
gd.rect.w = w;
gd.rect.h = h;
gd.cache_level = cache_level;
return gd;
}
// Enough to hold all of the ascii characters and some.
#define FC_DEFAULT_NUM_BUCKETS 300
typedef struct FC_MapNode
{
Uint32 key;
FC_GlyphData value;
struct FC_MapNode* next;
} FC_MapNode;
typedef struct FC_Map
{
int num_buckets;
FC_MapNode** buckets;
} FC_Map;
static FC_Map* FC_MapCreate(int num_buckets)
{
int i;
FC_Map* map = (FC_Map*)malloc(sizeof(FC_Map));
map->num_buckets = num_buckets;
map->buckets = (FC_MapNode**)malloc(num_buckets * sizeof(FC_MapNode*));
for(i = 0; i < num_buckets; ++i)
{
map->buckets[i] = NULL;
}
return map;
}
/*static void FC_MapClear(FC_Map* map)
{
int i;
if(map == NULL)
return;
// Go through each bucket
for(i = 0; i < map->num_buckets; ++i)
{
// Delete the nodes in order
FC_MapNode* node = map->buckets[i];
while(node != NULL)
{
FC_MapNode* last = node;
node = node->next;
free(last);
}
// Set the bucket to empty
map->buckets[i] = NULL;
}
}*/
static void FC_MapFree(FC_Map* map)
{
int i;
if(map == NULL)
return;
// Go through each bucket
for(i = 0; i < map->num_buckets; ++i)
{
// Delete the nodes in order
FC_MapNode* node = map->buckets[i];
while(node != NULL)
{
FC_MapNode* last = node;
node = node->next;
free(last);
}
}
free(map->buckets);
free(map);
}
// Note: Does not handle duplicates in any special way.
static FC_GlyphData* FC_MapInsert(FC_Map* map, Uint32 codepoint, FC_GlyphData glyph)
{
Uint32 index;
FC_MapNode* node;
if(map == NULL)
return NULL;
// Get index for bucket
index = codepoint % map->num_buckets;
// If this bucket is empty, create a node and return its value
if(map->buckets[index] == NULL)
{
node = map->buckets[index] = (FC_MapNode*)malloc(sizeof(FC_MapNode));
node->key = codepoint;
node->value = glyph;
node->next = NULL;
return &node->value;
}
for(node = map->buckets[index]; node != NULL; node = node->next)
{
// Find empty node and add a new one on.
if(node->next == NULL)
{
node->next = (FC_MapNode*)malloc(sizeof(FC_MapNode));
node = node->next;
node->key = codepoint;
node->value = glyph;
node->next = NULL;
return &node->value;
}
}
return NULL;
}
static FC_GlyphData* FC_MapFind(FC_Map* map, Uint32 codepoint)
{
Uint32 index;
FC_MapNode* node;
if(map == NULL)
return NULL;
// Get index for bucket
index = codepoint % map->num_buckets;
// Go through list until we find a match
for(node = map->buckets[index]; node != NULL; node = node->next)
{
if(node->key == codepoint)
return &node->value;
}
return NULL;
}
struct FC_Font
{
#ifndef FC_USE_SDL_GPU
SDL_Renderer* renderer;
#endif
TTF_Font* ttf_source; // TTF_Font source of characters
Uint8 owns_ttf_source; // Can we delete the TTF_Font ourselves?
FC_FilterEnum filter;
SDL_Color default_color;
Uint16 height;
Uint16 maxWidth;
Uint16 baseline;
int ascent;
int descent;
int lineSpacing;
int letterSpacing;
// Uses 32-bit (4-byte) Unicode codepoints to refer to each glyph
// Codepoints are little endian (reversed from UTF-8) so that something like 0x00000005 is ASCII 5 and the map can be indexed by ASCII values
FC_Map* glyphs;
FC_GlyphData last_glyph; // Texture packing cursor
int glyph_cache_size;
int glyph_cache_count;
FC_Image** glyph_cache;
char* loading_string;
};
// Private
static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight);
static FC_Rect FC_RenderLeft(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
static FC_Rect FC_RenderCenter(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
static FC_Rect FC_RenderRight(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
static_inline SDL_Surface* FC_CreateSurface32(Uint32 width, Uint32 height)
{
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
#else
return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
#endif
}
char* U8_alloc(unsigned int size)
{
char* result;
if(size == 0)
return NULL;
result = (char*)malloc(size);
result[0] = '\0';
return result;
}
void U8_free(char* string)
{
free(string);
}
char* U8_strdup(const char* string)
{
char* result;
if(string == NULL)
return NULL;
result = (char*)malloc(strlen(string)+1);
strcpy(result, string);
return result;
}
int U8_strlen(const char* string)
{
int length = 0;
if(string == NULL)
return 0;
while(*string != '\0')
{
string = U8_next(string);
++length;
}
return length;
}
int U8_charsize(const char* character)
{
if(character == NULL)
return 0;
if((unsigned char)*character <= 0x7F)
return 1;
else if((unsigned char)*character < 0xE0)
return 2;
else if((unsigned char)*character < 0xF0)
return 3;
else
return 4;
return 1;
}
int U8_charcpy(char* buffer, const char* source, int buffer_size)
{
int charsize;
if(buffer == NULL || source == NULL || buffer_size < 1)
return 0;
charsize = U8_charsize(source);
if(charsize > buffer_size)
return 0;
memcpy(buffer, source, charsize);
return charsize;
}
const char* U8_next(const char* string)
{
return string + U8_charsize(string);
}
int U8_strinsert(char* string, int position, const char* source, int max_bytes)
{
int pos_u8char;
int len;
int add_len;
int ulen;
const char* string_start = string;
if(string == NULL || source == NULL)
return 0;
len = strlen(string);
add_len = strlen(source);
ulen = U8_strlen(string);
if(position == -1)
position = ulen;
if(position < 0 || position > ulen || len + add_len + 1 > max_bytes)
return 0;
// Move string pointer to the proper position
pos_u8char = 0;
while(*string != '\0' && pos_u8char < position)
{
string = (char*)U8_next(string);
++pos_u8char;
}
// Move the rest of the string out of the way
memmove(string + add_len, string, len - (string - string_start) + 1);
// Copy in the new characters
memcpy(string, source, add_len);
return 1;
}
void U8_strdel(char* string, int position)
{
if(string == NULL || position < 0)
return;
while(*string != '\0')
{
if(position == 0)
{
int chars_to_erase = U8_charsize(string);
int remaining_bytes = strlen(string) + 1;
memmove(string, string + chars_to_erase, remaining_bytes);
break;
}
string = (char*)U8_next(string);
--position;
}
}
static_inline FC_Rect FC_RectUnion(FC_Rect A, FC_Rect B)
{
float x,x2,y,y2;
x = FC_MIN(A.x, B.x);
y = FC_MIN(A.y, B.y);
x2 = FC_MAX(A.x+A.w, B.x+B.w);
y2 = FC_MAX(A.y+A.h, B.y+B.h);
{
FC_Rect result = {x, y, FC_MAX(0, x2 - x), FC_MAX(0, y2 - y)};
return result;
}
}
// Adapted from SDL_IntersectRect
static_inline FC_Rect FC_RectIntersect(FC_Rect A, FC_Rect B)
{
FC_Rect result;
float Amin, Amax, Bmin, Bmax;
// Horizontal intersection
Amin = A.x;
Amax = Amin + A.w;
Bmin = B.x;
Bmax = Bmin + B.w;
if(Bmin > Amin)
Amin = Bmin;
result.x = Amin;
if(Bmax < Amax)
Amax = Bmax;
result.w = Amax - Amin > 0 ? Amax - Amin : 0;
// Vertical intersection
Amin = A.y;
Amax = Amin + A.h;
Bmin = B.y;
Bmax = Bmin + B.h;
if(Bmin > Amin)
Amin = Bmin;
result.y = Amin;
if(Bmax < Amax)
Amax = Bmax;
result.h = Amax - Amin > 0 ? Amax - Amin : 0;
return result;
}
FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale)
{
float w = srcrect->w * xscale;
float h = srcrect->h * yscale;
FC_Rect result;
// FIXME: Why does the scaled offset look so wrong?
#ifdef FC_USE_SDL_GPU
{
GPU_Rect r = *srcrect;
GPU_BlitScale(src, &r, dest, x + xscale*r.w/2.0f, y + r.h/2.0f, xscale, yscale);
}
#else
{
SDL_RendererFlip flip = SDL_FLIP_NONE;
if(xscale < 0)
{
xscale = -xscale;
flip = (SDL_RendererFlip) ((int)flip | (int)SDL_FLIP_HORIZONTAL);
}
if(yscale < 0)
{
yscale = -yscale;
flip = (SDL_RendererFlip) ((int)flip | (int)SDL_FLIP_VERTICAL);
}
SDL_Rect r = *srcrect;
SDL_Rect dr = {(int)x, (int)y, (int)(xscale*r.w), (int)(yscale*r.h)};
SDL_RenderCopyEx(dest, src, &r, &dr, 0, NULL, flip);
}
#endif
result.x = x;
result.y = y;
result.w = w;
result.h = h;
return result;
}
static FC_Rect (*fc_render_callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale) = &FC_DefaultRenderCallback;
void FC_SetRenderCallback(FC_Rect (*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale))
{
if(callback == NULL)
fc_render_callback = &FC_DefaultRenderCallback;
else
fc_render_callback = callback;
}
void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint)
{
char a, b, c, d;
if(result == NULL)
return;
a = (codepoint >> 24) & 0xFF;
b = (codepoint >> 16) & 0xFF;
c = (codepoint >> 8) & 0xFF;
d = codepoint & 0xFF;
if(a == 0)
{
if(b == 0)
{
if(c == 0)
{
result[0] = d;
result[1] = '\0';
}
else
{
result[0] = c;
result[1] = d;
result[2] = '\0';
}
}
else
{
result[0] = b;
result[1] = c;
result[2] = d;
result[3] = '\0';
}
}
else
{
result[0] = a;
result[1] = b;
result[2] = c;
result[3] = d;
result[4] = '\0';
}
}
Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer)
{
Uint32 result = 0;
const char* str;
if(c == NULL || *c == NULL)
return 0;
str = *c;
if((unsigned char)*str <= 0x7F)
result = *str;
else if((unsigned char)*str < 0xE0)
{
result |= (unsigned char)(*str) << 8;
result |= (unsigned char)(*(str+1));
if(advance_pointer)
*c += 1;
}
else if((unsigned char)*str < 0xF0)
{
result |= (unsigned char)(*str) << 16;
result |= (unsigned char)(*(str+1)) << 8;
result |= (unsigned char)(*(str+2));
if(advance_pointer)
*c += 2;
}
else
{
result |= (unsigned char)(*str) << 24;
result |= (unsigned char)(*(str+1)) << 16;
result |= (unsigned char)(*(str+2)) << 8;
result |= (unsigned char)(*(str+3));
if(advance_pointer)
*c += 3;
}
return result;
}
void FC_SetLoadingString(FC_Font* font, const char* string)
{
if(font == NULL)
return;
free(font->loading_string);
font->loading_string = U8_strdup(string);
}
unsigned int FC_GetBufferSize(void)
{
return fc_buffer_size;
}
void FC_SetBufferSize(unsigned int size)
{
free(fc_buffer);
if(size > 0)
{
fc_buffer_size = size;
fc_buffer = (char*)malloc(fc_buffer_size);
}
else
fc_buffer = (char*)malloc(fc_buffer_size);
}
unsigned int FC_GetTabWidth(void)
{
return fc_tab_width;
}
void FC_SetTabWidth(unsigned int width_in_spaces)
{
fc_tab_width = width_in_spaces;
}
// Constructors
static void FC_Init(FC_Font* font)
{
if(font == NULL)
return;
#ifndef FC_USE_SDL_GPU
font->renderer = NULL;
#endif
font->ttf_source = NULL;
font->owns_ttf_source = 0;
font->filter = FC_FILTER_NEAREST;
font->default_color.r = 0;
font->default_color.g = 0;
font->default_color.b = 0;
FC_GET_ALPHA(font->default_color) = 255;
font->height = 0; // ascent+descent
font->maxWidth = 0;
font->baseline = 0;
font->ascent = 0;
font->descent = 0;
font->lineSpacing = 0;
font->letterSpacing = 0;
// Give a little offset for when filtering/mipmaps are used. Depending on mipmap level, this will still not be enough.
font->last_glyph.rect.x = FC_CACHE_PADDING;
font->last_glyph.rect.y = FC_CACHE_PADDING;
font->last_glyph.rect.w = 0;
font->last_glyph.rect.h = 0;
font->last_glyph.cache_level = 0;
if(font->glyphs != NULL)
FC_MapFree(font->glyphs);
font->glyphs = FC_MapCreate(FC_DEFAULT_NUM_BUCKETS);
font->glyph_cache_size = 3;
font->glyph_cache_count = 0;
font->glyph_cache = (FC_Image**)malloc(font->glyph_cache_size * sizeof(FC_Image*));
if (font->loading_string == NULL)
font->loading_string = FC_GetStringASCII();
if(fc_buffer == NULL)
fc_buffer = (char*)malloc(fc_buffer_size);
}
static Uint8 FC_GrowGlyphCache(FC_Font* font)
{
if(font == NULL)
return 0;
#ifdef FC_USE_SDL_GPU
GPU_Image* new_level = GPU_CreateImage(font->height * 12, font->height * 12, GPU_FORMAT_RGBA);
GPU_SetAnchor(new_level, 0.5f, 0.5f); // Just in case the default is different
#else
SDL_Texture* new_level = SDL_CreateTexture(font->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, font->height * 12, font->height * 12);
#endif
if(new_level == NULL || !FC_SetGlyphCacheLevel(font, font->glyph_cache_count, new_level))
{
FC_Log("Error: SDL_FontCache ran out of packing space and could not add another cache level.\n");
#ifdef FC_USE_SDL_GPU
GPU_FreeImage(new_level);
#else
SDL_DestroyTexture(new_level);
#endif
return 0;
}
// bug: we do not have the correct color here, this might be the wrong color!
// , most functions use set_color_for_all_caches()
// - for evading this bug, you must use FC_SetDefaultColor(), before using any draw functions
set_color(new_level, font->default_color.r, font->default_color.g, font->default_color.b, FC_GET_ALPHA(font->default_color));
#ifndef FC_USE_SDL_GPU
{
Uint8 r, g, b, a;
SDL_Texture* prev_target = SDL_GetRenderTarget(font->renderer);
SDL_Rect prev_clip, prev_viewport;
int prev_logicalw, prev_logicalh;
Uint8 prev_clip_enabled;
float prev_scalex, prev_scaley;
// only backup if previous target existed (SDL will preserve them for the default target)
if (prev_target) {
prev_clip_enabled = has_clip(font->renderer);
if (prev_clip_enabled)
prev_clip = get_clip(font->renderer);
SDL_RenderGetViewport(font->renderer, &prev_viewport);
SDL_RenderGetScale(font->renderer, &prev_scalex, &prev_scaley);
SDL_RenderGetLogicalSize(font->renderer, &prev_logicalw, &prev_logicalh);
}
SDL_SetTextureBlendMode(new_level, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(font->renderer, new_level);
SDL_GetRenderDrawColor(font->renderer, &r, &g, &b, &a);
SDL_SetRenderDrawColor(font->renderer, 0, 0, 0, 0);
SDL_RenderClear(font->renderer);
SDL_SetRenderDrawColor(font->renderer, r, g, b, a);
SDL_SetRenderTarget(font->renderer, prev_target);
if (prev_target) {
if (prev_clip_enabled)
set_clip(font->renderer, &prev_clip);
if (prev_logicalw && prev_logicalh)
SDL_RenderSetLogicalSize(font->renderer, prev_logicalw, prev_logicalh);
else {
SDL_RenderSetViewport(font->renderer, &prev_viewport);
SDL_RenderSetScale(font->renderer, prev_scalex, prev_scaley);
}
}
}
#endif
return 1;
}
Uint8 FC_UploadGlyphCache(FC_Font* font, int cache_level, SDL_Surface* data_surface)
{
if(font == NULL || data_surface == NULL)
return 0;
#ifdef FC_USE_SDL_GPU
GPU_Image* new_level = GPU_CopyImageFromSurface(data_surface);
GPU_SetAnchor(new_level, 0.5f, 0.5f); // Just in case the default is different
if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
GPU_SetImageFilter(new_level, GPU_FILTER_LINEAR);
else
GPU_SetImageFilter(new_level, GPU_FILTER_NEAREST);
#else
SDL_Texture* new_level;
if(!fc_has_render_target_support)
new_level = SDL_CreateTextureFromSurface(font->renderer, data_surface);
else
{
// Must upload with render target enabled so we can put more glyphs on later
SDL_Renderer* renderer = font->renderer;
// Set filter mode for new texture
char old_filter_mode[16]; // Save it so we can change the hint value in the meantime
const char* old_filter_hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
if(!old_filter_hint)
old_filter_hint = "nearest";
snprintf(old_filter_mode, 16, "%s", old_filter_hint);
if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
else
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
new_level = SDL_CreateTexture(renderer, data_surface->format->format, SDL_TEXTUREACCESS_TARGET, data_surface->w, data_surface->h);
SDL_SetTextureBlendMode(new_level, SDL_BLENDMODE_BLEND);
// Reset filter mode for the temp texture
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
{
Uint8 r, g, b, a;
SDL_Texture* temp = SDL_CreateTextureFromSurface(renderer, data_surface);
SDL_Texture* prev_target = SDL_GetRenderTarget(renderer);
SDL_Rect prev_clip, prev_viewport;
int prev_logicalw, prev_logicalh;
Uint8 prev_clip_enabled;
float prev_scalex, prev_scaley;
// only backup if previous target existed (SDL will preserve them for the default target)
if (prev_target) {
prev_clip_enabled = has_clip(renderer);
if (prev_clip_enabled)
prev_clip = get_clip(renderer);
SDL_RenderGetViewport(renderer, &prev_viewport);
SDL_RenderGetScale(renderer, &prev_scalex, &prev_scaley);
SDL_RenderGetLogicalSize(renderer, &prev_logicalw, &prev_logicalh);
}
SDL_SetTextureBlendMode(temp, SDL_BLENDMODE_NONE);
SDL_SetRenderTarget(renderer, new_level);
SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, r, g, b, a);
SDL_RenderCopy(renderer, temp, NULL, NULL);
SDL_SetRenderTarget(renderer, prev_target);
if (prev_target) {
if (prev_clip_enabled)
set_clip(renderer, &prev_clip);
if (prev_logicalw && prev_logicalh)
SDL_RenderSetLogicalSize(renderer, prev_logicalw, prev_logicalh);
else {
SDL_RenderSetViewport(renderer, &prev_viewport);
SDL_RenderSetScale(renderer, prev_scalex, prev_scaley);
}
}
SDL_DestroyTexture(temp);
}
// Reset to the old filter value
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, old_filter_mode);
}
#endif
if(new_level == NULL || !FC_SetGlyphCacheLevel(font, cache_level, new_level))
{
FC_Log("Error: SDL_FontCache ran out of packing space and could not add another cache level.\n");
#ifdef FC_USE_SDL_GPU
GPU_FreeImage(new_level);
#else
SDL_DestroyTexture(new_level);
#endif
return 0;
}
return 1;
}
static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight)
{
FC_Map* glyphs = font->glyphs;
FC_GlyphData* last_glyph = &font->last_glyph;
Uint16 height = font->height + FC_CACHE_PADDING;
// TAB is special!
if(codepoint == '\t')
{
FC_GlyphData spaceGlyph;
FC_GetGlyphData(font, &spaceGlyph, ' ');
width = fc_tab_width * spaceGlyph.rect.w;
}
if(last_glyph->rect.x + last_glyph->rect.w + width >= maxWidth - FC_CACHE_PADDING)
{
if(last_glyph->rect.y + height + height >= maxHeight - FC_CACHE_PADDING)
{
// Get ready to pack on the next cache level when it is ready
last_glyph->cache_level = font->glyph_cache_count;
last_glyph->rect.x = FC_CACHE_PADDING;
last_glyph->rect.y = FC_CACHE_PADDING;
last_glyph->rect.w = 0;
return NULL;
}
else
{
// Go to next row
last_glyph->rect.x = FC_CACHE_PADDING;
last_glyph->rect.y += height;
last_glyph->rect.w = 0;
}
}
// Move to next space
last_glyph->rect.x += last_glyph->rect.w + 1 + FC_CACHE_PADDING;
last_glyph->rect.w = width;
return FC_MapInsert(glyphs, codepoint, FC_MakeGlyphData(last_glyph->cache_level, last_glyph->rect.x, last_glyph->rect.y, last_glyph->rect.w, last_glyph->rect.h));
}
FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level)
{
if(font == NULL || cache_level < 0 || cache_level > font->glyph_cache_count)
return NULL;
return font->glyph_cache[cache_level];
}
Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture)
{
if(font == NULL || cache_level < 0)
return 0;
// Must be sequentially added
if(cache_level > font->glyph_cache_count + 1)
return 0;
if(cache_level == font->glyph_cache_count)
{
font->glyph_cache_count++;
// Grow cache?
if(font->glyph_cache_count > font->glyph_cache_size)
{
// Copy old cache to new one
int i;
FC_Image** new_cache;
new_cache = (FC_Image**)malloc(font->glyph_cache_count * sizeof(FC_Image*));
for(i = 0; i < font->glyph_cache_size; ++i)
new_cache[i] = font->glyph_cache[i];
// Save new cache
free(font->glyph_cache);
font->glyph_cache_size = font->glyph_cache_count;
font->glyph_cache = new_cache;
}
}
font->glyph_cache[cache_level] = cache_texture;
return 1;
}
FC_Font* FC_CreateFont(void)
{
FC_Font* font;
font = (FC_Font*)malloc(sizeof(FC_Font));
memset(font, 0, sizeof(FC_Font));
FC_Init(font);
++NUM_EXISTING_FONTS;
return font;
}
// Assume this many will be enough...
#define FC_LOAD_MAX_SURFACES 10
#ifdef FC_USE_SDL_GPU
Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color)
#else
Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color)
#endif
{
if(font == NULL || ttf == NULL)
return 0;
#ifndef FC_USE_SDL_GPU
if(renderer == NULL)
return 0;
#endif
FC_ClearFont(font);
// Might as well check render target support here
#ifdef FC_USE_SDL_GPU
fc_has_render_target_support = GPU_IsFeatureEnabled(GPU_FEATURE_RENDER_TARGETS);
#else
SDL_RendererInfo info;
SDL_GetRendererInfo(renderer, &info);
fc_has_render_target_support = (info.flags & SDL_RENDERER_TARGETTEXTURE);
font->renderer = renderer;
#endif
font->ttf_source = ttf;
//font->line_height = TTF_FontLineSkip(ttf);
font->height = TTF_FontHeight(ttf);
font->ascent = TTF_FontAscent(ttf);
font->descent = -TTF_FontDescent(ttf);
// Some bug for certain fonts can result in an incorrect height.
if(font->height < font->ascent - font->descent)
font->height = font->ascent - font->descent;
font->baseline = font->height - font->descent;
font->default_color = color;
{
SDL_Color white = {255, 255, 255, 255};
SDL_Surface* glyph_surf;
char buff[5];
const char* buff_ptr = buff;
const char* source_string;
Uint8 packed = 0;
// Copy glyphs from the surface to the font texture and store the position data
// Pack row by row into a square texture
// Try figuring out dimensions that make sense for the font size.
unsigned int w = font->height*12;
unsigned int h = font->height*12;
SDL_Surface* surfaces[FC_LOAD_MAX_SURFACES];
int num_surfaces = 1;
surfaces[0] = FC_CreateSurface32(w, h);
font->last_glyph.rect.x = FC_CACHE_PADDING;
font->last_glyph.rect.y = FC_CACHE_PADDING;
font->last_glyph.rect.w = 0;
font->last_glyph.rect.h = font->height;
source_string = font->loading_string;
for(; *source_string != '\0'; source_string = U8_next(source_string))
{
memset(buff, 0, 5);
if(!U8_charcpy(buff, source_string, 5))
continue;
glyph_surf = TTF_RenderUTF8_Blended(ttf, buff, white);
if(glyph_surf == NULL)
continue;
// Try packing. If it fails, create a new surface for the next cache level.
packed = (FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces-1]->w, surfaces[num_surfaces-1]->h) != NULL);
if(!packed)
{
int i = num_surfaces-1;
if(num_surfaces >= FC_LOAD_MAX_SURFACES)
{
// Can't do any more!
FC_Log("SDL_FontCache error: Could not create enough cache surfaces to fit all of the loading string!\n");
SDL_FreeSurface(glyph_surf);
break;
}
// Upload the current surface to the glyph cache now so we can keep the cache level packing cursor up to date as we go.
FC_UploadGlyphCache(font, i, surfaces[i]);
SDL_FreeSurface(surfaces[i]);
#ifndef FC_USE_SDL_GPU
SDL_SetTextureBlendMode(font->glyph_cache[i], SDL_BLENDMODE_BLEND);
#endif
// Update the glyph cursor to the new cache level. We need to do this here because the actual cache lags behind our use of the packing above.
font->last_glyph.cache_level = num_surfaces;
surfaces[num_surfaces] = FC_CreateSurface32(w, h);
num_surfaces++;
}
// Try packing for the new surface, then blit onto it.
if(packed || FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces-1]->w, surfaces[num_surfaces-1]->h) != NULL)
{
SDL_SetSurfaceBlendMode(glyph_surf, SDL_BLENDMODE_NONE);
SDL_Rect srcRect = {0, 0, glyph_surf->w, glyph_surf->h};
SDL_Rect destrect = font->last_glyph.rect;
SDL_BlitSurface(glyph_surf, &srcRect, surfaces[num_surfaces-1], &destrect);
}
SDL_FreeSurface(glyph_surf);
}
{
int i = num_surfaces-1;
FC_UploadGlyphCache(font, i, surfaces[i]);
SDL_FreeSurface(surfaces[i]);
#ifndef FC_USE_SDL_GPU
SDL_SetTextureBlendMode(font->glyph_cache[i], SDL_BLENDMODE_BLEND);
#endif
}
}
return 1;
}
#ifdef FC_USE_SDL_GPU
Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style)
#else
Uint8 FC_LoadFont(FC_Font* font, FC_Target* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style)
#endif
{
SDL_RWops* rwops;
if(font == NULL)
return 0;
rwops = SDL_RWFromFile(filename_ttf, "rb");
if(rwops == NULL)
{
FC_Log("Unable to open file for reading: %s \n", SDL_GetError());
return 0;
}
#ifdef FC_USE_SDL_GPU
return FC_LoadFont_RW(font, rwops, 1, pointSize, color, style);
#else
return FC_LoadFont_RW(font, renderer, rwops, 1, pointSize, color, style);
#endif
}
#ifdef FC_USE_SDL_GPU
Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style)
#else
Uint8 FC_LoadFont_RW(FC_Font* font, FC_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style)
#endif
{
Uint8 result;
TTF_Font* ttf;
Uint8 outline;
if(font == NULL)
return 0;
if(!TTF_WasInit() && TTF_Init() < 0)
{
FC_Log("Unable to initialize SDL_ttf: %s \n", TTF_GetError());
if(own_rwops)
SDL_RWclose(file_rwops_ttf);
return 0;
}
ttf = TTF_OpenFontRW(file_rwops_ttf, own_rwops, pointSize);
if(ttf == NULL)
{
FC_Log("Unable to load TrueType font: %s \n", TTF_GetError());
if(own_rwops)
SDL_RWclose(file_rwops_ttf);
return 0;
}
outline = (style & TTF_STYLE_OUTLINE);
if(outline)
{
style &= ~TTF_STYLE_OUTLINE;
TTF_SetFontOutline(ttf, 1);
}
TTF_SetFontStyle(ttf, style);
#ifdef FC_USE_SDL_GPU
result = FC_LoadFontFromTTF(font, ttf, color);
#else
result = FC_LoadFontFromTTF(font, renderer, ttf, color);
#endif
// Can only load new (uncached) glyphs if we can keep the SDL_RWops open.
font->owns_ttf_source = own_rwops;
if(!own_rwops)
{
TTF_CloseFont(font->ttf_source);
font->ttf_source = NULL;
}
return result;
}
#ifndef FC_USE_SDL_GPU
void FC_ResetFontFromRendererReset(FC_Font* font, SDL_Renderer* renderer, Uint32 evType)
{
TTF_Font* ttf;
SDL_Color col;
Uint8 owns_ttf;
if (font == NULL)
return;
// Destroy glyph cache
if (evType == SDL_RENDER_TARGETS_RESET) {
int i;
for (i = 0; i < font->glyph_cache_count; ++i)
SDL_DestroyTexture(font->glyph_cache[i]);
}
free(font->glyph_cache);
ttf = font->ttf_source;
col = font->default_color;
owns_ttf = font->owns_ttf_source;
FC_Init(font);
// Can only reload glyphs if we own the SDL_RWops.
if (owns_ttf)
FC_LoadFontFromTTF(font, renderer, ttf, col);
font->owns_ttf_source = owns_ttf;
}
#endif
void FC_ClearFont(FC_Font* font)
{
int i;
if(font == NULL)
return;
// Release resources
if(font->owns_ttf_source)
TTF_CloseFont(font->ttf_source);
font->owns_ttf_source = 0;
font->ttf_source = NULL;
// Delete glyph map
FC_MapFree(font->glyphs);
font->glyphs = NULL;
// Delete glyph cache
for(i = 0; i < font->glyph_cache_count; ++i)
{
#ifdef FC_USE_SDL_GPU
GPU_FreeImage(font->glyph_cache[i]);
#else
SDL_DestroyTexture(font->glyph_cache[i]);
#endif
}
free(font->glyph_cache);
font->glyph_cache = NULL;
// Reset font
FC_Init(font);
}
void FC_FreeFont(FC_Font* font)
{
int i;
if(font == NULL)
return;
// Release resources
if(font->owns_ttf_source)
TTF_CloseFont(font->ttf_source);
// Delete glyph map
FC_MapFree(font->glyphs);
// Delete glyph cache
for(i = 0; i < font->glyph_cache_count; ++i)
{
#ifdef FC_USE_SDL_GPU
GPU_FreeImage(font->glyph_cache[i]);
#else
SDL_DestroyTexture(font->glyph_cache[i]);
#endif
}
free(font->glyph_cache);
free(font->loading_string);
free(font);
// If the last font has been freed; assume shutdown and free the global variables
if (--NUM_EXISTING_FONTS <= 0)
{
free(ASCII_STRING);
ASCII_STRING = NULL;
free(LATIN_1_STRING);
LATIN_1_STRING = NULL;
free(ASCII_LATIN_1_STRING);
ASCII_LATIN_1_STRING = NULL;
free(fc_buffer);
fc_buffer = NULL;
}
}
int FC_GetNumCacheLevels(FC_Font* font)
{
return font->glyph_cache_count;
}
Uint8 FC_AddGlyphToCache(FC_Font* font, SDL_Surface* glyph_surface)
{
if(font == NULL || glyph_surface == NULL)
return 0;
SDL_SetSurfaceBlendMode(glyph_surface, SDL_BLENDMODE_NONE);
FC_Image* dest = FC_GetGlyphCacheLevel(font, font->last_glyph.cache_level);
if(dest == NULL)
return 0;
#ifdef FC_USE_SDL_GPU
{
GPU_Target* target = GPU_LoadTarget(dest);
if(target == NULL)
return 0;
GPU_Image* img = GPU_CopyImageFromSurface(glyph_surface);
GPU_SetAnchor(img, 0.5f, 0.5f); // Just in case the default is different
GPU_SetImageFilter(img, GPU_FILTER_NEAREST);
GPU_SetBlendMode(img, GPU_BLEND_SET);
SDL_Rect destrect = font->last_glyph.rect;
GPU_Blit(img, NULL, target, destrect.x + destrect.w/2, destrect.y + destrect.h/2);
GPU_FreeImage(img);
GPU_FreeTarget(target);
}
#else
{
SDL_Renderer* renderer = font->renderer;
SDL_Texture* img;
SDL_Rect destrect;
SDL_Texture* prev_target = SDL_GetRenderTarget(renderer);
SDL_Rect prev_clip, prev_viewport;
int prev_logicalw, prev_logicalh;
Uint8 prev_clip_enabled;
float prev_scalex, prev_scaley;
// only backup if previous target existed (SDL will preserve them for the default target)
if (prev_target) {
prev_clip_enabled = has_clip(renderer);
if (prev_clip_enabled)
prev_clip = get_clip(renderer);
SDL_RenderGetViewport(renderer, &prev_viewport);
SDL_RenderGetScale(renderer, &prev_scalex, &prev_scaley);
SDL_RenderGetLogicalSize(renderer, &prev_logicalw, &prev_logicalh);
}
img = SDL_CreateTextureFromSurface(renderer, glyph_surface);
destrect = font->last_glyph.rect;
SDL_SetRenderTarget(renderer, dest);
SDL_RenderCopy(renderer, img, NULL, &destrect);
SDL_SetRenderTarget(renderer, prev_target);
if (prev_target) {
if (prev_clip_enabled)
set_clip(renderer, &prev_clip);
if (prev_logicalw && prev_logicalh)
SDL_RenderSetLogicalSize(renderer, prev_logicalw, prev_logicalh);
else {
SDL_RenderSetViewport(renderer, &prev_viewport);
SDL_RenderSetScale(renderer, prev_scalex, prev_scaley);
}
}
SDL_DestroyTexture(img);
}
#endif
return 1;
}
unsigned int FC_GetNumCodepoints(FC_Font* font)
{
FC_Map* glyphs;
int i;
unsigned int result = 0;
if(font == NULL || font->glyphs == NULL)
return 0;
glyphs = font->glyphs;
for(i = 0; i < glyphs->num_buckets; ++i)
{
FC_MapNode* node;
for(node = glyphs->buckets[i]; node != NULL; node = node->next)
{
result++;
}
}
return result;
}
void FC_GetCodepoints(FC_Font* font, Uint32* result)
{
FC_Map* glyphs;
int i;
unsigned int count = 0;
if(font == NULL || font->glyphs == NULL)
return;
glyphs = font->glyphs;
for(i = 0; i < glyphs->num_buckets; ++i)
{
FC_MapNode* node;
for(node = glyphs->buckets[i]; node != NULL; node = node->next)
{
result[count] = node->key;
count++;
}
}
}
Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint)
{
FC_GlyphData* e = FC_MapFind(font->glyphs, codepoint);
if(e == NULL)
{
char buff[5];
int w, h;
SDL_Color white = {255, 255, 255, 255};
SDL_Surface* surf;
FC_Image* cache_image;
if(font->ttf_source == NULL)
return 0;
FC_GetUTF8FromCodepoint(buff, codepoint);
cache_image = FC_GetGlyphCacheLevel(font, font->last_glyph.cache_level);
if(cache_image == NULL)
{
FC_Log("SDL_FontCache: Failed to load cache image, so cannot add new glyphs!\n");
return 0;
}
#ifdef FC_USE_SDL_GPU
w = cache_image->w;
h = cache_image->h;
#else
SDL_QueryTexture(cache_image, NULL, NULL, &w, &h);
#endif
surf = TTF_RenderUTF8_Blended(font->ttf_source, buff, white);
if(surf == NULL)
{
return 0;
}
e = FC_PackGlyphData(font, codepoint, surf->w, w, h);
if(e == NULL)
{
// Grow the cache
FC_GrowGlyphCache(font);
// Try packing again
e = FC_PackGlyphData(font, codepoint, surf->w, w, h);
if(e == NULL)
{
SDL_FreeSurface(surf);
return 0;
}
}
// Render onto the cache texture
FC_AddGlyphToCache(font, surf);
SDL_FreeSurface(surf);
}
if(result != NULL && e != NULL)
*result = *e;
return 1;
}
FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data)
{
return FC_MapInsert(font->glyphs, codepoint, glyph_data);
}
// Drawing
static FC_Rect FC_RenderLeft(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
{
const char* c = text;
FC_Rect srcRect;
FC_Rect dstRect;
FC_Rect dirtyRect = FC_MakeRect(x, y, 0, 0);
FC_GlyphData glyph;
Uint32 codepoint;
float destX = x;
float destY = y;
float destH;
float destLineSpacing;
float destLetterSpacing;
if(font == NULL)
return dirtyRect;
destH = font->height * scale.y;
destLineSpacing = font->lineSpacing*scale.y;
destLetterSpacing = font->letterSpacing*scale.x;
if(c == NULL || font->glyph_cache_count == 0 || dest == NULL)
return dirtyRect;
int newlineX = x;
for(; *c != '\0'; c++)
{
if(*c == '\n')
{
destX = newlineX;
destY += destH + destLineSpacing;
continue;
}
codepoint = FC_GetCodepointFromUTF8(&c, 1); // Increments 'c' to skip the extra UTF-8 bytes
if(!FC_GetGlyphData(font, &glyph, codepoint))
{
codepoint = ' ';
if(!FC_GetGlyphData(font, &glyph, codepoint))
continue; // Skip bad characters
}
if (codepoint == ' ')
{
destX += glyph.rect.w*scale.x + destLetterSpacing;
continue;
}
/*if(destX >= dest->w)
continue;
if(destY >= dest->h)
continue;*/
#ifdef FC_USE_SDL_GPU
srcRect.x = glyph.rect.x;
srcRect.y = glyph.rect.y;
srcRect.w = glyph.rect.w;
srcRect.h = glyph.rect.h;
#else
srcRect = glyph.rect;
#endif
dstRect = fc_render_callback(FC_GetGlyphCacheLevel(font, glyph.cache_level), &srcRect, dest, destX, destY, scale.x, scale.y);
if(dirtyRect.w == 0 || dirtyRect.h == 0)
dirtyRect = dstRect;
else
dirtyRect = FC_RectUnion(dirtyRect, dstRect);
destX += glyph.rect.w*scale.x + destLetterSpacing;
}
return dirtyRect;
}
static void set_color_for_all_caches(FC_Font* font, SDL_Color color)
{
// TODO: How can I predict which glyph caches are to be used?
FC_Image* img;
int i;
int num_levels = FC_GetNumCacheLevels(font);
for(i = 0; i < num_levels; ++i)
{
img = FC_GetGlyphCacheLevel(font, i);
set_color(img, color.r, color.g, color.b, FC_GET_ALPHA(color));
}
}
FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...)
{
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, font->default_color);
return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
}
typedef struct FC_StringList
{
char* value;
struct FC_StringList* next;
} FC_StringList;
void FC_StringListFree(FC_StringList* node)
{
// Delete the nodes in order
while(node != NULL)
{
FC_StringList* last = node;
node = node->next;
free(last->value);
free(last);
}
}
FC_StringList** FC_StringListPushBack(FC_StringList** node, char* value, Uint8 copy)
{
if(node == NULL)
{
return NULL;
}
// Get to the last node
while(*node != NULL)
{
node = &(*node)->next;
}
*node = (FC_StringList*)malloc(sizeof(FC_StringList));
(*node)->value = (copy? U8_strdup(value) : value);
(*node)->next = NULL;
return node;
}
FC_StringList** FC_StringListPushBackBytes(FC_StringList** node, const char* data, int num_bytes)
{
if(node == NULL)
{
return node;
}
// Get to the last node
while(*node != NULL)
{
node = &(*node)->next;
}
*node = (FC_StringList*)malloc(sizeof(FC_StringList));
(*node)->value = (char*)malloc(num_bytes + 1);
memcpy((*node)->value, data, num_bytes);
(*node)->value[num_bytes] = '\0';
(*node)->next = NULL;
return node;
}
static FC_StringList* FC_Explode(const char* text, char delimiter)
{
FC_StringList* head;
FC_StringList* new_node;
FC_StringList** node;
const char* start;
const char* end;
unsigned int size;
if(text == NULL)
return NULL;
head = NULL;
node = &head;
// Doesn't technically support UTF-8, but it's probably fine, right?
size = 0;
start = end = text;
while(1)
{
if(*end == delimiter || *end == '\0')
{
*node = (FC_StringList*)malloc(sizeof(FC_StringList));
new_node = *node;
new_node->value = (char*)malloc(size + 1);
memcpy(new_node->value, start, size);
new_node->value[size] = '\0';
new_node->next = NULL;
if(*end == '\0')
break;
node = &((*node)->next);
start = end+1;
size = 0;
}
else
++size;
++end;
}
return head;
}
static FC_StringList* FC_ExplodeBreakingSpace(const char* text, FC_StringList** spaces)
{
FC_StringList* head;
FC_StringList** node;
const char* start;
const char* end;
unsigned int size;
if(text == NULL)
return NULL;
head = NULL;
node = &head;
// Warning: spaces must not be initialized before this function
*spaces = NULL;
// Doesn't technically support UTF-8, but it's probably fine, right?
size = 0;
start = end = text;
while(1)
{
// Add any characters here that should make separate words (except for \n?)
if(*end == ' ' || *end == '\t' || *end == '\0')
{
FC_StringListPushBackBytes(node, start, size);
FC_StringListPushBackBytes(spaces, end, 1);
if(*end == '\0')
break;
node = &((*node)->next);
start = end+1;
size = 0;
}
else
++size;
++end;
}
return head;
}
static FC_StringList* FC_ExplodeAndKeep(const char* text, char delimiter)
{
FC_StringList* head;
FC_StringList** node;
const char* start;
const char* end;
unsigned int size;
if(text == NULL)
return NULL;
head = NULL;
node = &head;
// Doesn't technically support UTF-8, but it's probably fine, right?
size = 0;
start = end = text;
while(1)
{
if(*end == delimiter || *end == '\0')
{
FC_StringListPushBackBytes(node, start, size);
if(*end == '\0')
break;
node = &((*node)->next);
start = end;
size = 1;
}
else
++size;
++end;
}
return head;
}
static void FC_RenderAlign(FC_Font* font, FC_Target* dest, float x, float y, int width, FC_Scale scale, FC_AlignEnum align, const char* text)
{
switch(align)
{
case FC_ALIGN_LEFT:
FC_RenderLeft(font, dest, x, y, scale, text);
break;
case FC_ALIGN_CENTER:
FC_RenderCenter(font, dest, x + width/2, y, scale, text);
break;
case FC_ALIGN_RIGHT:
FC_RenderRight(font, dest, x + width, y, scale, text);
break;
}
}
static FC_StringList* FC_GetBufferFitToColumn(FC_Font* font, int width, FC_Scale scale, Uint8 keep_newlines)
{
FC_StringList* result = NULL;
FC_StringList** current = &result;
FC_StringList *ls, *iter;
ls = (keep_newlines? FC_ExplodeAndKeep(fc_buffer, '\n') : FC_Explode(fc_buffer, '\n'));
for(iter = ls; iter != NULL; iter = iter->next)
{
char* line = iter->value;
// If line is too long, then add words one at a time until we go over.
if(width > 0 && FC_GetWidth(font, "%s", line) > width)
{
FC_StringList *words, *word_iter, *spaces, *spaces_iter;
words = FC_ExplodeBreakingSpace(line, &spaces);
// Skip the first word for the iterator, so there will always be at least one word per line
line = new_concat(words->value, spaces->value);
for(word_iter = words->next, spaces_iter = spaces->next; word_iter != NULL && spaces_iter != NULL; word_iter = word_iter->next, spaces_iter = spaces_iter->next)
{
char* line_plus_word = new_concat(line, word_iter->value);
char* word_plus_space = new_concat(word_iter->value, spaces_iter->value);
if(FC_GetWidth(font, "%s", line_plus_word) > width)
{
current = FC_StringListPushBack(current, line, 0);
line = word_plus_space;
}
else
{
replace_concat(&line, word_plus_space);
free(word_plus_space);
}
free(line_plus_word);
}
current = FC_StringListPushBack(current, line, 0);
FC_StringListFree(words);
FC_StringListFree(spaces);
}
else
{
current = FC_StringListPushBack(current, line, 0);
iter->value = NULL;
}
}
FC_StringListFree(ls);
return result;
}
static void FC_DrawColumnFromBuffer(FC_Font* font, FC_Target* dest, FC_Rect box, int* total_height, FC_Scale scale, FC_AlignEnum align)
{
int y = box.y;
FC_StringList *ls, *iter;
ls = FC_GetBufferFitToColumn(font, box.w, scale, 0);
for(iter = ls; iter != NULL; iter = iter->next)
{
FC_RenderAlign(font, dest, box.x, y, box.w, scale, align, iter->value);
y += FC_GetLineHeight(font);
}
FC_StringListFree(ls);
if(total_height != NULL)
*total_height = y - box.y;
}
FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...)
{
Uint8 useClip;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
useClip = has_clip(dest);
FC_Rect oldclip, newclip;
if(useClip)
{
oldclip = get_clip(dest);
newclip = FC_RectIntersect(oldclip, box);
}
else
newclip = box;
set_clip(dest, &newclip);
set_color_for_all_caches(font, font->default_color);
FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), FC_ALIGN_LEFT);
if(useClip)
set_clip(dest, &oldclip);
else
set_clip(dest, NULL);
return box;
}
FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...)
{
Uint8 useClip;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
useClip = has_clip(dest);
FC_Rect oldclip, newclip;
if(useClip)
{
oldclip = get_clip(dest);
newclip = FC_RectIntersect(oldclip, box);
}
else
newclip = box;
set_clip(dest, &newclip);
set_color_for_all_caches(font, font->default_color);
FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), align);
if(useClip)
set_clip(dest, &oldclip);
else
set_clip(dest, NULL);
return box;
}
FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...)
{
Uint8 useClip;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
useClip = has_clip(dest);
FC_Rect oldclip, newclip;
if(useClip)
{
oldclip = get_clip(dest);
newclip = FC_RectIntersect(oldclip, box);
}
else
newclip = box;
set_clip(dest, &newclip);
set_color_for_all_caches(font, font->default_color);
FC_DrawColumnFromBuffer(font, dest, box, NULL, scale, FC_ALIGN_LEFT);
if(useClip)
set_clip(dest, &oldclip);
else
set_clip(dest, NULL);
return box;
}
FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...)
{
Uint8 useClip;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
useClip = has_clip(dest);
FC_Rect oldclip, newclip;
if(useClip)
{
oldclip = get_clip(dest);
newclip = FC_RectIntersect(oldclip, box);
}
else
newclip = box;
set_clip(dest, &newclip);
set_color_for_all_caches(font, color);
FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), FC_ALIGN_LEFT);
if(useClip)
set_clip(dest, &oldclip);
else
set_clip(dest, NULL);
return box;
}
FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...)
{
Uint8 useClip;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(box.x, box.y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
useClip = has_clip(dest);
FC_Rect oldclip, newclip;
if(useClip)
{
oldclip = get_clip(dest);
newclip = FC_RectIntersect(oldclip, box);
}
else
newclip = box;
set_clip(dest, &newclip);
set_color_for_all_caches(font, effect.color);
FC_DrawColumnFromBuffer(font, dest, box, NULL, effect.scale, effect.alignment);
if(useClip)
set_clip(dest, &oldclip);
else
set_clip(dest, NULL);
return box;
}
FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...)
{
FC_Rect box = {x, y, width, 0};
int total_height;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, font->default_color);
FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), FC_ALIGN_LEFT);
return FC_MakeRect(box.x, box.y, width, total_height);
}
FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...)
{
FC_Rect box = {x, y, width, 0};
int total_height;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, font->default_color);
switch(align)
{
case FC_ALIGN_CENTER:
box.x -= width/2;
break;
case FC_ALIGN_RIGHT:
box.x -= width;
break;
default:
break;
}
FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), align);
return FC_MakeRect(box.x, box.y, width, total_height);
}
FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...)
{
FC_Rect box = {x, y, width, 0};
int total_height;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, font->default_color);
FC_DrawColumnFromBuffer(font, dest, box, &total_height, scale, FC_ALIGN_LEFT);
return FC_MakeRect(box.x, box.y, width, total_height);
}
FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...)
{
FC_Rect box = {x, y, width, 0};
int total_height;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, color);
FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), FC_ALIGN_LEFT);
return FC_MakeRect(box.x, box.y, width, total_height);
}
FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...)
{
FC_Rect box = {x, y, width, 0};
int total_height;
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, effect.color);
switch(effect.alignment)
{
case FC_ALIGN_CENTER:
box.x -= width/2;
break;
case FC_ALIGN_RIGHT:
box.x -= width;
break;
default:
break;
}
FC_DrawColumnFromBuffer(font, dest, box, &total_height, effect.scale, effect.alignment);
return FC_MakeRect(box.x, box.y, width, total_height);
}
static FC_Rect FC_RenderCenter(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
{
FC_Rect result = {x, y, 0, 0};
if(text == NULL || font == NULL)
return result;
char* str = U8_strdup(text);
char* del = str;
char* c;
// Go through str, when you find a \n, replace it with \0 and print it
// then move down, back, and continue.
for(c = str; *c != '\0';)
{
if(*c == '\n')
{
*c = '\0';
result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str)/2.0f, y, scale, str), result);
*c = '\n';
c++;
str = c;
y += scale.y*font->height;
}
else
c++;
}
result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str)/2.0f, y, scale, str), result);
free(del);
return result;
}
static FC_Rect FC_RenderRight(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
{
FC_Rect result = {x, y, 0, 0};
if(text == NULL || font == NULL)
return result;
char* str = U8_strdup(text);
char* del = str;
char* c;
for(c = str; *c != '\0';)
{
if(*c == '\n')
{
*c = '\0';
result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str), y, scale, str), result);
*c = '\n';
c++;
str = c;
y += scale.y*font->height;
}
else
c++;
}
result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str), y, scale, str), result);
free(del);
return result;
}
FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...)
{
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, font->default_color);
return FC_RenderLeft(font, dest, x, y, scale, fc_buffer);
}
FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...)
{
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, font->default_color);
FC_Rect result;
switch(align)
{
case FC_ALIGN_LEFT:
result = FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
break;
case FC_ALIGN_CENTER:
result = FC_RenderCenter(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
break;
case FC_ALIGN_RIGHT:
result = FC_RenderRight(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
break;
default:
result = FC_MakeRect(x, y, 0, 0);
break;
}
return result;
}
FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...)
{
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, color);
return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
}
FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...)
{
if(formatted_text == NULL || font == NULL)
return FC_MakeRect(x, y, 0, 0);
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
set_color_for_all_caches(font, effect.color);
FC_Rect result;
switch(effect.alignment)
{
case FC_ALIGN_LEFT:
result = FC_RenderLeft(font, dest, x, y, effect.scale, fc_buffer);
break;
case FC_ALIGN_CENTER:
result = FC_RenderCenter(font, dest, x, y, effect.scale, fc_buffer);
break;
case FC_ALIGN_RIGHT:
result = FC_RenderRight(font, dest, x, y, effect.scale, fc_buffer);
break;
default:
result = FC_MakeRect(x, y, 0, 0);
break;
}
return result;
}
// Getters
FC_FilterEnum FC_GetFilterMode(FC_Font* font)
{
if(font == NULL)
return FC_FILTER_NEAREST;
return font->filter;
}
Uint16 FC_GetLineHeight(FC_Font* font)
{
if(font == NULL)
return 0;
return font->height;
}
Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...)
{
if(formatted_text == NULL || font == NULL)
return 0;
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
Uint16 numLines = 1;
const char* c;
for (c = fc_buffer; *c != '\0'; c++)
{
if(*c == '\n')
numLines++;
}
// Actual height of letter region + line spacing
return font->height*numLines + font->lineSpacing*(numLines - 1); //height*numLines;
}
Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...)
{
if(formatted_text == NULL || font == NULL)
return 0;
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
const char* c;
Uint16 width = 0;
Uint16 bigWidth = 0; // Allows for multi-line strings
for (c = fc_buffer; *c != '\0'; c++)
{
if(*c == '\n')
{
bigWidth = bigWidth >= width? bigWidth : width;
width = 0;
continue;
}
FC_GlyphData glyph;
Uint32 codepoint = FC_GetCodepointFromUTF8(&c, 1);
if(FC_GetGlyphData(font, &glyph, codepoint) || FC_GetGlyphData(font, &glyph, ' '))
width += glyph.rect.w;
}
bigWidth = bigWidth >= width? bigWidth : width;
return bigWidth;
}
// If width == -1, use no width limit
FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...)
{
FC_Rect result = {0, 0, 1, FC_GetLineHeight(font)};
FC_StringList *ls, *iter;
int num_lines = 0;
Uint8 done = 0;
if(formatted_text == NULL || column_width == 0 || position_index == 0 || font == NULL)
return result;
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
ls = FC_GetBufferFitToColumn(font, column_width, FC_MakeScale(1,1), 1);
for(iter = ls; iter != NULL;)
{
char* line;
int i = 0;
FC_StringList* next_iter = iter->next;
++num_lines;
for(line = iter->value; line != NULL && *line != '\0'; line = (char*)U8_next(line))
{
++i;
--position_index;
if(position_index == 0)
{
// FIXME: Doesn't handle box-wrapped newlines correctly
line = (char*)U8_next(line);
line[0] = '\0';
result.x = FC_GetWidth(font, "%s", iter->value);
done = 1;
break;
}
}
if(done)
break;
// Prevent line wrapping if there are no more lines
if(next_iter == NULL && !done)
result.x = FC_GetWidth(font, "%s", iter->value);
iter = next_iter;
}
FC_StringListFree(ls);
if(num_lines > 1)
{
result.y = (num_lines - 1) * FC_GetLineHeight(font);
}
return result;
}
Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...)
{
int y = 0;
FC_StringList *ls, *iter;
if(font == NULL)
return 0;
if(formatted_text == NULL || width == 0)
return font->height;
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
ls = FC_GetBufferFitToColumn(font, width, FC_MakeScale(1,1), 0);
for(iter = ls; iter != NULL; iter = iter->next)
{
y += FC_GetLineHeight(font);
}
FC_StringListFree(ls);
return y;
}
static int FC_GetAscentFromCodepoint(FC_Font* font, Uint32 codepoint)
{
FC_GlyphData glyph;
if(font == NULL)
return 0;
// FIXME: Store ascent so we can return it here
FC_GetGlyphData(font, &glyph, codepoint);
return glyph.rect.h;
}
static int FC_GetDescentFromCodepoint(FC_Font* font, Uint32 codepoint)
{
FC_GlyphData glyph;
if(font == NULL)
return 0;
// FIXME: Store descent so we can return it here
FC_GetGlyphData(font, &glyph, codepoint);
return glyph.rect.h;
}
int FC_GetAscent(FC_Font* font, const char* formatted_text, ...)
{
Uint32 codepoint;
int max, ascent;
const char* c;
if(font == NULL)
return 0;
if(formatted_text == NULL)
return font->ascent;
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
max = 0;
c = fc_buffer;
while(*c != '\0')
{
codepoint = FC_GetCodepointFromUTF8(&c, 1);
if(codepoint != 0)
{
ascent = FC_GetAscentFromCodepoint(font, codepoint);
if(ascent > max)
max = ascent;
}
++c;
}
return max;
}
int FC_GetDescent(FC_Font* font, const char* formatted_text, ...)
{
Uint32 codepoint;
int max, descent;
const char* c;
if(font == NULL)
return 0;
if(formatted_text == NULL)
return font->descent;
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
max = 0;
c = fc_buffer;
while(*c != '\0')
{
codepoint = FC_GetCodepointFromUTF8(&c, 1);
if(codepoint != 0)
{
descent = FC_GetDescentFromCodepoint(font, codepoint);
if(descent > max)
max = descent;
}
++c;
}
return max;
}
int FC_GetBaseline(FC_Font* font)
{
if(font == NULL)
return 0;
return font->baseline;
}
int FC_GetSpacing(FC_Font* font)
{
if(font == NULL)
return 0;
return font->letterSpacing;
}
int FC_GetLineSpacing(FC_Font* font)
{
if(font == NULL)
return 0;
return font->lineSpacing;
}
Uint16 FC_GetMaxWidth(FC_Font* font)
{
if(font == NULL)
return 0;
return font->maxWidth;
}
SDL_Color FC_GetDefaultColor(FC_Font* font)
{
if(font == NULL)
{
SDL_Color c = {0,0,0,255};
return c;
}
return font->default_color;
}
FC_Rect FC_GetBounds(FC_Font* font, float x, float y, FC_AlignEnum align, FC_Scale scale, const char* formatted_text, ...)
{
FC_Rect result = {x, y, 0, 0};
if(formatted_text == NULL)
return result;
// Create a temp buffer while GetWidth and GetHeight use fc_buffer.
char* temp = (char*)malloc(fc_buffer_size);
FC_EXTRACT_VARARGS(temp, formatted_text);
result.w = FC_GetWidth(font, "%s", temp) * scale.x;
result.h = FC_GetHeight(font, "%s", temp) * scale.y;
switch(align)
{
case FC_ALIGN_LEFT:
break;
case FC_ALIGN_CENTER:
result.x -= result.w/2;
break;
case FC_ALIGN_RIGHT:
result.x -= result.w;
break;
default:
break;
}
free(temp);
return result;
}
Uint8 FC_InRect(float x, float y, FC_Rect input_rect)
{
return (input_rect.x <= x && x <= input_rect.x + input_rect.w && input_rect.y <= y && y <= input_rect.y + input_rect.h);
}
// TODO: Make it work with alignment
Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...)
{
FC_StringList *ls, *iter;
Uint8 done = 0;
int height = FC_GetLineHeight(font);
Uint16 position = 0;
int current_x = 0;
int current_y = 0;
FC_GlyphData glyph_data;
if(formatted_text == NULL || column_width == 0 || font == NULL)
return 0;
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
ls = FC_GetBufferFitToColumn(font, column_width, FC_MakeScale(1,1), 1);
for(iter = ls; iter != NULL; iter = iter->next)
{
char* line;
for(line = iter->value; line != NULL && *line != '\0'; line = (char*)U8_next(line))
{
if(FC_GetGlyphData(font, &glyph_data, FC_GetCodepointFromUTF8((const char**)&line, 0)))
{
if(FC_InRect(x, y, FC_MakeRect(current_x, current_y, glyph_data.rect.w, glyph_data.rect.h)))
{
done = 1;
break;
}
current_x += glyph_data.rect.w;
}
position++;
}
if(done)
break;
current_x = 0;
current_y += height;
if(y < current_y)
break;
}
FC_StringListFree(ls);
return position;
}
int FC_GetWrappedText(FC_Font* font, char* result, int max_result_size, Uint16 width, const char* formatted_text, ...)
{
FC_StringList *ls, *iter;
if(font == NULL)
return 0;
if(formatted_text == NULL || width == 0)
return 0;
FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
ls = FC_GetBufferFitToColumn(font, width, FC_MakeScale(1,1), 0);
int size_so_far = 0;
int size_remaining = max_result_size-1; // reserve for \0
for(iter = ls; iter != NULL && size_remaining > 0; iter = iter->next)
{
// Copy as much of this line as we can
int len = strlen(iter->value);
int num_bytes = FC_MIN(len, size_remaining);
memcpy(&result[size_so_far], iter->value, num_bytes);
size_so_far += num_bytes;
// If there's another line, add newline character
if(size_remaining > 0 && iter->next != NULL)
{
--size_remaining;
result[size_so_far] = '\n';
++size_so_far;
}
}
FC_StringListFree(ls);
result[size_so_far] = '\0';
return size_so_far;
}
// Setters
void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter)
{
if(font == NULL)
return;
if(font->filter != filter)
{
font->filter = filter;
#ifdef FC_USE_SDL_GPU
// Update each texture to use this filter mode
{
int i;
GPU_FilterEnum gpu_filter = GPU_FILTER_NEAREST;
if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
gpu_filter = GPU_FILTER_LINEAR;
for(i = 0; i < font->glyph_cache_count; ++i)
{
GPU_SetImageFilter(font->glyph_cache[i], gpu_filter);
}
}
#endif
}
}
void FC_SetSpacing(FC_Font* font, int LetterSpacing)
{
if(font == NULL)
return;
font->letterSpacing = LetterSpacing;
}
void FC_SetLineSpacing(FC_Font* font, int LineSpacing)
{
if(font == NULL)
return;
font->lineSpacing = LineSpacing;
}
void FC_SetDefaultColor(FC_Font* font, SDL_Color color)
{
if(font == NULL)
return;
font->default_color = color;
}
/**
* @file
* @author Benedict R. Gaster
*/
#include <iostream>
#include <iomanip>
#include <cstring>
#include <app.hpp>
namespace uwe {
App::App() :
output_framerate_{false} {
}
App::~App() {
}
void App::init(int width, int height, std::string title) {
context_.init(width, height, title);
}
void App::run() {
SDL_Event event;
bool running = true;
unsigned int frames = 0;
Uint64 start = SDL_GetPerformanceCounter();
begin();
while( running )
{
while( SDL_PollEvent( &event ) && running ) {
if (event.type == SDL_QUIT ||
(SDL_KEYDOWN == event.type && SDL_SCANCODE_ESCAPE == event.key.keysym.scancode) ) {
running = false;
break;
}
switch (event.type) {
case SDL_KEYDOWN: {
key_pressed(static_cast<Scancode>(event.key.keysym.scancode), event.key.repeat != 0);
break;
}
case SDL_KEYUP: {
key_released(static_cast<Scancode>(event.key.keysym.scancode));
break;
}
case SDL_MOUSEBUTTONDOWN: {
mouse_pressed(event.button.x, event.button.y, static_cast<Button>(event.button.button));
break;
}
case SDL_MOUSEBUTTONUP: {
mouse_released(event.button.x, event.button.y, static_cast<Button>(event.button.button));
break;
}
case SDL_MOUSEMOTION: {
mouse_moved(event.motion.x, event.motion.y);
break;
}
}
}
update();
draw();
// finally present the renderer to the GPU
SDL_RenderPresent( context_.get_renderer() );
frames++;
if (output_framerate_) {
const uint64_t end = SDL_GetPerformanceCounter();
const static uint64_t freq = SDL_GetPerformanceFrequency();
const double seconds = ( end - start ) / static_cast< double >( freq );
if( seconds > 2.0 )
{
std::cout
<< frames << " frames in "
<< std::setprecision(1) << std::fixed << seconds << " seconds = "
<< std::setprecision(1) << std::fixed << frames / seconds << " FPS ("
<< std::setprecision(3) << std::fixed << ( seconds * 1000.0 ) / frames << " ms/frame)"
<< std::endl;
start = end;
frames = 0;
}
}
}
}
} // namespace uwe
\ No newline at end of file
#include <iostream>
#include <context.hpp>
#include <iomanip>
#include <cstring>
namespace uwe {
Context::Context() {
}
void Context::init(int width, int height, std::string title) {
width_ = width;
height_ = height;
tex_width_ = width;
tex_height_ = height;
pixels_ = std::vector<uint8_t>(tex_width_ * tex_height_ *4),
SDL_Init( SDL_INIT_EVERYTHING );
window_ = SDL_CreateWindow(
"SDL2",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width_, height_,
SDL_WINDOW_SHOWN);
SDL_SetWindowTitle(window_, title.c_str());
renderer_ = SDL_CreateRenderer(
window_,
-1,
SDL_RENDERER_ACCELERATED);
texture_ = SDL_CreateTexture(
renderer_,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
tex_width_,
tex_height_);
}
Context::~Context() {
for (auto font: loaded_fonts_) {
FC_FreeFont(font);
}
SDL_DestroyRenderer( renderer_ );
SDL_DestroyWindow( window_ );
SDL_Quit();
}
// void Context::run() {
void Context::dump_renderer_info() {
SDL_RendererInfo info;
SDL_GetRendererInfo( renderer_, &info );
std::cout << "Renderer name: " << info.name << std::endl;
std::cout << "Texture formats: " << std::endl;
for( uint32_t i = 0; i < info.num_texture_formats; i++ ) {
std::cout << SDL_GetPixelFormatName( info.texture_formats[i] ) << std::endl;
}
}
}
\ No newline at end of file
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/**
* \file SDL.h
*
* Main include header for the SDL library
*/
#ifndef SDL_h_
#define SDL_h_
#include "SDL_main.h"
#include "SDL_stdinc.h"
#include "SDL_assert.h"
#include "SDL_atomic.h"
#include "SDL_audio.h"
#include "SDL_clipboard.h"
#include "SDL_cpuinfo.h"
#include "SDL_endian.h"
#include "SDL_error.h"
#include "SDL_events.h"
#include "SDL_filesystem.h"
#include "SDL_gamecontroller.h"
#include "SDL_haptic.h"
#include "SDL_hints.h"
#include "SDL_joystick.h"
#include "SDL_loadso.h"
#include "SDL_log.h"
#include "SDL_messagebox.h"
#include "SDL_metal.h"
#include "SDL_mutex.h"
#include "SDL_power.h"
#include "SDL_render.h"
#include "SDL_rwops.h"
#include "SDL_sensor.h"
#include "SDL_shape.h"
#include "SDL_system.h"
#include "SDL_thread.h"
#include "SDL_timer.h"
#include "SDL_version.h"
#include "SDL_video.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/* As of version 0.5, SDL is loaded dynamically into the application */
/**
* \name SDL_INIT_*
*
* These are the flags which may be passed to SDL_Init(). You should
* specify the subsystems which you will be using in your application.
*/
/* @{ */
#define SDL_INIT_TIMER 0x00000001u
#define SDL_INIT_AUDIO 0x00000010u
#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
#define SDL_INIT_JOYSTICK 0x00000200u /**< SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS */
#define SDL_INIT_HAPTIC 0x00001000u
#define SDL_INIT_GAMECONTROLLER 0x00002000u /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
#define SDL_INIT_EVENTS 0x00004000u
#define SDL_INIT_SENSOR 0x00008000u
#define SDL_INIT_NOPARACHUTE 0x00100000u /**< compatibility; this flag is ignored. */
#define SDL_INIT_EVERYTHING ( \
SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_SENSOR \
)
/* @} */
/**
* This function initializes the subsystems specified by \c flags
*/
extern DECLSPEC int SDLCALL SDL_Init(Uint32 flags);
/**
* This function initializes specific SDL subsystems
*
* Subsystem initialization is ref-counted, you must call
* SDL_QuitSubSystem() for each SDL_InitSubSystem() to correctly
* shutdown a subsystem manually (or call SDL_Quit() to force shutdown).
* If a subsystem is already loaded then this call will
* increase the ref-count and return.
*/
extern DECLSPEC int SDLCALL SDL_InitSubSystem(Uint32 flags);
/**
* This function cleans up specific SDL subsystems
*/
extern DECLSPEC void SDLCALL SDL_QuitSubSystem(Uint32 flags);
/**
* This function returns a mask of the specified subsystems which have
* previously been initialized.
*
* If \c flags is 0, it returns a mask of all initialized subsystems.
*/
extern DECLSPEC Uint32 SDLCALL SDL_WasInit(Uint32 flags);
/**
* This function cleans up all initialized subsystems. You should
* call it upon all exit conditions.
*/
extern DECLSPEC void SDLCALL SDL_Quit(void);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"
#endif /* SDL_h_ */
/* vi: set ts=4 sw=4 expandtab: */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_assert_h_
#define SDL_assert_h_
#include "SDL_config.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SDL_ASSERT_LEVEL
#ifdef SDL_DEFAULT_ASSERT_LEVEL
#define SDL_ASSERT_LEVEL SDL_DEFAULT_ASSERT_LEVEL
#elif defined(_DEBUG) || defined(DEBUG) || \
(defined(__GNUC__) && !defined(__OPTIMIZE__))
#define SDL_ASSERT_LEVEL 2
#else
#define SDL_ASSERT_LEVEL 1
#endif
#endif /* SDL_ASSERT_LEVEL */
/*
These are macros and not first class functions so that the debugger breaks
on the assertion line and not in some random guts of SDL, and so each
assert can have unique static variables associated with it.
*/
#if defined(_MSC_VER)
/* Don't include intrin.h here because it contains C++ code */
extern void __cdecl __debugbreak(void);
#define SDL_TriggerBreakpoint() __debugbreak()
#elif ( (!defined(__NACL__)) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))) )
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
#elif defined(__386__) && defined(__WATCOMC__)
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
#elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__)
#include <signal.h>
#define SDL_TriggerBreakpoint() raise(SIGTRAP)
#else
/* How do we trigger breakpoints on this platform? */
#define SDL_TriggerBreakpoint()
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
# define SDL_FUNCTION __func__
#elif ((__GNUC__ >= 2) || defined(_MSC_VER) || defined (__WATCOMC__))
# define SDL_FUNCTION __FUNCTION__
#else
# define SDL_FUNCTION "???"
#endif
#define SDL_FILE __FILE__
#define SDL_LINE __LINE__
/*
sizeof (x) makes the compiler still parse the expression even without
assertions enabled, so the code is always checked at compile time, but
doesn't actually generate code for it, so there are no side effects or
expensive checks at run time, just the constant size of what x WOULD be,
which presumably gets optimized out as unused.
This also solves the problem of...
int somevalue = blah();
SDL_assert(somevalue == 1);
...which would cause compiles to complain that somevalue is unused if we
disable assertions.
*/
/* "while (0,0)" fools Microsoft's compiler's /W4 warning level into thinking
this condition isn't constant. And looks like an owl's face! */
#ifdef _MSC_VER /* stupid /W4 warnings. */
#define SDL_NULL_WHILE_LOOP_CONDITION (0,0)
#else
#define SDL_NULL_WHILE_LOOP_CONDITION (0)
#endif
#define SDL_disabled_assert(condition) \
do { (void) sizeof ((condition)); } while (SDL_NULL_WHILE_LOOP_CONDITION)
typedef enum
{
SDL_ASSERTION_RETRY, /**< Retry the assert immediately. */
SDL_ASSERTION_BREAK, /**< Make the debugger trigger a breakpoint. */
SDL_ASSERTION_ABORT, /**< Terminate the program. */
SDL_ASSERTION_IGNORE, /**< Ignore the assert. */
SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */
} SDL_AssertState;
typedef struct SDL_AssertData
{
int always_ignore;
unsigned int trigger_count;
const char *condition;
const char *filename;
int linenum;
const char *function;
const struct SDL_AssertData *next;
} SDL_AssertData;
#if (SDL_ASSERT_LEVEL > 0)
/* Never call this directly. Use the SDL_assert* macros. */
extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *,
const char *,
const char *, int)
#if defined(__clang__)
#if __has_feature(attribute_analyzer_noreturn)
/* this tells Clang's static analysis that we're a custom assert function,
and that the analyzer should assume the condition was always true past this
SDL_assert test. */
__attribute__((analyzer_noreturn))
#endif
#endif
;
/* the do {} while(0) avoids dangling else problems:
if (x) SDL_assert(y); else blah();
... without the do/while, the "else" could attach to this macro's "if".
We try to handle just the minimum we need here in a macro...the loop,
the static vars, and break points. The heavy lifting is handled in
SDL_ReportAssertion(), in SDL_assert.c.
*/
#define SDL_enabled_assert(condition) \
do { \
while ( !(condition) ) { \
static struct SDL_AssertData sdl_assert_data = { \
0, 0, #condition, 0, 0, 0, 0 \
}; \
const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
continue; /* go again. */ \
} else if (sdl_assert_state == SDL_ASSERTION_BREAK) { \
SDL_TriggerBreakpoint(); \
} \
break; /* not retrying. */ \
} \
} while (SDL_NULL_WHILE_LOOP_CONDITION)
#endif /* enabled assertions support code */
/* Enable various levels of assertions. */
#if SDL_ASSERT_LEVEL == 0 /* assertions disabled */
# define SDL_assert(condition) SDL_disabled_assert(condition)
# define SDL_assert_release(condition) SDL_disabled_assert(condition)
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
#elif SDL_ASSERT_LEVEL == 1 /* release settings. */
# define SDL_assert(condition) SDL_disabled_assert(condition)
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
#elif SDL_ASSERT_LEVEL == 2 /* normal settings. */
# define SDL_assert(condition) SDL_enabled_assert(condition)
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
#elif SDL_ASSERT_LEVEL == 3 /* paranoid settings. */
# define SDL_assert(condition) SDL_enabled_assert(condition)
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
# define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
#else
# error Unknown assertion level.
#endif
/* this assertion is never disabled at any level. */
#define SDL_assert_always(condition) SDL_enabled_assert(condition)
typedef SDL_AssertState (SDLCALL *SDL_AssertionHandler)(
const SDL_AssertData* data, void* userdata);
/**
* \brief Set an application-defined assertion handler.
*
* This allows an app to show its own assertion UI and/or force the
* response to an assertion failure. If the app doesn't provide this, SDL
* will try to do the right thing, popping up a system-specific GUI dialog,
* and probably minimizing any fullscreen windows.
*
* This callback may fire from any thread, but it runs wrapped in a mutex, so
* it will only fire from one thread at a time.
*
* Setting the callback to NULL restores SDL's original internal handler.
*
* This callback is NOT reset to SDL's internal handler upon SDL_Quit()!
*
* Return SDL_AssertState value of how to handle the assertion failure.
*
* \param handler Callback function, called when an assertion fails.
* \param userdata A pointer passed to the callback as-is.
*/
extern DECLSPEC void SDLCALL SDL_SetAssertionHandler(
SDL_AssertionHandler handler,
void *userdata);
/**
* \brief Get the default assertion handler.
*
* This returns the function pointer that is called by default when an
* assertion is triggered. This is an internal function provided by SDL,
* that is used for assertions when SDL_SetAssertionHandler() hasn't been
* used to provide a different function.
*
* \return The default SDL_AssertionHandler that is called when an assert triggers.
*/
extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetDefaultAssertionHandler(void);
/**
* \brief Get the current assertion handler.
*
* This returns the function pointer that is called when an assertion is
* triggered. This is either the value last passed to
* SDL_SetAssertionHandler(), or if no application-specified function is
* set, is equivalent to calling SDL_GetDefaultAssertionHandler().
*
* \param puserdata Pointer to a void*, which will store the "userdata"
* pointer that was passed to SDL_SetAssertionHandler().
* This value will always be NULL for the default handler.
* If you don't care about this data, it is safe to pass
* a NULL pointer to this function to ignore it.
* \return The SDL_AssertionHandler that is called when an assert triggers.
*/
extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puserdata);
/**
* \brief Get a list of all assertion failures.
*
* Get all assertions triggered since last call to SDL_ResetAssertionReport(),
* or the start of the program.
*
* The proper way to examine this data looks something like this:
*
* <code>
* const SDL_AssertData *item = SDL_GetAssertionReport();
* while (item) {
* printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\\n",
* item->condition, item->function, item->filename,
* item->linenum, item->trigger_count,
* item->always_ignore ? "yes" : "no");
* item = item->next;
* }
* </code>
*
* \return List of all assertions.
* \sa SDL_ResetAssertionReport
*/
extern DECLSPEC const SDL_AssertData * SDLCALL SDL_GetAssertionReport(void);
/**
* \brief Reset the list of all assertion failures.
*
* Reset list of all assertions triggered.
*
* \sa SDL_GetAssertionReport
*/
extern DECLSPEC void SDLCALL SDL_ResetAssertionReport(void);
/* these had wrong naming conventions until 2.0.4. Please update your app! */
#define SDL_assert_state SDL_AssertState
#define SDL_assert_data SDL_AssertData
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"
#endif /* SDL_assert_h_ */
/* vi: set ts=4 sw=4 expandtab: */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/**
* \file SDL_atomic.h
*
* Atomic operations.
*
* IMPORTANT:
* If you are not an expert in concurrent lockless programming, you should
* only be using the atomic lock and reference counting functions in this
* file. In all other cases you should be protecting your data structures
* with full mutexes.
*
* The list of "safe" functions to use are:
* SDL_AtomicLock()
* SDL_AtomicUnlock()
* SDL_AtomicIncRef()
* SDL_AtomicDecRef()
*
* Seriously, here be dragons!
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
* You can find out a little more about lockless programming and the
* subtle issues that can arise here:
* http://msdn.microsoft.com/en-us/library/ee418650%28v=vs.85%29.aspx
*
* There's also lots of good information here:
* http://www.1024cores.net/home/lock-free-algorithms
* http://preshing.com/
*
* These operations may or may not actually be implemented using
* processor specific atomic operations. When possible they are
* implemented as true processor specific atomic operations. When that
* is not possible the are implemented using locks that *do* use the
* available atomic operations.
*
* All of the atomic operations that modify memory are full memory barriers.
*/
#ifndef SDL_atomic_h_
#define SDL_atomic_h_
#include "SDL_stdinc.h"
#include "SDL_platform.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \name SDL AtomicLock
*
* The atomic locks are efficient spinlocks using CPU instructions,
* but are vulnerable to starvation and can spin forever if a thread
* holding a lock has been terminated. For this reason you should
* minimize the code executed inside an atomic lock and never do
* expensive things like API or system calls while holding them.
*
* The atomic locks are not safe to lock recursively.
*
* Porting Note:
* The spin lock functions and type are required and can not be
* emulated because they are used in the atomic emulation code.
*/
/* @{ */
typedef int SDL_SpinLock;
/**
* \brief Try to lock a spin lock by setting it to a non-zero value.
*
* \param lock Points to the lock.
*
* \return SDL_TRUE if the lock succeeded, SDL_FALSE if the lock is already held.
*/
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicTryLock(SDL_SpinLock *lock);
/**
* \brief Lock a spin lock by setting it to a non-zero value.
*
* \param lock Points to the lock.
*/
extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock);
/**
* \brief Unlock a spin lock by setting it to 0. Always returns immediately
*
* \param lock Points to the lock.
*/
extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock);
/* @} *//* SDL AtomicLock */
/**
* The compiler barrier prevents the compiler from reordering
* reads and writes to globally visible variables across the call.
*/
#if defined(_MSC_VER) && (_MSC_VER > 1200) && !defined(__clang__)
void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
#define SDL_CompilerBarrier() _ReadWriteBarrier()
#elif (defined(__GNUC__) && !defined(__EMSCRIPTEN__)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
/* This is correct for all CPUs when using GCC or Solaris Studio 12.1+. */
#define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
#elif defined(__WATCOMC__)
extern _inline void SDL_CompilerBarrier (void);
#pragma aux SDL_CompilerBarrier = "" parm [] modify exact [];
#else
#define SDL_CompilerBarrier() \
{ SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); }
#endif
/**
* Memory barriers are designed to prevent reads and writes from being
* reordered by the compiler and being seen out of order on multi-core CPUs.
*
* A typical pattern would be for thread A to write some data and a flag,
* and for thread B to read the flag and get the data. In this case you
* would insert a release barrier between writing the data and the flag,
* guaranteeing that the data write completes no later than the flag is
* written, and you would insert an acquire barrier between reading the
* flag and reading the data, to ensure that all the reads associated
* with the flag have completed.
*
* In this pattern you should always see a release barrier paired with
* an acquire barrier and you should gate the data reads/writes with a
* single flag variable.
*
* For more information on these semantics, take a look at the blog post:
* http://preshing.com/20120913/acquire-and-release-semantics
*/
extern DECLSPEC void SDLCALL SDL_MemoryBarrierReleaseFunction(void);
extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
#if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory")
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory")
#elif defined(__GNUC__) && defined(__aarch64__)
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
#elif defined(__GNUC__) && defined(__arm__)
#if 0 /* defined(__LINUX__) || defined(__ANDROID__) */
/* Information from:
https://chromium.googlesource.com/chromium/chromium/+/trunk/base/atomicops_internals_arm_gcc.h#19
The Linux kernel provides a helper function which provides the right code for a memory barrier,
hard-coded at address 0xffff0fa0
*/
typedef void (*SDL_KernelMemoryBarrierFunc)();
#define SDL_MemoryBarrierRelease() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
#define SDL_MemoryBarrierAcquire() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
#elif 0 /* defined(__QNXNTO__) */
#include <sys/cpuinline.h>
#define SDL_MemoryBarrierRelease() __cpu_membarrier()
#define SDL_MemoryBarrierAcquire() __cpu_membarrier()
#else
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_5TE__)
#ifdef __thumb__
/* The mcr instruction isn't available in thumb mode, use real functions */
#define SDL_MEMORY_BARRIER_USES_FUNCTION
#define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
#define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
#else
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
#endif /* __thumb__ */
#else
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
#endif /* __LINUX__ || __ANDROID__ */
#endif /* __GNUC__ && __arm__ */
#else
#if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
/* This is correct for all CPUs on Solaris when using Solaris Studio 12.1+. */
#include <mbarrier.h>
#define SDL_MemoryBarrierRelease() __machine_rel_barrier()
#define SDL_MemoryBarrierAcquire() __machine_acq_barrier()
#else
/* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */
#define SDL_MemoryBarrierRelease() SDL_CompilerBarrier()
#define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
#endif
#endif
/**
* \brief A type representing an atomic integer value. It is a struct
* so people don't accidentally use numeric operations on it.
*/
typedef struct { int value; } SDL_atomic_t;
/**
* \brief Set an atomic variable to a new value if it is currently an old value.
*
* \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise.
*
* \note If you don't know what this function is for, you shouldn't use it!
*/
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
/**
* \brief Set an atomic variable to a value.
*
* \return The previous value of the atomic variable.
*/
extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int v);
/**
* \brief Get the value of an atomic variable
*/
extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a);
/**
* \brief Add to an atomic variable.
*
* \return The previous value of the atomic variable.
*
* \note This same style can be used for any number operation
*/
extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int v);
/**
* \brief Increment an atomic variable used as a reference count.
*/
#ifndef SDL_AtomicIncRef
#define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1)
#endif
/**
* \brief Decrement an atomic variable used as a reference count.
*
* \return SDL_TRUE if the variable reached zero after decrementing,
* SDL_FALSE otherwise
*/
#ifndef SDL_AtomicDecRef
#define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1)
#endif
/**
* \brief Set a pointer to a new value if it is currently an old value.
*
* \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
*
* \note If you don't know what this function is for, you shouldn't use it!
*/
extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void **a, void *oldval, void *newval);
/**
* \brief Set a pointer to a value atomically.
*
* \return The previous value of the pointer.
*/
extern DECLSPEC void* SDLCALL SDL_AtomicSetPtr(void **a, void* v);
/**
* \brief Get the value of a pointer atomically.
*/
extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void **a);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"
#endif /* SDL_atomic_h_ */
/* vi: set ts=4 sw=4 expandtab: */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/**
* \file SDL_audio.h
*
* Access to the raw audio mixing buffer for the SDL library.
*/
#ifndef SDL_audio_h_
#define SDL_audio_h_
#include "SDL_stdinc.h"
#include "SDL_error.h"
#include "SDL_endian.h"
#include "SDL_mutex.h"
#include "SDL_thread.h"
#include "SDL_rwops.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Audio format flags.
*
* These are what the 16 bits in SDL_AudioFormat currently mean...
* (Unspecified bits are always zero).
*
* \verbatim
++-----------------------sample is signed if set
||
|| ++-----------sample is bigendian if set
|| ||
|| || ++---sample is float if set
|| || ||
|| || || +---sample bit size---+
|| || || | |
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
\endverbatim
*
* There are macros in SDL 2.0 and later to query these bits.
*/
typedef Uint16 SDL_AudioFormat;
/**
* \name Audio flags
*/
/* @{ */
#define SDL_AUDIO_MASK_BITSIZE (0xFF)
#define SDL_AUDIO_MASK_DATATYPE (1<<8)
#define SDL_AUDIO_MASK_ENDIAN (1<<12)
#define SDL_AUDIO_MASK_SIGNED (1<<15)
#define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE)
#define SDL_AUDIO_ISFLOAT(x) (x & SDL_AUDIO_MASK_DATATYPE)
#define SDL_AUDIO_ISBIGENDIAN(x) (x & SDL_AUDIO_MASK_ENDIAN)
#define SDL_AUDIO_ISSIGNED(x) (x & SDL_AUDIO_MASK_SIGNED)
#define SDL_AUDIO_ISINT(x) (!SDL_AUDIO_ISFLOAT(x))
#define SDL_AUDIO_ISLITTLEENDIAN(x) (!SDL_AUDIO_ISBIGENDIAN(x))
#define SDL_AUDIO_ISUNSIGNED(x) (!SDL_AUDIO_ISSIGNED(x))
/**
* \name Audio format flags
*
* Defaults to LSB byte order.
*/
/* @{ */
#define AUDIO_U8 0x0008 /**< Unsigned 8-bit samples */
#define AUDIO_S8 0x8008 /**< Signed 8-bit samples */
#define AUDIO_U16LSB 0x0010 /**< Unsigned 16-bit samples */
#define AUDIO_S16LSB 0x8010 /**< Signed 16-bit samples */
#define AUDIO_U16MSB 0x1010 /**< As above, but big-endian byte order */
#define AUDIO_S16MSB 0x9010 /**< As above, but big-endian byte order */
#define AUDIO_U16 AUDIO_U16LSB
#define AUDIO_S16 AUDIO_S16LSB
/* @} */
/**
* \name int32 support
*/
/* @{ */
#define AUDIO_S32LSB 0x8020 /**< 32-bit integer samples */
#define AUDIO_S32MSB 0x9020 /**< As above, but big-endian byte order */
#define AUDIO_S32 AUDIO_S32LSB
/* @} */
/**
* \name float32 support
*/
/* @{ */
#define AUDIO_F32LSB 0x8120 /**< 32-bit floating point samples */
#define AUDIO_F32MSB 0x9120 /**< As above, but big-endian byte order */
#define AUDIO_F32 AUDIO_F32LSB
/* @} */
/**
* \name Native audio byte ordering
*/
/* @{ */
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define AUDIO_U16SYS AUDIO_U16LSB
#define AUDIO_S16SYS AUDIO_S16LSB
#define AUDIO_S32SYS AUDIO_S32LSB
#define AUDIO_F32SYS AUDIO_F32LSB
#else
#define AUDIO_U16SYS AUDIO_U16MSB
#define AUDIO_S16SYS AUDIO_S16MSB
#define AUDIO_S32SYS AUDIO_S32MSB
#define AUDIO_F32SYS AUDIO_F32MSB
#endif
/* @} */
/**
* \name Allow change flags
*
* Which audio format changes are allowed when opening a device.
*/
/* @{ */
#define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001
#define SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002
#define SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004
#define SDL_AUDIO_ALLOW_SAMPLES_CHANGE 0x00000008
#define SDL_AUDIO_ALLOW_ANY_CHANGE (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE)
/* @} */
/* @} *//* Audio flags */
/**
* This function is called when the audio device needs more data.
*
* \param userdata An application-specific parameter saved in
* the SDL_AudioSpec structure
* \param stream A pointer to the audio data buffer.
* \param len The length of that buffer in bytes.
*
* Once the callback returns, the buffer will no longer be valid.
* Stereo samples are stored in a LRLRLR ordering.
*
* You can choose to avoid callbacks and use SDL_QueueAudio() instead, if
* you like. Just open your audio device with a NULL callback.
*/
typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream,
int len);
/**
* The calculated values in this structure are calculated by SDL_OpenAudio().
*
* For multi-channel audio, the default SDL channel mapping is:
* 2: FL FR (stereo)
* 3: FL FR LFE (2.1 surround)
* 4: FL FR BL BR (quad)
* 5: FL FR FC BL BR (quad + center)
* 6: FL FR FC LFE SL SR (5.1 surround - last two can also be BL BR)
* 7: FL FR FC LFE BC SL SR (6.1 surround)
* 8: FL FR FC LFE BL BR SL SR (7.1 surround)
*/
typedef struct SDL_AudioSpec
{
int freq; /**< DSP frequency -- samples per second */
SDL_AudioFormat format; /**< Audio data format */
Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */
Uint8 silence; /**< Audio buffer silence value (calculated) */
Uint16 samples; /**< Audio buffer size in sample FRAMES (total samples divided by channel count) */
Uint16 padding; /**< Necessary for some compile environments */
Uint32 size; /**< Audio buffer size in bytes (calculated) */
SDL_AudioCallback callback; /**< Callback that feeds the audio device (NULL to use SDL_QueueAudio()). */
void *userdata; /**< Userdata passed to callback (ignored for NULL callbacks). */
} SDL_AudioSpec;
struct SDL_AudioCVT;
typedef void (SDLCALL * SDL_AudioFilter) (struct SDL_AudioCVT * cvt,
SDL_AudioFormat format);
/**
* \brief Upper limit of filters in SDL_AudioCVT
*
* The maximum number of SDL_AudioFilter functions in SDL_AudioCVT is
* currently limited to 9. The SDL_AudioCVT.filters array has 10 pointers,
* one of which is the terminating NULL pointer.
*/
#define SDL_AUDIOCVT_MAX_FILTERS 9
/**
* \struct SDL_AudioCVT
* \brief A structure to hold a set of audio conversion filters and buffers.
*
* Note that various parts of the conversion pipeline can take advantage
* of SIMD operations (like SSE2, for example). SDL_AudioCVT doesn't require
* you to pass it aligned data, but can possibly run much faster if you
* set both its (buf) field to a pointer that is aligned to 16 bytes, and its
* (len) field to something that's a multiple of 16, if possible.
*/
#ifdef __GNUC__
/* This structure is 84 bytes on 32-bit architectures, make sure GCC doesn't
pad it out to 88 bytes to guarantee ABI compatibility between compilers.
vvv
The next time we rev the ABI, make sure to size the ints and add padding.
*/
#define SDL_AUDIOCVT_PACKED __attribute__((packed))
#else
#define SDL_AUDIOCVT_PACKED
#endif
/* */
typedef struct SDL_AudioCVT
{
int needed; /**< Set to 1 if conversion possible */
SDL_AudioFormat src_format; /**< Source audio format */
SDL_AudioFormat dst_format; /**< Target audio format */
double rate_incr; /**< Rate conversion increment */
Uint8 *buf; /**< Buffer to hold entire audio data */
int len; /**< Length of original audio buffer */
int len_cvt; /**< Length of converted audio buffer */
int len_mult; /**< buffer must be len*len_mult big */
double len_ratio; /**< Given len, final size is len*len_ratio */
SDL_AudioFilter filters[SDL_AUDIOCVT_MAX_FILTERS + 1]; /**< NULL-terminated list of filter functions */
int filter_index; /**< Current audio conversion function */
} SDL_AUDIOCVT_PACKED SDL_AudioCVT;
/* Function prototypes */
/**
* \name Driver discovery functions
*
* These functions return the list of built in audio drivers, in the
* order that they are normally initialized by default.
*/
/* @{ */
extern DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void);
extern DECLSPEC const char *SDLCALL SDL_GetAudioDriver(int index);
/* @} */
/**
* \name Initialization and cleanup
*
* \internal These functions are used internally, and should not be used unless
* you have a specific need to specify the audio driver you want to
* use. You should normally use SDL_Init() or SDL_InitSubSystem().
*/
/* @{ */
extern DECLSPEC int SDLCALL SDL_AudioInit(const char *driver_name);
extern DECLSPEC void SDLCALL SDL_AudioQuit(void);
/* @} */
/**
* This function returns the name of the current audio driver, or NULL
* if no driver has been initialized.
*/
extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(void);
/**
* This function opens the audio device with the desired parameters, and
* returns 0 if successful, placing the actual hardware parameters in the
* structure pointed to by \c obtained. If \c obtained is NULL, the audio
* data passed to the callback function will be guaranteed to be in the
* requested format, and will be automatically converted to the hardware
* audio format if necessary. This function returns -1 if it failed
* to open the audio device, or couldn't set up the audio thread.
*
* When filling in the desired audio spec structure,
* - \c desired->freq should be the desired audio frequency in samples-per-
* second.
* - \c desired->format should be the desired audio format.
* - \c desired->samples is the desired size of the audio buffer, in
* samples. This number should be a power of two, and may be adjusted by
* the audio driver to a value more suitable for the hardware. Good values
* seem to range between 512 and 8096 inclusive, depending on the
* application and CPU speed. Smaller values yield faster response time,
* but can lead to underflow if the application is doing heavy processing
* and cannot fill the audio buffer in time. A stereo sample consists of
* both right and left channels in LR ordering.
* Note that the number of samples is directly related to time by the
* following formula: \code ms = (samples*1000)/freq \endcode
* - \c desired->size is the size in bytes of the audio buffer, and is
* calculated by SDL_OpenAudio().
* - \c desired->silence is the value used to set the buffer to silence,
* and is calculated by SDL_OpenAudio().
* - \c desired->callback should be set to a function that will be called
* when the audio device is ready for more data. It is passed a pointer
* to the audio buffer, and the length in bytes of the audio buffer.
* This function usually runs in a separate thread, and so you should
* protect data structures that it accesses by calling SDL_LockAudio()
* and SDL_UnlockAudio() in your code. Alternately, you may pass a NULL
* pointer here, and call SDL_QueueAudio() with some frequency, to queue
* more audio samples to be played (or for capture devices, call
* SDL_DequeueAudio() with some frequency, to obtain audio samples).
* - \c desired->userdata is passed as the first parameter to your callback
* function. If you passed a NULL callback, this value is ignored.
*
* The audio device starts out playing silence when it's opened, and should
* be enabled for playing by calling \c SDL_PauseAudio(0) when you are ready
* for your audio callback function to be called. Since the audio driver
* may modify the requested size of the audio buffer, you should allocate
* any local mixing buffers after you open the audio device.
*/
extern DECLSPEC int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
SDL_AudioSpec * obtained);
/**
* SDL Audio Device IDs.
*
* A successful call to SDL_OpenAudio() is always device id 1, and legacy
* SDL audio APIs assume you want this device ID. SDL_OpenAudioDevice() calls
* always returns devices >= 2 on success. The legacy calls are good both
* for backwards compatibility and when you don't care about multiple,
* specific, or capture devices.
*/
typedef Uint32 SDL_AudioDeviceID;
/**
* Get the number of available devices exposed by the current driver.
* Only valid after a successfully initializing the audio subsystem.
* Returns -1 if an explicit list of devices can't be determined; this is
* not an error. For example, if SDL is set up to talk to a remote audio
* server, it can't list every one available on the Internet, but it will
* still allow a specific host to be specified to SDL_OpenAudioDevice().
*
* In many common cases, when this function returns a value <= 0, it can still
* successfully open the default device (NULL for first argument of
* SDL_OpenAudioDevice()).
*/
extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
/**
* Get the human-readable name of a specific audio device.
* Must be a value between 0 and (number of audio devices-1).
* Only valid after a successfully initializing the audio subsystem.
* The values returned by this function reflect the latest call to
* SDL_GetNumAudioDevices(); recall that function to redetect available
* hardware.
*
* The string returned by this function is UTF-8 encoded, read-only, and
* managed internally. You are not to free it. If you need to keep the
* string for any length of time, you should make your own copy of it, as it
* will be invalid next time any of several other SDL functions is called.
*/
extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
int iscapture);
/**
* Open a specific audio device. Passing in a device name of NULL requests
* the most reasonable default (and is equivalent to calling SDL_OpenAudio()).
*
* The device name is a UTF-8 string reported by SDL_GetAudioDeviceName(), but
* some drivers allow arbitrary and driver-specific strings, such as a
* hostname/IP address for a remote audio server, or a filename in the
* diskaudio driver.
*
* \return 0 on error, a valid device ID that is >= 2 on success.
*
* SDL_OpenAudio(), unlike this function, always acts on device ID 1.
*/
extern DECLSPEC SDL_AudioDeviceID SDLCALL SDL_OpenAudioDevice(const char
*device,
int iscapture,
const
SDL_AudioSpec *
desired,
SDL_AudioSpec *
obtained,
int
allowed_changes);
/**
* \name Audio state
*
* Get the current audio state.
*/
/* @{ */
typedef enum
{
SDL_AUDIO_STOPPED = 0,
SDL_AUDIO_PLAYING,
SDL_AUDIO_PAUSED
} SDL_AudioStatus;
extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioStatus(void);
extern DECLSPEC SDL_AudioStatus SDLCALL
SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev);
/* @} *//* Audio State */
/**
* \name Pause audio functions
*
* These functions pause and unpause the audio callback processing.
* They should be called with a parameter of 0 after opening the audio
* device to start playing sound. This is so you can safely initialize
* data for your callback function after opening the audio device.
* Silence will be written to the audio device during the pause.
*/
/* @{ */
extern DECLSPEC void SDLCALL SDL_PauseAudio(int pause_on);
extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
int pause_on);
/* @} *//* Pause audio functions */
/**
* \brief Load the audio data of a WAVE file into memory
*
* Loading a WAVE file requires \c src, \c spec, \c audio_buf and \c audio_len
* to be valid pointers. The entire data portion of the file is then loaded
* into memory and decoded if necessary.
*
* If \c freesrc is non-zero, the data source gets automatically closed and
* freed before the function returns.
*
* Supported are RIFF WAVE files with the formats PCM (8, 16, 24, and 32 bits),
* IEEE Float (32 bits), Microsoft ADPCM and IMA ADPCM (4 bits), and A-law and
* µ-law (8 bits). Other formats are currently unsupported and cause an error.
*
* If this function succeeds, the pointer returned by it is equal to \c spec
* and the pointer to the audio data allocated by the function is written to
* \c audio_buf and its length in bytes to \c audio_len. The \ref SDL_AudioSpec
* members \c freq, \c channels, and \c format are set to the values of the
* audio data in the buffer. The \c samples member is set to a sane default and
* all others are set to zero.
*
* It's necessary to use SDL_FreeWAV() to free the audio data returned in
* \c audio_buf when it is no longer used.
*
* Because of the underspecification of the Waveform format, there are many
* problematic files in the wild that cause issues with strict decoders. To
* provide compatibility with these files, this decoder is lenient in regards
* to the truncation of the file, the fact chunk, and the size of the RIFF
* chunk. The hints SDL_HINT_WAVE_RIFF_CHUNK_SIZE, SDL_HINT_WAVE_TRUNCATION,
* and SDL_HINT_WAVE_FACT_CHUNK can be used to tune the behavior of the
* loading process.
*
* Any file that is invalid (due to truncation, corruption, or wrong values in
* the headers), too big, or unsupported causes an error. Additionally, any
* critical I/O error from the data source will terminate the loading process
* with an error. The function returns NULL on error and in all cases (with the
* exception of \c src being NULL), an appropriate error message will be set.
*
* It is required that the data source supports seeking.
*
* Example:
* \code
* SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...);
* \endcode
*
* \param src The data source with the WAVE data
* \param freesrc A integer value that makes the function close the data source if non-zero
* \param spec A pointer filled with the audio format of the audio data
* \param audio_buf A pointer filled with the audio data allocated by the function
* \param audio_len A pointer filled with the length of the audio data buffer in bytes
* \return NULL on error, or non-NULL on success.
*/
extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src,
int freesrc,
SDL_AudioSpec * spec,
Uint8 ** audio_buf,
Uint32 * audio_len);
/**
* Loads a WAV from a file.
* Compatibility convenience function.
*/
#define SDL_LoadWAV(file, spec, audio_buf, audio_len) \
SDL_LoadWAV_RW(SDL_RWFromFile(file, "rb"),1, spec,audio_buf,audio_len)
/**
* This function frees data previously allocated with SDL_LoadWAV_RW()
*/
extern DECLSPEC void SDLCALL SDL_FreeWAV(Uint8 * audio_buf);
/**
* This function takes a source format and rate and a destination format
* and rate, and initializes the \c cvt structure with information needed
* by SDL_ConvertAudio() to convert a buffer of audio data from one format
* to the other. An unsupported format causes an error and -1 will be returned.
*
* \return 0 if no conversion is needed, 1 if the audio filter is set up,
* or -1 on error.
*/
extern DECLSPEC int SDLCALL SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
SDL_AudioFormat src_format,
Uint8 src_channels,
int src_rate,
SDL_AudioFormat dst_format,
Uint8 dst_channels,
int dst_rate);
/**
* Once you have initialized the \c cvt structure using SDL_BuildAudioCVT(),
* created an audio buffer \c cvt->buf, and filled it with \c cvt->len bytes of
* audio data in the source format, this function will convert it in-place
* to the desired format.
*
* The data conversion may expand the size of the audio data, so the buffer
* \c cvt->buf should be allocated after the \c cvt structure is initialized by
* SDL_BuildAudioCVT(), and should be \c cvt->len*cvt->len_mult bytes long.
*
* \return 0 on success or -1 if \c cvt->buf is NULL.
*/
extern DECLSPEC int SDLCALL SDL_ConvertAudio(SDL_AudioCVT * cvt);
/* SDL_AudioStream is a new audio conversion interface.
The benefits vs SDL_AudioCVT:
- it can handle resampling data in chunks without generating
artifacts, when it doesn't have the complete buffer available.
- it can handle incoming data in any variable size.
- You push data as you have it, and pull it when you need it
*/
/* this is opaque to the outside world. */
struct _SDL_AudioStream;
typedef struct _SDL_AudioStream SDL_AudioStream;
/**
* Create a new audio stream
*
* \param src_format The format of the source audio
* \param src_channels The number of channels of the source audio
* \param src_rate The sampling rate of the source audio
* \param dst_format The format of the desired audio output
* \param dst_channels The number of channels of the desired audio output
* \param dst_rate The sampling rate of the desired audio output
* \return 0 on success, or -1 on error.
*
* \sa SDL_AudioStreamPut
* \sa SDL_AudioStreamGet
* \sa SDL_AudioStreamAvailable
* \sa SDL_AudioStreamFlush
* \sa SDL_AudioStreamClear
* \sa SDL_FreeAudioStream
*/
extern DECLSPEC SDL_AudioStream * SDLCALL SDL_NewAudioStream(const SDL_AudioFormat src_format,
const Uint8 src_channels,
const int src_rate,
const SDL_AudioFormat dst_format,
const Uint8 dst_channels,
const int dst_rate);
/**
* Add data to be converted/resampled to the stream
*
* \param stream The stream the audio data is being added to
* \param buf A pointer to the audio data to add
* \param len The number of bytes to write to the stream
* \return 0 on success, or -1 on error.
*
* \sa SDL_NewAudioStream
* \sa SDL_AudioStreamGet
* \sa SDL_AudioStreamAvailable
* \sa SDL_AudioStreamFlush
* \sa SDL_AudioStreamClear
* \sa SDL_FreeAudioStream
*/
extern DECLSPEC int SDLCALL SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len);
/**
* Get converted/resampled data from the stream
*
* \param stream The stream the audio is being requested from
* \param buf A buffer to fill with audio data
* \param len The maximum number of bytes to fill
* \return The number of bytes read from the stream, or -1 on error
*
* \sa SDL_NewAudioStream
* \sa SDL_AudioStreamPut
* \sa SDL_AudioStreamAvailable
* \sa SDL_AudioStreamFlush
* \sa SDL_AudioStreamClear
* \sa SDL_FreeAudioStream
*/
extern DECLSPEC int SDLCALL SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len);
/**
* Get the number of converted/resampled bytes available. The stream may be
* buffering data behind the scenes until it has enough to resample
* correctly, so this number might be lower than what you expect, or even
* be zero. Add more data or flush the stream if you need the data now.
*
* \sa SDL_NewAudioStream
* \sa SDL_AudioStreamPut
* \sa SDL_AudioStreamGet
* \sa SDL_AudioStreamFlush
* \sa SDL_AudioStreamClear
* \sa SDL_FreeAudioStream
*/
extern DECLSPEC int SDLCALL SDL_AudioStreamAvailable(SDL_AudioStream *stream);
/**
* Tell the stream that you're done sending data, and anything being buffered
* should be converted/resampled and made available immediately.
*
* It is legal to add more data to a stream after flushing, but there will
* be audio gaps in the output. Generally this is intended to signal the
* end of input, so the complete output becomes available.
*
* \sa SDL_NewAudioStream
* \sa SDL_AudioStreamPut
* \sa SDL_AudioStreamGet
* \sa SDL_AudioStreamAvailable
* \sa SDL_AudioStreamClear
* \sa SDL_FreeAudioStream
*/
extern DECLSPEC int SDLCALL SDL_AudioStreamFlush(SDL_AudioStream *stream);
/**
* Clear any pending data in the stream without converting it
*
* \sa SDL_NewAudioStream
* \sa SDL_AudioStreamPut
* \sa SDL_AudioStreamGet
* \sa SDL_AudioStreamAvailable
* \sa SDL_AudioStreamFlush
* \sa SDL_FreeAudioStream
*/
extern DECLSPEC void SDLCALL SDL_AudioStreamClear(SDL_AudioStream *stream);
/**
* Free an audio stream
*
* \sa SDL_NewAudioStream
* \sa SDL_AudioStreamPut
* \sa SDL_AudioStreamGet
* \sa SDL_AudioStreamAvailable
* \sa SDL_AudioStreamFlush
* \sa SDL_AudioStreamClear
*/
extern DECLSPEC void SDLCALL SDL_FreeAudioStream(SDL_AudioStream *stream);
#define SDL_MIX_MAXVOLUME 128
/**
* This takes two audio buffers of the playing audio format and mixes
* them, performing addition, volume adjustment, and overflow clipping.
* The volume ranges from 0 - 128, and should be set to ::SDL_MIX_MAXVOLUME
* for full audio volume. Note this does not change hardware volume.
* This is provided for convenience -- you can mix your own audio data.
*/
extern DECLSPEC void SDLCALL SDL_MixAudio(Uint8 * dst, const Uint8 * src,
Uint32 len, int volume);
/**
* This works like SDL_MixAudio(), but you specify the audio format instead of
* using the format of audio device 1. Thus it can be used when no audio
* device is open at all.
*/
extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst,
const Uint8 * src,
SDL_AudioFormat format,
Uint32 len, int volume);
/**
* Queue more audio on non-callback devices.
*
* (If you are looking to retrieve queued audio from a non-callback capture
* device, you want SDL_DequeueAudio() instead. This will return -1 to
* signify an error if you use it with capture devices.)
*
* SDL offers two ways to feed audio to the device: you can either supply a
* callback that SDL triggers with some frequency to obtain more audio
* (pull method), or you can supply no callback, and then SDL will expect
* you to supply data at regular intervals (push method) with this function.
*
* There are no limits on the amount of data you can queue, short of
* exhaustion of address space. Queued data will drain to the device as
* necessary without further intervention from you. If the device needs
* audio but there is not enough queued, it will play silence to make up
* the difference. This means you will have skips in your audio playback
* if you aren't routinely queueing sufficient data.
*
* This function copies the supplied data, so you are safe to free it when
* the function returns. This function is thread-safe, but queueing to the
* same device from two threads at once does not promise which buffer will
* be queued first.
*
* You may not queue audio on a device that is using an application-supplied
* callback; doing so returns an error. You have to use the audio callback
* or queue audio with this function, but not both.
*
* You should not call SDL_LockAudio() on the device before queueing; SDL
* handles locking internally for this function.
*
* \param dev The device ID to which we will queue audio.
* \param data The data to queue to the device for later playback.
* \param len The number of bytes (not samples!) to which (data) points.
* \return 0 on success, or -1 on error.
*
* \sa SDL_GetQueuedAudioSize
* \sa SDL_ClearQueuedAudio
*/
extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *data, Uint32 len);
/**
* Dequeue more audio on non-callback devices.
*
* (If you are looking to queue audio for output on a non-callback playback
* device, you want SDL_QueueAudio() instead. This will always return 0
* if you use it with playback devices.)
*
* SDL offers two ways to retrieve audio from a capture device: you can
* either supply a callback that SDL triggers with some frequency as the
* device records more audio data, (push method), or you can supply no
* callback, and then SDL will expect you to retrieve data at regular
* intervals (pull method) with this function.
*
* There are no limits on the amount of data you can queue, short of
* exhaustion of address space. Data from the device will keep queuing as
* necessary without further intervention from you. This means you will
* eventually run out of memory if you aren't routinely dequeueing data.
*
* Capture devices will not queue data when paused; if you are expecting
* to not need captured audio for some length of time, use
* SDL_PauseAudioDevice() to stop the capture device from queueing more
* data. This can be useful during, say, level loading times. When
* unpaused, capture devices will start queueing data from that point,
* having flushed any capturable data available while paused.
*
* This function is thread-safe, but dequeueing from the same device from
* two threads at once does not promise which thread will dequeued data
* first.
*
* You may not dequeue audio from a device that is using an
* application-supplied callback; doing so returns an error. You have to use
* the audio callback, or dequeue audio with this function, but not both.
*
* You should not call SDL_LockAudio() on the device before queueing; SDL
* handles locking internally for this function.
*
* \param dev The device ID from which we will dequeue audio.
* \param data A pointer into where audio data should be copied.
* \param len The number of bytes (not samples!) to which (data) points.
* \return number of bytes dequeued, which could be less than requested.
*
* \sa SDL_GetQueuedAudioSize
* \sa SDL_ClearQueuedAudio
*/
extern DECLSPEC Uint32 SDLCALL SDL_DequeueAudio(SDL_AudioDeviceID dev, void *data, Uint32 len);
/**
* Get the number of bytes of still-queued audio.
*
* For playback device:
*
* This is the number of bytes that have been queued for playback with
* SDL_QueueAudio(), but have not yet been sent to the hardware. This
* number may shrink at any time, so this only informs of pending data.
*
* Once we've sent it to the hardware, this function can not decide the
* exact byte boundary of what has been played. It's possible that we just
* gave the hardware several kilobytes right before you called this
* function, but it hasn't played any of it yet, or maybe half of it, etc.
*
* For capture devices:
*
* This is the number of bytes that have been captured by the device and
* are waiting for you to dequeue. This number may grow at any time, so
* this only informs of the lower-bound of available data.
*
* You may not queue audio on a device that is using an application-supplied
* callback; calling this function on such a device always returns 0.
* You have to queue audio with SDL_QueueAudio()/SDL_DequeueAudio(), or use
* the audio callback, but not both.
*
* You should not call SDL_LockAudio() on the device before querying; SDL
* handles locking internally for this function.
*
* \param dev The device ID of which we will query queued audio size.
* \return Number of bytes (not samples!) of queued audio.
*
* \sa SDL_QueueAudio
* \sa SDL_ClearQueuedAudio
*/
extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
/**
* Drop any queued audio data. For playback devices, this is any queued data
* still waiting to be submitted to the hardware. For capture devices, this
* is any data that was queued by the device that hasn't yet been dequeued by
* the application.
*
* Immediately after this call, SDL_GetQueuedAudioSize() will return 0. For
* playback devices, the hardware will start playing silence if more audio
* isn't queued. Unpaused capture devices will start filling the queue again
* as soon as they have more data available (which, depending on the state
* of the hardware and the thread, could be before this function call
* returns!).
*
* This will not prevent playback of queued audio that's already been sent
* to the hardware, as we can not undo that, so expect there to be some
* fraction of a second of audio that might still be heard. This can be
* useful if you want to, say, drop any pending music during a level change
* in your game.
*
* You may not queue audio on a device that is using an application-supplied
* callback; calling this function on such a device is always a no-op.
* You have to queue audio with SDL_QueueAudio()/SDL_DequeueAudio(), or use
* the audio callback, but not both.
*
* You should not call SDL_LockAudio() on the device before clearing the
* queue; SDL handles locking internally for this function.
*
* This function always succeeds and thus returns void.
*
* \param dev The device ID of which to clear the audio queue.
*
* \sa SDL_QueueAudio
* \sa SDL_GetQueuedAudioSize
*/
extern DECLSPEC void SDLCALL SDL_ClearQueuedAudio(SDL_AudioDeviceID dev);
/**
* \name Audio lock functions
*
* The lock manipulated by these functions protects the callback function.
* During a SDL_LockAudio()/SDL_UnlockAudio() pair, you can be guaranteed that
* the callback function is not running. Do not call these from the callback
* function or you will cause deadlock.
*/
/* @{ */
extern DECLSPEC void SDLCALL SDL_LockAudio(void);
extern DECLSPEC void SDLCALL SDL_LockAudioDevice(SDL_AudioDeviceID dev);
extern DECLSPEC void SDLCALL SDL_UnlockAudio(void);
extern DECLSPEC void SDLCALL SDL_UnlockAudioDevice(SDL_AudioDeviceID dev);
/* @} *//* Audio lock functions */
/**
* This function shuts down audio processing and closes the audio device.
*/
extern DECLSPEC void SDLCALL SDL_CloseAudio(void);
extern DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"
#endif /* SDL_audio_h_ */
/* vi: set ts=4 sw=4 expandtab: */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/**
* \file SDL_bits.h
*
* Functions for fiddling with bits and bitmasks.
*/
#ifndef SDL_bits_h_
#define SDL_bits_h_
#include "SDL_stdinc.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \file SDL_bits.h
*/
/**
* Get the index of the most significant bit. Result is undefined when called
* with 0. This operation can also be stated as "count leading zeroes" and
* "log base 2".
*
* \return Index of the most significant bit, or -1 if the value is 0.
*/
#if defined(__WATCOMC__) && defined(__386__)
extern _inline int _SDL_clz_watcom (Uint32);
#pragma aux _SDL_clz_watcom = \
"bsr eax, eax" \
"xor eax, 31" \
parm [eax] nomemory \
value [eax] \
modify exact [eax] nomemory;
#endif
SDL_FORCE_INLINE int
SDL_MostSignificantBitIndex32(Uint32 x)
{
#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
/* Count Leading Zeroes builtin in GCC.
* http://gcc.gnu.org/onlinedocs/gcc-4.3.4/gcc/Other-Builtins.html
*/
if (x == 0) {
return -1;
}
return 31 - __builtin_clz(x);
#elif defined(__WATCOMC__) && defined(__386__)
if (x == 0) {
return -1;
}
return 31 - _SDL_clz_watcom(x);
#else
/* Based off of Bit Twiddling Hacks by Sean Eron Anderson
* <seander@cs.stanford.edu>, released in the public domain.
* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
*/
const Uint32 b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
const int S[] = {1, 2, 4, 8, 16};
int msbIndex = 0;
int i;
if (x == 0) {
return -1;
}
for (i = 4; i >= 0; i--)
{
if (x & b[i])
{
x >>= S[i];
msbIndex |= S[i];
}
}
return msbIndex;
#endif
}
SDL_FORCE_INLINE SDL_bool
SDL_HasExactlyOneBitSet32(Uint32 x)
{
if (x && !(x & (x - 1))) {
return SDL_TRUE;
}
return SDL_FALSE;
}
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"
#endif /* SDL_bits_h_ */
/* vi: set ts=4 sw=4 expandtab: */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/**
* \file SDL_blendmode.h
*
* Header file declaring the SDL_BlendMode enumeration
*/
#ifndef SDL_blendmode_h_
#define SDL_blendmode_h_
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief The blend mode used in SDL_RenderCopy() and drawing operations.
*/
typedef enum
{
SDL_BLENDMODE_NONE = 0x00000000, /**< no blending
dstRGBA = srcRGBA */
SDL_BLENDMODE_BLEND = 0x00000001, /**< alpha blending
dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
dstA = srcA + (dstA * (1-srcA)) */
SDL_BLENDMODE_ADD = 0x00000002, /**< additive blending
dstRGB = (srcRGB * srcA) + dstRGB
dstA = dstA */
SDL_BLENDMODE_MOD = 0x00000004, /**< color modulate
dstRGB = srcRGB * dstRGB
dstA = dstA */
SDL_BLENDMODE_MUL = 0x00000008, /**< color multiply
dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))
dstA = (srcA * dstA) + (dstA * (1-srcA)) */
SDL_BLENDMODE_INVALID = 0x7FFFFFFF
/* Additional custom blend modes can be returned by SDL_ComposeCustomBlendMode() */
} SDL_BlendMode;
/**
* \brief The blend operation used when combining source and destination pixel components
*/
typedef enum
{
SDL_BLENDOPERATION_ADD = 0x1, /**< dst + src: supported by all renderers */
SDL_BLENDOPERATION_SUBTRACT = 0x2, /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */
SDL_BLENDOPERATION_REV_SUBTRACT = 0x3, /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */
SDL_BLENDOPERATION_MINIMUM = 0x4, /**< min(dst, src) : supported by D3D11 */
SDL_BLENDOPERATION_MAXIMUM = 0x5 /**< max(dst, src) : supported by D3D11 */
} SDL_BlendOperation;
/**
* \brief The normalized factor used to multiply pixel components
*/
typedef enum
{
SDL_BLENDFACTOR_ZERO = 0x1, /**< 0, 0, 0, 0 */
SDL_BLENDFACTOR_ONE = 0x2, /**< 1, 1, 1, 1 */
SDL_BLENDFACTOR_SRC_COLOR = 0x3, /**< srcR, srcG, srcB, srcA */
SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR = 0x4, /**< 1-srcR, 1-srcG, 1-srcB, 1-srcA */
SDL_BLENDFACTOR_SRC_ALPHA = 0x5, /**< srcA, srcA, srcA, srcA */
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA = 0x6, /**< 1-srcA, 1-srcA, 1-srcA, 1-srcA */
SDL_BLENDFACTOR_DST_COLOR = 0x7, /**< dstR, dstG, dstB, dstA */
SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8, /**< 1-dstR, 1-dstG, 1-dstB, 1-dstA */
SDL_BLENDFACTOR_DST_ALPHA = 0x9, /**< dstA, dstA, dstA, dstA */
SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA /**< 1-dstA, 1-dstA, 1-dstA, 1-dstA */
} SDL_BlendFactor;
/**
* \brief Create a custom blend mode, which may or may not be supported by a given renderer
*
* \param srcColorFactor source color factor
* \param dstColorFactor destination color factor
* \param colorOperation color operation
* \param srcAlphaFactor source alpha factor
* \param dstAlphaFactor destination alpha factor
* \param alphaOperation alpha operation
*
* The result of the blend mode operation will be:
* dstRGB = dstRGB * dstColorFactor colorOperation srcRGB * srcColorFactor
* and
* dstA = dstA * dstAlphaFactor alphaOperation srcA * srcAlphaFactor
*/
extern DECLSPEC SDL_BlendMode SDLCALL SDL_ComposeCustomBlendMode(SDL_BlendFactor srcColorFactor,
SDL_BlendFactor dstColorFactor,
SDL_BlendOperation colorOperation,
SDL_BlendFactor srcAlphaFactor,
SDL_BlendFactor dstAlphaFactor,
SDL_BlendOperation alphaOperation);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"
#endif /* SDL_blendmode_h_ */
/* vi: set ts=4 sw=4 expandtab: */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/**
* \file SDL_clipboard.h
*
* Include file for SDL clipboard handling
*/
#ifndef SDL_clipboard_h_
#define SDL_clipboard_h_
#include "SDL_stdinc.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/* Function prototypes */
/**
* \brief Put UTF-8 text into the clipboard
*
* \sa SDL_GetClipboardText()
*/
extern DECLSPEC int SDLCALL SDL_SetClipboardText(const char *text);
/**
* \brief Get UTF-8 text from the clipboard, which must be freed with SDL_free()
*
* \sa SDL_SetClipboardText()
*/
extern DECLSPEC char * SDLCALL SDL_GetClipboardText(void);
/**
* \brief Returns a flag indicating whether the clipboard exists and contains a text string that is non-empty
*
* \sa SDL_GetClipboardText()
*/
extern DECLSPEC SDL_bool SDLCALL SDL_HasClipboardText(void);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"
#endif /* SDL_clipboard_h_ */
/* vi: set ts=4 sw=4 expandtab: */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_config_windows_h_
#define SDL_config_windows_h_
#define SDL_config_h_
#include "SDL_platform.h"
/* This is a set of defines to configure the SDL features */
#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
#define HAVE_STDINT_H 1
#elif defined(_MSC_VER)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#ifndef _UINTPTR_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 uintptr_t;
#else
typedef unsigned int uintptr_t;
#endif
#define _UINTPTR_T_DEFINED
#endif
/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
#define DWORD_PTR DWORD
#endif
#if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
#define LONG_PTR LONG
#endif
#else /* !__GNUC__ && !_MSC_VER */
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#ifndef _SIZE_T_DEFINED_
#define _SIZE_T_DEFINED_
typedef unsigned int size_t;
#endif
typedef unsigned int uintptr_t;
#endif /* __GNUC__ || _MSC_VER */
#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
#ifdef _WIN64
# define SIZEOF_VOIDP 8
#else
# define SIZEOF_VOIDP 4
#endif
#define HAVE_DDRAW_H 1
#define HAVE_DINPUT_H 1
#define HAVE_DSOUND_H 1
#define HAVE_DXGI_H 1
#define HAVE_XINPUT_H 1
#define HAVE_MMDEVICEAPI_H 1
#define HAVE_AUDIOCLIENT_H 1
/* This is disabled by default to avoid C runtime dependencies and manifest requirements */
#ifdef HAVE_LIBC
/* Useful headers */
#define STDC_HEADERS 1
#define HAVE_CTYPE_H 1
#define HAVE_FLOAT_H 1
#define HAVE_LIMITS_H 1
#define HAVE_MATH_H 1
#define HAVE_SIGNAL_H 1
#define HAVE_STDIO_H 1
#define HAVE_STRING_H 1
/* C library functions */
#define HAVE_MALLOC 1
#define HAVE_CALLOC 1
#define HAVE_REALLOC 1
#define HAVE_FREE 1
#define HAVE_ALLOCA 1
#define HAVE_QSORT 1
#define HAVE_ABS 1
#define HAVE_MEMSET 1
#define HAVE_MEMCPY 1
#define HAVE_MEMMOVE 1
#define HAVE_MEMCMP 1
#define HAVE_STRLEN 1
#define HAVE__STRREV 1
/* These functions have security warnings, so we won't use them */
/* #undef HAVE__STRUPR */
/* #undef HAVE__STRLWR */
#define HAVE_STRCHR 1
#define HAVE_STRRCHR 1
#define HAVE_STRSTR 1
/* #undef HAVE_STRTOK_R */
#if defined(_MSC_VER)
#define HAVE_STRTOK_S 1
#endif
/* These functions have security warnings, so we won't use them */
/* #undef HAVE__LTOA */
/* #undef HAVE__ULTOA */
#define HAVE_STRTOL 1
#define HAVE_STRTOUL 1
#define HAVE_STRTOD 1
#define HAVE_ATOI 1
#define HAVE_ATOF 1
#define HAVE_STRCMP 1
#define HAVE_STRNCMP 1
#define HAVE__STRICMP 1
#define HAVE__STRNICMP 1
#define HAVE_ACOS 1
#define HAVE_ACOSF 1
#define HAVE_ASIN 1
#define HAVE_ASINF 1
#define HAVE_ATAN 1
#define HAVE_ATANF 1
#define HAVE_ATAN2 1
#define HAVE_ATAN2F 1
#define HAVE_CEILF 1
#define HAVE__COPYSIGN 1
#define HAVE_COS 1
#define HAVE_COSF 1
#define HAVE_EXP 1
#define HAVE_EXPF 1
#define HAVE_FABS 1
#define HAVE_FABSF 1
#define HAVE_FLOOR 1
#define HAVE_FLOORF 1
#define HAVE_FMOD 1
#define HAVE_FMODF 1
#define HAVE_LOG 1
#define HAVE_LOGF 1
#define HAVE_LOG10 1
#define HAVE_LOG10F 1
#define HAVE_POW 1
#define HAVE_POWF 1
#define HAVE_SIN 1
#define HAVE_SINF 1
#define HAVE_SQRT 1
#define HAVE_SQRTF 1
#define HAVE_TAN 1
#define HAVE_TANF 1
#if defined(_MSC_VER)
/* These functions were added with the VC++ 2013 C runtime library */
#if _MSC_VER >= 1800
#define HAVE_STRTOLL 1
#define HAVE_VSSCANF 1
#define HAVE_SCALBN 1
#define HAVE_SCALBNF 1
#endif
/* This function is available with at least the VC++ 2008 C runtime library */
#if _MSC_VER >= 1400
#define HAVE__FSEEKI64 1
#endif
#endif
#if !defined(_MSC_VER) || defined(_USE_MATH_DEFINES)
#define HAVE_M_PI 1
#endif
#else
#define HAVE_STDARG_H 1
#define HAVE_STDDEF_H 1
#endif
/* Enable various audio drivers */
#define SDL_AUDIO_DRIVER_WASAPI 1
#define SDL_AUDIO_DRIVER_DSOUND 1
#define SDL_AUDIO_DRIVER_WINMM 1
#define SDL_AUDIO_DRIVER_DISK 1
#define SDL_AUDIO_DRIVER_DUMMY 1
/* Enable various input drivers */
#define SDL_JOYSTICK_DINPUT 1
#define SDL_JOYSTICK_XINPUT 1
#define SDL_JOYSTICK_HIDAPI 1
#define SDL_HAPTIC_DINPUT 1
#define SDL_HAPTIC_XINPUT 1
/* Enable the dummy sensor driver */
#define SDL_SENSOR_DUMMY 1
/* Enable various shared object loading systems */
#define SDL_LOADSO_WINDOWS 1
/* Enable various threading systems */
#define SDL_THREAD_WINDOWS 1
/* Enable various timer systems */
#define SDL_TIMER_WINDOWS 1
/* Enable various video drivers */
#define SDL_VIDEO_DRIVER_DUMMY 1
#define SDL_VIDEO_DRIVER_WINDOWS 1
#ifndef SDL_VIDEO_RENDER_D3D
#define SDL_VIDEO_RENDER_D3D 1
#endif
#ifndef SDL_VIDEO_RENDER_D3D11
#define SDL_VIDEO_RENDER_D3D11 0
#endif
/* Enable OpenGL support */
#ifndef SDL_VIDEO_OPENGL
#define SDL_VIDEO_OPENGL 1
#endif
#ifndef SDL_VIDEO_OPENGL_WGL
#define SDL_VIDEO_OPENGL_WGL 1
#endif
#ifndef SDL_VIDEO_RENDER_OGL
#define SDL_VIDEO_RENDER_OGL 1
#endif
#ifndef SDL_VIDEO_RENDER_OGL_ES2
#define SDL_VIDEO_RENDER_OGL_ES2 1
#endif
#ifndef SDL_VIDEO_OPENGL_ES2
#define SDL_VIDEO_OPENGL_ES2 1
#endif
#ifndef SDL_VIDEO_OPENGL_EGL
#define SDL_VIDEO_OPENGL_EGL 1
#endif
/* Enable Vulkan support */
#define SDL_VIDEO_VULKAN 1
/* Enable system power support */
#define SDL_POWER_WINDOWS 1
/* Enable filesystem support */
#define SDL_FILESYSTEM_WINDOWS 1
/* Enable assembly routines (Win64 doesn't have inline asm) */
#ifndef _WIN64
#define SDL_ASSEMBLY_ROUTINES 1
#endif
#endif /* SDL_config_windows_h_ */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_config_h_
#define SDL_config_h_
/**
* \file SDL_config.h.in
*
* This is a set of defines to configure the SDL features
*/
/* General platform specific identifiers */
#include "SDL_platform.h"
/* C language features */
#cmakedefine const @HAVE_CONST@
#cmakedefine inline @HAVE_INLINE@
#cmakedefine volatile @HAVE_VOLATILE@
/* C datatypes */
/* Define SIZEOF_VOIDP for 64/32 architectures */
#ifdef __LP64__
#define SIZEOF_VOIDP 8
#else
#define SIZEOF_VOIDP 4
#endif
#cmakedefine HAVE_GCC_ATOMICS @HAVE_GCC_ATOMICS@
#cmakedefine HAVE_GCC_SYNC_LOCK_TEST_AND_SET @HAVE_GCC_SYNC_LOCK_TEST_AND_SET@
#cmakedefine HAVE_D3D_H @HAVE_D3D_H@
#cmakedefine HAVE_D3D11_H @HAVE_D3D11_H@
#cmakedefine HAVE_DDRAW_H @HAVE_DDRAW_H@
#cmakedefine HAVE_DSOUND_H @HAVE_DSOUND_H@
#cmakedefine HAVE_DINPUT_H @HAVE_DINPUT_H@
#cmakedefine HAVE_XAUDIO2_H @HAVE_XAUDIO2_H@
#cmakedefine HAVE_XINPUT_H @HAVE_XINPUT_H@
#cmakedefine HAVE_DXGI_H @HAVE_DXGI_H@
#cmakedefine HAVE_XINPUT_GAMEPAD_EX @HAVE_XINPUT_GAMEPAD_EX@
#cmakedefine HAVE_XINPUT_STATE_EX @HAVE_XINPUT_STATE_EX@
/* Comment this if you want to build without any C library requirements */
#cmakedefine HAVE_LIBC 1
#if HAVE_LIBC
/* Useful headers */
#cmakedefine HAVE_ALLOCA_H 1
#cmakedefine HAVE_SYS_TYPES_H 1
#cmakedefine HAVE_STDIO_H 1
#cmakedefine STDC_HEADERS 1
#cmakedefine HAVE_STDLIB_H 1
#cmakedefine HAVE_STDARG_H 1
#cmakedefine HAVE_MALLOC_H 1
#cmakedefine HAVE_MEMORY_H 1
#cmakedefine HAVE_STRING_H 1
#cmakedefine HAVE_STRINGS_H 1
#cmakedefine HAVE_WCHAR_H 1
#cmakedefine HAVE_INTTYPES_H 1
#cmakedefine HAVE_STDINT_H 1
#cmakedefine HAVE_CTYPE_H 1
#cmakedefine HAVE_MATH_H 1
#cmakedefine HAVE_ICONV_H 1
#cmakedefine HAVE_SIGNAL_H 1
#cmakedefine HAVE_ALTIVEC_H 1
#cmakedefine HAVE_PTHREAD_NP_H 1
#cmakedefine HAVE_LIBUDEV_H 1
#cmakedefine HAVE_DBUS_DBUS_H 1
#cmakedefine HAVE_IBUS_IBUS_H 1
#cmakedefine HAVE_FCITX_FRONTEND_H 1
#cmakedefine HAVE_LIBSAMPLERATE_H 1
/* C library functions */
#cmakedefine HAVE_MALLOC 1
#cmakedefine HAVE_CALLOC 1
#cmakedefine HAVE_REALLOC 1
#cmakedefine HAVE_FREE 1
#cmakedefine HAVE_ALLOCA 1
#ifndef __WIN32__ /* Don't use C runtime versions of these on Windows */
#cmakedefine HAVE_GETENV 1
#cmakedefine HAVE_SETENV 1
#cmakedefine HAVE_PUTENV 1
#cmakedefine HAVE_UNSETENV 1
#endif
#cmakedefine HAVE_QSORT 1
#cmakedefine HAVE_ABS 1
#cmakedefine HAVE_BCOPY 1
#cmakedefine HAVE_MEMSET 1
#cmakedefine HAVE_MEMCPY 1
#cmakedefine HAVE_MEMMOVE 1
#cmakedefine HAVE_MEMCMP 1
#cmakedefine HAVE_WCSLEN 1
#cmakedefine HAVE_WCSLCPY 1
#cmakedefine HAVE_WCSLCAT 1
#cmakedefine HAVE_WCSCMP 1
#cmakedefine HAVE_STRLEN 1
#cmakedefine HAVE_STRLCPY 1
#cmakedefine HAVE_STRLCAT 1
#cmakedefine HAVE_STRDUP 1
#cmakedefine HAVE__STRREV 1
#cmakedefine HAVE__STRUPR 1
#cmakedefine HAVE__STRLWR 1
#cmakedefine HAVE_INDEX 1
#cmakedefine HAVE_RINDEX 1
#cmakedefine HAVE_STRCHR 1
#cmakedefine HAVE_STRRCHR 1
#cmakedefine HAVE_STRSTR 1
#cmakedefine HAVE_ITOA 1
#cmakedefine HAVE__LTOA 1
#cmakedefine HAVE__UITOA 1
#cmakedefine HAVE__ULTOA 1
#cmakedefine HAVE_STRTOL 1
#cmakedefine HAVE_STRTOUL 1
#cmakedefine HAVE__I64TOA 1
#cmakedefine HAVE__UI64TOA 1
#cmakedefine HAVE_STRTOLL 1
#cmakedefine HAVE_STRTOULL 1
#cmakedefine HAVE_STRTOD 1
#cmakedefine HAVE_ATOI 1
#cmakedefine HAVE_ATOF 1
#cmakedefine HAVE_STRCMP 1
#cmakedefine HAVE_STRNCMP 1
#cmakedefine HAVE__STRICMP 1
#cmakedefine HAVE_STRCASECMP 1
#cmakedefine HAVE__STRNICMP 1
#cmakedefine HAVE_STRNCASECMP 1
#cmakedefine HAVE_VSSCANF 1
#cmakedefine HAVE_VSNPRINTF 1
#cmakedefine HAVE_M_PI 1
#cmakedefine HAVE_ATAN 1
#cmakedefine HAVE_ATAN2 1
#cmakedefine HAVE_ACOS 1
#cmakedefine HAVE_ASIN 1
#cmakedefine HAVE_CEIL 1
#cmakedefine HAVE_COPYSIGN 1
#cmakedefine HAVE_COS 1
#cmakedefine HAVE_COSF 1
#cmakedefine HAVE_FABS 1
#cmakedefine HAVE_FLOOR 1
#cmakedefine HAVE_LOG 1
#cmakedefine HAVE_POW 1
#cmakedefine HAVE_SCALBN 1
#cmakedefine HAVE_SIN 1
#cmakedefine HAVE_SINF 1
#cmakedefine HAVE_SQRT 1
#cmakedefine HAVE_SQRTF 1
#cmakedefine HAVE_TAN 1
#cmakedefine HAVE_TANF 1
#cmakedefine HAVE_FOPEN64 1
#cmakedefine HAVE_FSEEKO 1
#cmakedefine HAVE_FSEEKO64 1
#cmakedefine HAVE_SIGACTION 1
#cmakedefine HAVE_SA_SIGACTION 1
#cmakedefine HAVE_SETJMP 1
#cmakedefine HAVE_NANOSLEEP 1
#cmakedefine HAVE_SYSCONF 1
#cmakedefine HAVE_SYSCTLBYNAME 1
#cmakedefine HAVE_CLOCK_GETTIME 1
#cmakedefine HAVE_GETPAGESIZE 1
#cmakedefine HAVE_MPROTECT 1
#cmakedefine HAVE_ICONV 1
#cmakedefine HAVE_PTHREAD_SETNAME_NP 1
#cmakedefine HAVE_PTHREAD_SET_NAME_NP 1
#cmakedefine HAVE_SEM_TIMEDWAIT 1
#cmakedefine HAVE_GETAUXVAL 1
#cmakedefine HAVE_POLL 1
#elif __WIN32__
#cmakedefine HAVE_STDARG_H 1
#cmakedefine HAVE_STDDEF_H 1
#else
/* We may need some replacement for stdarg.h here */
#include <stdarg.h>
#endif /* HAVE_LIBC */
/* SDL internal assertion support */
#cmakedefine SDL_DEFAULT_ASSERT_LEVEL @SDL_DEFAULT_ASSERT_LEVEL@
/* Allow disabling of core subsystems */
#cmakedefine SDL_ATOMIC_DISABLED @SDL_ATOMIC_DISABLED@
#cmakedefine SDL_AUDIO_DISABLED @SDL_AUDIO_DISABLED@
#cmakedefine SDL_CPUINFO_DISABLED @SDL_CPUINFO_DISABLED@
#cmakedefine SDL_EVENTS_DISABLED @SDL_EVENTS_DISABLED@
#cmakedefine SDL_FILE_DISABLED @SDL_FILE_DISABLED@
#cmakedefine SDL_JOYSTICK_DISABLED @SDL_JOYSTICK_DISABLED@
#cmakedefine SDL_HAPTIC_DISABLED @SDL_HAPTIC_DISABLED@
#cmakedefine SDL_LOADSO_DISABLED @SDL_LOADSO_DISABLED@
#cmakedefine SDL_RENDER_DISABLED @SDL_RENDER_DISABLED@
#cmakedefine SDL_THREADS_DISABLED @SDL_THREADS_DISABLED@
#cmakedefine SDL_TIMERS_DISABLED @SDL_TIMERS_DISABLED@
#cmakedefine SDL_VIDEO_DISABLED @SDL_VIDEO_DISABLED@
#cmakedefine SDL_POWER_DISABLED @SDL_POWER_DISABLED@
#cmakedefine SDL_FILESYSTEM_DISABLED @SDL_FILESYSTEM_DISABLED@
/* Enable various audio drivers */
#cmakedefine SDL_AUDIO_DRIVER_ALSA @SDL_AUDIO_DRIVER_ALSA@
#cmakedefine SDL_AUDIO_DRIVER_ALSA_DYNAMIC @SDL_AUDIO_DRIVER_ALSA_DYNAMIC@
#cmakedefine SDL_AUDIO_DRIVER_ANDROID @SDL_AUDIO_DRIVER_ANDROID@
#cmakedefine SDL_AUDIO_DRIVER_ARTS @SDL_AUDIO_DRIVER_ARTS@
#cmakedefine SDL_AUDIO_DRIVER_ARTS_DYNAMIC @SDL_AUDIO_DRIVER_ARTS_DYNAMIC@
#cmakedefine SDL_AUDIO_DRIVER_COREAUDIO @SDL_AUDIO_DRIVER_COREAUDIO@
#cmakedefine SDL_AUDIO_DRIVER_DISK @SDL_AUDIO_DRIVER_DISK@
#cmakedefine SDL_AUDIO_DRIVER_DSOUND @SDL_AUDIO_DRIVER_DSOUND@
#cmakedefine SDL_AUDIO_DRIVER_DUMMY @SDL_AUDIO_DRIVER_DUMMY@
#cmakedefine SDL_AUDIO_DRIVER_EMSCRIPTEN @SDL_AUDIO_DRIVER_EMSCRIPTEN@
#cmakedefine SDL_AUDIO_DRIVER_ESD @SDL_AUDIO_DRIVER_ESD@
#cmakedefine SDL_AUDIO_DRIVER_ESD_DYNAMIC @SDL_AUDIO_DRIVER_ESD_DYNAMIC@
#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND @SDL_AUDIO_DRIVER_FUSIONSOUND@
#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC @SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC@
#cmakedefine SDL_AUDIO_DRIVER_HAIKU @SDL_AUDIO_DRIVER_HAIKU@
#cmakedefine SDL_AUDIO_DRIVER_JACK @SDL_AUDIO_DRIVER_JACK@
#cmakedefine SDL_AUDIO_DRIVER_JACK_DYNAMIC @SDL_AUDIO_DRIVER_JACK_DYNAMIC@
#cmakedefine SDL_AUDIO_DRIVER_NAS @SDL_AUDIO_DRIVER_NAS@
#cmakedefine SDL_AUDIO_DRIVER_NAS_DYNAMIC @SDL_AUDIO_DRIVER_NAS_DYNAMIC@
#cmakedefine SDL_AUDIO_DRIVER_NETBSD @SDL_AUDIO_DRIVER_NETBSD@
#cmakedefine SDL_AUDIO_DRIVER_OSS @SDL_AUDIO_DRIVER_OSS@
#cmakedefine SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H @SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H@
#cmakedefine SDL_AUDIO_DRIVER_PAUDIO @SDL_AUDIO_DRIVER_PAUDIO@
#cmakedefine SDL_AUDIO_DRIVER_PULSEAUDIO @SDL_AUDIO_DRIVER_PULSEAUDIO@
#cmakedefine SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC @SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC@
#cmakedefine SDL_AUDIO_DRIVER_QSA @SDL_AUDIO_DRIVER_QSA@
#cmakedefine SDL_AUDIO_DRIVER_SNDIO @SDL_AUDIO_DRIVER_SNDIO@
#cmakedefine SDL_AUDIO_DRIVER_SNDIO_DYNAMIC @SDL_AUDIO_DRIVER_SNDIO_DYNAMIC@
#cmakedefine SDL_AUDIO_DRIVER_SUNAUDIO @SDL_AUDIO_DRIVER_SUNAUDIO@
#cmakedefine SDL_AUDIO_DRIVER_WASAPI @SDL_AUDIO_DRIVER_WASAPI@
#cmakedefine SDL_AUDIO_DRIVER_WINMM @SDL_AUDIO_DRIVER_WINMM@
#cmakedefine SDL_AUDIO_DRIVER_XAUDIO2 @SDL_AUDIO_DRIVER_XAUDIO2@
/* Enable various input drivers */
#cmakedefine SDL_INPUT_LINUXEV @SDL_INPUT_LINUXEV@
#cmakedefine SDL_INPUT_LINUXKD @SDL_INPUT_LINUXKD@
#cmakedefine SDL_INPUT_TSLIB @SDL_INPUT_TSLIB@
#cmakedefine SDL_JOYSTICK_ANDROID @SDL_JOYSTICK_ANDROID@
#cmakedefine SDL_JOYSTICK_HAIKU @SDL_JOYSTICK_HAIKU@
#cmakedefine SDL_JOYSTICK_DINPUT @SDL_JOYSTICK_DINPUT@
#cmakedefine SDL_JOYSTICK_XINPUT @SDL_JOYSTICK_XINPUT@
#cmakedefine SDL_JOYSTICK_DUMMY @SDL_JOYSTICK_DUMMY@
#cmakedefine SDL_JOYSTICK_IOKIT @SDL_JOYSTICK_IOKIT@
#cmakedefine SDL_JOYSTICK_MFI @SDL_JOYSTICK_MFI@
#cmakedefine SDL_JOYSTICK_LINUX @SDL_JOYSTICK_LINUX@
#cmakedefine SDL_JOYSTICK_WINMM @SDL_JOYSTICK_WINMM@
#cmakedefine SDL_JOYSTICK_USBHID @SDL_JOYSTICK_USBHID@
#cmakedefine SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H @SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H@
#cmakedefine SDL_JOYSTICK_EMSCRIPTEN @SDL_JOYSTICK_EMSCRIPTEN@
#cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@
#cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@
#cmakedefine SDL_HAPTIC_IOKIT @SDL_HAPTIC_IOKIT@
#cmakedefine SDL_HAPTIC_DINPUT @SDL_HAPTIC_DINPUT@
#cmakedefine SDL_HAPTIC_XINPUT @SDL_HAPTIC_XINPUT@
#cmakedefine SDL_HAPTIC_ANDROID @SDL_HAPTIC_ANDROID@
/* Enable various shared object loading systems */
#cmakedefine SDL_LOADSO_DLOPEN @SDL_LOADSO_DLOPEN@
#cmakedefine SDL_LOADSO_DUMMY @SDL_LOADSO_DUMMY@
#cmakedefine SDL_LOADSO_LDG @SDL_LOADSO_LDG@
#cmakedefine SDL_LOADSO_WINDOWS @SDL_LOADSO_WINDOWS@
/* Enable various threading systems */
#cmakedefine SDL_THREAD_PTHREAD @SDL_THREAD_PTHREAD@
#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX@
#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP@
#cmakedefine SDL_THREAD_WINDOWS @SDL_THREAD_WINDOWS@
/* Enable various timer systems */
#cmakedefine SDL_TIMER_HAIKU @SDL_TIMER_HAIKU@
#cmakedefine SDL_TIMER_DUMMY @SDL_TIMER_DUMMY@
#cmakedefine SDL_TIMER_UNIX @SDL_TIMER_UNIX@
#cmakedefine SDL_TIMER_WINDOWS @SDL_TIMER_WINDOWS@
#cmakedefine SDL_TIMER_WINCE @SDL_TIMER_WINCE@
/* Enable various video drivers */
#cmakedefine SDL_VIDEO_DRIVER_ANDROID @SDL_VIDEO_DRIVER_ANDROID@
#cmakedefine SDL_VIDEO_DRIVER_HAIKU @SDL_VIDEO_DRIVER_HAIKU@
#cmakedefine SDL_VIDEO_DRIVER_COCOA @SDL_VIDEO_DRIVER_COCOA@
#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB @SDL_VIDEO_DRIVER_DIRECTFB@
#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC @SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC@
#cmakedefine SDL_VIDEO_DRIVER_DUMMY @SDL_VIDEO_DRIVER_DUMMY@
#cmakedefine SDL_VIDEO_DRIVER_WINDOWS @SDL_VIDEO_DRIVER_WINDOWS@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND @SDL_VIDEO_DRIVER_WAYLAND@
#cmakedefine SDL_VIDEO_DRIVER_RPI @SDL_VIDEO_DRIVER_RPI@
#cmakedefine SDL_VIDEO_DRIVER_VIVANTE @SDL_VIDEO_DRIVER_VIVANTE@
#cmakedefine SDL_VIDEO_DRIVER_VIVANTE_VDK @SDL_VIDEO_DRIVER_VIVANTE_VDK@
#cmakedefine SDL_VIDEO_DRIVER_KMSDRM @SDL_VIDEO_DRIVER_KMSDRM@
#cmakedefine SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC @SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC@
#cmakedefine SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM @SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH @SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON@
#cmakedefine SDL_VIDEO_DRIVER_MIR @SDL_VIDEO_DRIVER_MIR@
#cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC @SDL_VIDEO_DRIVER_MIR_DYNAMIC@
#cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON@
#cmakedefine SDL_VIDEO_DRIVER_EMSCRIPTEN @SDL_VIDEO_DRIVER_EMSCRIPTEN@
#cmakedefine SDL_VIDEO_DRIVER_X11 @SDL_VIDEO_DRIVER_X11@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC @SDL_VIDEO_DRIVER_X11_DYNAMIC@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT @SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS @SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE @SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE@
#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR @SDL_VIDEO_DRIVER_X11_XCURSOR@
#cmakedefine SDL_VIDEO_DRIVER_X11_XDBE @SDL_VIDEO_DRIVER_X11_XDBE@
#cmakedefine SDL_VIDEO_DRIVER_X11_XINERAMA @SDL_VIDEO_DRIVER_X11_XINERAMA@
#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2 @SDL_VIDEO_DRIVER_X11_XINPUT2@
#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH @SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH@
#cmakedefine SDL_VIDEO_DRIVER_X11_XRANDR @SDL_VIDEO_DRIVER_X11_XRANDR@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER @SDL_VIDEO_DRIVER_X11_XSCRNSAVER@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE @SDL_VIDEO_DRIVER_X11_XSHAPE@
#cmakedefine SDL_VIDEO_DRIVER_X11_XVIDMODE @SDL_VIDEO_DRIVER_X11_XVIDMODE@
#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS @SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS@
#cmakedefine SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY @SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY@
#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM @SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM@
#cmakedefine SDL_VIDEO_RENDER_D3D @SDL_VIDEO_RENDER_D3D@
#cmakedefine SDL_VIDEO_RENDER_D3D11 @SDL_VIDEO_RENDER_D3D11@
#cmakedefine SDL_VIDEO_RENDER_OGL @SDL_VIDEO_RENDER_OGL@
#cmakedefine SDL_VIDEO_RENDER_OGL_ES @SDL_VIDEO_RENDER_OGL_ES@
#cmakedefine SDL_VIDEO_RENDER_OGL_ES2 @SDL_VIDEO_RENDER_OGL_ES2@
#cmakedefine SDL_VIDEO_RENDER_DIRECTFB @SDL_VIDEO_RENDER_DIRECTFB@
/* Enable OpenGL support */
#cmakedefine SDL_VIDEO_OPENGL @SDL_VIDEO_OPENGL@
#cmakedefine SDL_VIDEO_OPENGL_ES @SDL_VIDEO_OPENGL_ES@
#cmakedefine SDL_VIDEO_OPENGL_ES2 @SDL_VIDEO_OPENGL_ES2@
#cmakedefine SDL_VIDEO_OPENGL_BGL @SDL_VIDEO_OPENGL_BGL@
#cmakedefine SDL_VIDEO_OPENGL_CGL @SDL_VIDEO_OPENGL_CGL@
#cmakedefine SDL_VIDEO_OPENGL_GLX @SDL_VIDEO_OPENGL_GLX@
#cmakedefine SDL_VIDEO_OPENGL_WGL @SDL_VIDEO_OPENGL_WGL@
#cmakedefine SDL_VIDEO_OPENGL_EGL @SDL_VIDEO_OPENGL_EGL@
#cmakedefine SDL_VIDEO_OPENGL_OSMESA @SDL_VIDEO_OPENGL_OSMESA@
#cmakedefine SDL_VIDEO_OPENGL_OSMESA_DYNAMIC @SDL_VIDEO_OPENGL_OSMESA_DYNAMIC@
/* Enable Vulkan support */
#cmakedefine SDL_VIDEO_VULKAN @SDL_VIDEO_VULKAN@
/* Enable system power support */
#cmakedefine SDL_POWER_ANDROID @SDL_POWER_ANDROID@
#cmakedefine SDL_POWER_LINUX @SDL_POWER_LINUX@
#cmakedefine SDL_POWER_WINDOWS @SDL_POWER_WINDOWS@
#cmakedefine SDL_POWER_MACOSX @SDL_POWER_MACOSX@
#cmakedefine SDL_POWER_HAIKU @SDL_POWER_HAIKU@
#cmakedefine SDL_POWER_EMSCRIPTEN @SDL_POWER_EMSCRIPTEN@
#cmakedefine SDL_POWER_HARDWIRED @SDL_POWER_HARDWIRED@
/* Enable system filesystem support */
#cmakedefine SDL_FILESYSTEM_ANDROID @SDL_FILESYSTEM_ANDROID@
#cmakedefine SDL_FILESYSTEM_HAIKU @SDL_FILESYSTEM_HAIKU@
#cmakedefine SDL_FILESYSTEM_COCOA @SDL_FILESYSTEM_COCOA@
#cmakedefine SDL_FILESYSTEM_DUMMY @SDL_FILESYSTEM_DUMMY@
#cmakedefine SDL_FILESYSTEM_UNIX @SDL_FILESYSTEM_UNIX@
#cmakedefine SDL_FILESYSTEM_WINDOWS @SDL_FILESYSTEM_WINDOWS@
#cmakedefine SDL_FILESYSTEM_EMSCRIPTEN @SDL_FILESYSTEM_EMSCRIPTEN@
/* Enable assembly routines */
#cmakedefine SDL_ASSEMBLY_ROUTINES @SDL_ASSEMBLY_ROUTINES@
#cmakedefine SDL_ALTIVEC_BLITTERS @SDL_ALTIVEC_BLITTERS@
/* Enable dynamic libsamplerate support */
#cmakedefine SDL_LIBSAMPLERATE_DYNAMIC @SDL_LIBSAMPLERATE_DYNAMIC@
/* Platform specific definitions */
#if !defined(__WIN32__)
# if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
typedef unsigned int size_t;
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
typedef unsigned long uintptr_t;
# endif /* if (stdint.h isn't available) */
#else /* __WIN32__ */
# if !defined(_STDINT_H_) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
# if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
#define HAVE_STDINT_H 1
# elif defined(_MSC_VER)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
# ifndef _UINTPTR_T_DEFINED
# ifdef _WIN64
typedef unsigned __int64 uintptr_t;
# else
typedef unsigned int uintptr_t;
# endif
#define _UINTPTR_T_DEFINED
# endif
/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
# if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
#define DWORD_PTR DWORD
# endif
# if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
#define LONG_PTR LONG
# endif
# else /* !__GNUC__ && !_MSC_VER */
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
# ifndef _SIZE_T_DEFINED_
#define _SIZE_T_DEFINED_
typedef unsigned int size_t;
# endif
typedef unsigned int uintptr_t;
# endif /* __GNUC__ || _MSC_VER */
# endif /* !_STDINT_H_ && !HAVE_STDINT_H */
#endif /* __WIN32__ */
#endif /* SDL_config_h_ */