Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Last active August 29, 2015 14:07
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pervognsen/dfcdeb558ef0c0f6bcf4 to your computer and use it in GitHub Desktop.
Save pervognsen/dfcdeb558ef0c0f6bcf4 to your computer and use it in GitHub Desktop.
SDL_stb
#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