#include "sdl_overlay.h" #include "charbits.h" typedef struct { const uint8_t* bits; uint8_t shift; } bit_buffer; void make_bit_buffer(bit_buffer* buf, const uint8_t* bits) { buf->bits = bits; buf->shift = 0; } uint8_t get_bits(bit_buffer* buf) { uint8_t val = ((buf->bits[0] >> buf->shift) & 3); if (buf->shift == 6) { buf->shift = 0; buf->bits++; } else { buf->shift += 2; } return val; } static const SDL_Color pal[2] = { {0, 0, 0, 255}, {255, 255, 255, 255} }; static SDL_Surface* create_char_surface(const uint8_t* bits) { int w = *bits++; bit_buffer buf = {0}; make_bit_buffer(&buf, bits); SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat( 0, w, char_h, 8, SDL_PIXELFORMAT_INDEX8 ); SDL_SetPaletteColors(surface->format->palette, pal, 1U, 2U); SDL_SetColorKey(surface, SDL_TRUE, 0); uint8_t* line = surface->pixels; for (int y = char_h; y > 0; --y) { uint8_t* dst = line; for (int x = w; x > 0; --x) { *dst++ = get_bits(&buf); } for (int x = (char_w - w); x > 0; --x) get_bits(&buf); line += surface->pitch; } return surface; } static SDL_Texture* create_char_texture(SDL_Renderer* rend, const uint8_t* bits) { SDL_Surface* surface = create_char_surface(bits); SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE); SDL_Texture* texture = SDL_CreateTextureFromSurface( rend, surface ); SDL_FreeSurface(surface); return texture; } int sdl_overlay_font_init(SDL_Renderer* rend, sdl_overlay_font* font) { font->chars = chars; font->charbits = charbits; font->char_count = char_count; font->textures = calloc(char_count, sizeof(SDL_Texture*)); for (int i = 0; i < font->char_count; ++i) { font->textures[i] = create_char_texture( rend, &font->charbits[i * charbit_size] ); } return 0; } void sdl_overlay_font_done(sdl_overlay_font* font) { for (int i = 0; i < font->char_count; ++i) { SDL_DestroyTexture(font->textures[i]); } } #define overlay_start_x (char_w / 2) #define overlay_start_y (char_h / 2) static inline int char_index(char c) { if (c >= 'a' && c <= 'z') c += ('A' - 'a'); if (c > ' ' && c < 'a') return (c - ' '); if (c >= '{' && c <= '~') return (65 + c - '{'); return 0; } static void render_string(SDL_Renderer* rend, int ox, int oy, int sx, int sy, sdl_overlay_font* font, const char* string) { for (const char* c = string; *c; ++c) { if (*c == ' ') { ox += ((char_w / 2) - 1); } else { int index = char_index(*c); int cw = font->charbits[index * charbit_size]; SDL_Texture* texture = font->textures[index]; SDL_Rect rect = { .x = ox * sx, .y = oy * sy, .w = cw * sx, .h = char_h * sy, }; SDL_RenderCopy(rend, texture, NULL, &rect); ox += (cw - 1); } } } int sdl_overlay_frame(Overlay* overlay, sdl_overlay_font* font, SDL_Renderer* rend, int sx, int sy) { int y = overlay_start_y; overlay_message* last = NULL, *next = NULL; for ( overlay_message* message = overlay->messages; NULL != message; last = message, message = next) { next = message->next; render_string(rend, overlay_start_x, y, sx, sy, font, message->string); y += (char_h + 1); if (message->expiry > 0 && --(message->expiry) == 0) { if (NULL == last) { overlay->messages = message->next; } else { last->next = message->next; } free(message->string); free(message); } } return 0; }