Last active
August 29, 2015 14:07
-
-
Save pervognsen/dfcdeb558ef0c0f6bcf4 to your computer and use it in GitHub Desktop.
SDL_stb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _SDL_stb_h | |
#define _SDL_stb_h | |
// Memory buffers | |
typedef struct | |
{ | |
Uint8 *data; | |
Uint32 size; | |
} SDL_MemoryBuffer; | |
void SDL_ReadMemoryBufferFromRW(SDL_MemoryBuffer *dest, SDL_RWops *src); | |
#define SDL_ReadMemoryBufferFromFile(dest, filename) SDL_ReadMemoryBufferFromRW(dest, SDL_RWFromFile((filename), "rb")) | |
// Surfaces and image loading | |
SDL_Surface *SDL_CreateSurfaceRGBA8888(void *pixels, int width, int height); | |
SDL_Surface *SDL_LoadSurfaceFromRW(SDL_RWops *src); | |
#define SDL_LoadSurface(filename) SDL_LoadSurfaceFromRW(SDL_RWFromFile((filename), "rb")) | |
// Audio buffers and loading | |
typedef struct | |
{ | |
SDL_AudioSpec spec; | |
SDL_MemoryBuffer samples; | |
} SDL_AudioBuffer; | |
SDL_AudioBuffer *SDL_CreateAudioBuffer(SDL_AudioSpec spec, SDL_MemoryBuffer samples); | |
void SDL_FreeAudioBuffer(SDL_AudioBuffer *audio_buffer); | |
SDL_AudioBuffer *SDL_LoadAudioBufferWAV(const char *filename); | |
SDL_AudioBuffer *SDL_LoadAudioBufferVorbis(const char *filename); | |
typedef struct SDL_Font SDL_Font; | |
// Truetype fonts and font atlases | |
SDL_Font *SDL_CreateFont(SDL_MemoryBuffer ttf); | |
void SDL_FreeFont(SDL_Font *font); | |
SDL_Font *SDL_LoadFontFromRW(SDL_RWops *src); | |
#define SDL_LoadFont(filename) SDL_LoadFontFromRW(SDL_RWFromFile((filename), "rb")) | |
#define SDL_FONT_ATLAS_WIDTH 512 | |
#define SDL_FONT_ATLAS_MIN_HEIGHT 32 | |
typedef struct | |
{ | |
SDL_Rect rect; | |
float x_offset; | |
float y_offset; | |
float x_advance; | |
} SDL_FontAtlasGlyph; | |
typedef struct | |
{ | |
SDL_Surface *surface; | |
int first_codepoint; | |
int num_codepoints; | |
void *glyphs; | |
} SDL_FontAtlas; | |
SDL_FontAtlas *SDL_CreateFontAtlas(SDL_Font *font, int first_codepoint, int num_codepoints, float glyph_height); | |
void SDL_FreeFontAtlas(SDL_FontAtlas *atlas); | |
SDL_FontAtlasGlyph SDL_GetFontAtlasGlyph(SDL_FontAtlas *atlas, int codepoint); | |
void SDL_BlitFontAtlasText(SDL_FontAtlas *atlas, const char *text, SDL_Surface *dest, int x, int y); | |
typedef struct | |
{ | |
int ascent; | |
int descent; | |
int line_gap; | |
int left_side_bearing; | |
int advance_width; | |
SDL_Rect bounding_box; | |
} SDL_GlyphMetrics; | |
#endif | |
#ifdef SDL_STB_IMPLEMENTATION | |
#define STB_IMAGE_IMPLEMENTATION | |
#define STB_TRUETYPE_IMPLEMENTATION | |
#include "stb_image.h" | |
#include "stb_vorbis.c" | |
#include "stb_truetype.h" | |
void SDL_ReadMemoryBufferFromRW(SDL_MemoryBuffer *dest, SDL_RWops *src) | |
{ | |
dest->size = SDL_RWsize(src); | |
dest->data = (Uint8 *) SDL_malloc(dest->size); | |
SDL_RWread(src, dest->data, 1, dest->size); | |
SDL_RWclose(src); | |
} | |
SDL_Surface *SDL_CreateSurfaceRGBA8888(void *rgba, int width, int height) | |
{ | |
return SDL_CreateRGBSurfaceFrom(rgba, width, height, 32, 4 * width, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); | |
} | |
static int SDL_stbi_callback_read(void *user, char *data, int size) | |
{ | |
return SDL_RWread((SDL_RWops *) user, data, 1, size); | |
} | |
static void SDL_stbi_callback_skip(void *user, int n) | |
{ | |
SDL_RWseek((SDL_RWops *) user, n, RW_SEEK_CUR); | |
} | |
static int SDL_stbi_callback_eof(void *user) | |
{ | |
SDL_RWops *src = (SDL_RWops *) user; | |
if (SDL_RWseek(src, +1, RW_SEEK_CUR) == -1) | |
return 1; | |
SDL_RWseek(src, -1, RW_SEEK_CUR); | |
return 0; | |
} | |
static stbi_io_callbacks SDL_stbi_callbacks = | |
{ | |
SDL_stbi_callback_read, | |
SDL_stbi_callback_skip, | |
SDL_stbi_callback_eof | |
}; | |
SDL_Surface *SDL_LoadSurfaceFromRW(SDL_RWops *src) | |
{ | |
int width, height, components; | |
Uint32 amask; | |
SDL_Surface *surface; | |
stbi_uc *pixels; | |
pixels = stbi_load_from_callbacks(&SDL_stbi_callbacks, (void *) src, &width, &height, &components, 4); | |
SDL_RWclose(src); | |
if (!pixels) | |
return NULL; | |
surface = SDL_CreateSurfaceRGBA8888(pixels, width, height); | |
if (!surface) | |
return NULL; | |
stbi_image_free(pixels); | |
return surface; | |
} | |
SDL_AudioBuffer *SDL_CreateAudioBuffer(SDL_AudioSpec spec, SDL_MemoryBuffer samples) | |
{ | |
SDL_AudioBuffer *audio_buffer = (SDL_AudioBuffer *) SDL_malloc(sizeof(SDL_AudioBuffer)); | |
audio_buffer->spec = spec; | |
audio_buffer->samples = samples; | |
return audio_buffer; | |
} | |
void SDL_FreeAudioBuffer(SDL_AudioBuffer *audio_buffer) | |
{ | |
SDL_free(audio_buffer->samples.data); | |
SDL_free(audio_buffer); | |
} | |
SDL_AudioBuffer *SDL_LoadAudioBufferWAV(const char *filename) | |
{ | |
SDL_AudioSpec spec; | |
SDL_MemoryBuffer samples; | |
if (!SDL_LoadWAV(filename, &spec, &samples.data, &samples.size)) | |
return NULL; | |
return SDL_CreateAudioBuffer(spec, samples); | |
} | |
SDL_AudioBuffer *SDL_LoadAudioBufferVorbis(const char *filename) | |
{ | |
SDL_AudioSpec spec = {0, AUDIO_S16, 0}; | |
SDL_MemoryBuffer samples; | |
int size; | |
SDL_MemoryBuffer file; | |
SDL_ReadMemoryBufferFromFile(&file, filename); | |
size = stb_vorbis_decode_memory(file.data, file.size, (int *) &spec.channels, &spec.freq, (short **) &samples.data); | |
if (size < 0) | |
return NULL; | |
samples.size = 4 * size; | |
return SDL_CreateAudioBuffer(spec, samples); | |
} | |
struct SDL_Font | |
{ | |
stbtt_fontinfo info; | |
}; | |
SDL_Font *SDL_CreateFont(SDL_MemoryBuffer ttf) | |
{ | |
SDL_Font *font = (SDL_Font *) SDL_malloc(sizeof(SDL_Font)); | |
stbtt_InitFont(&font->info, ttf.data, 0); | |
return font; | |
} | |
void SDL_FreeFont(SDL_Font *font) | |
{ | |
SDL_free(font->info.data); | |
SDL_free(font); | |
} | |
SDL_Font *SDL_LoadFontFromRW(SDL_RWops *src) | |
{ | |
SDL_MemoryBuffer ttf; | |
SDL_ReadMemoryBufferFromRW(&ttf, src); | |
return SDL_CreateFont(ttf); | |
} | |
SDL_FontAtlas *SDL_CreateFontAtlas(SDL_Font *font, int first_codepoint, int num_codepoints, float glyph_height) | |
{ | |
int size, width, height, temp_height; | |
SDL_FontAtlas *atlas; | |
Uint8 *alpha_bitmap, *rgba_bitmap, *src, *dest; | |
atlas = (SDL_FontAtlas *) SDL_malloc(sizeof(SDL_FontAtlas)); | |
atlas->first_codepoint = first_codepoint; | |
atlas->num_codepoints = num_codepoints; | |
atlas->glyphs = (stbtt_bakedchar *) SDL_malloc(num_codepoints * sizeof(stbtt_bakedchar)); | |
width = SDL_FONT_ATLAS_WIDTH; | |
for (temp_height = SDL_FONT_ATLAS_MIN_HEIGHT; ; temp_height *= 2) | |
{ | |
alpha_bitmap = (Uint8 *) SDL_malloc(width * temp_height); | |
height = stbtt_BakeFontBitmap((unsigned char *) &font->info, font->info.fontstart, glyph_height, alpha_bitmap, width, temp_height, first_codepoint, num_codepoints, atlas->glyphs); | |
if (height > 0) | |
break; | |
SDL_free(alpha_bitmap); | |
} | |
size = width * height; | |
rgba_bitmap = (Uint8 *) SDL_malloc(4 * size); | |
src = alpha_bitmap; | |
dest = rgba_bitmap; | |
for (int i = 0; i < size; i++) | |
{ | |
*dest++ = *dest++ = *dest++ = 0xFF; | |
*dest++ = *src++; | |
} | |
SDL_free(alpha_bitmap); | |
atlas->surface = SDL_CreateSurfaceRGBA8888(rgba_bitmap, width, height); | |
return atlas; | |
} | |
void SDL_FreeFontAtlas(SDL_FontAtlas *atlas) | |
{ | |
SDL_FreeSurface(atlas->surface); | |
SDL_free(atlas->glyphs); | |
SDL_free(atlas); | |
} | |
SDL_FontAtlasGlyph SDL_GetFontAtlasGlyph(SDL_FontAtlas *atlas, int codepoint) | |
{ | |
stbtt_bakedchar bakedchar = ((stbtt_bakedchar *) atlas->glyphs)[codepoint - atlas->first_codepoint]; | |
SDL_FontAtlasGlyph glyph = | |
{ | |
{bakedchar.x0, bakedchar.y0, bakedchar.x1 - bakedchar.x0, bakedchar.y1 - bakedchar.y0}, | |
bakedchar.xoff, | |
bakedchar.yoff, | |
bakedchar.xadvance | |
}; | |
return glyph; | |
} | |
void SDL_BlitFontAtlasText(SDL_FontAtlas *atlas, const char *text, SDL_Surface *dest, int x, int y) | |
{ | |
const char *p; | |
SDL_Rect rect; | |
float fx; | |
fx = x; | |
for (p = text; *p; p++) | |
{ | |
SDL_FontAtlasGlyph glyph = SDL_GetFontAtlasGlyph(atlas, *p); | |
rect.x = (int) (fx + glyph.x_offset + 0.5f); | |
rect.y = (int) (y + glyph.y_offset + 0.5f); | |
rect.w = glyph.rect.w; | |
rect.h = glyph.rect.h; | |
SDL_BlitSurface(atlas->surface, &glyph.rect, dest, &rect); | |
fx += glyph.x_advance; | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment