diff options
-rw-r--r-- | font.c | 153 | ||||
-rw-r--r-- | font.h | 30 | ||||
-rw-r--r-- | window.c | 27 |
3 files changed, 73 insertions, 137 deletions
@@ -1,140 +1,75 @@ #include "font.h" -/* Create a texture containing all of the glyphs in a specified BDF file. */ -SDL_Texture *font_create_texture(SDL_Renderer *renderer, BDFFontInfo *font) +#include <assert.h> +#include <stdlib.h> + +/* Create a texture atlas containing all of the glyphs in a font. */ +SDL_Texture *font_create_texture(SDL_Renderer *renderer, PSFFont *font) { SDL_Texture *result; - SDL_Surface *surface = SDL_CreateRGBSurface(0, 8 * font->num_chars, font->bounds.h, 32, 0, 0, 0, 0); - - printf("Made surface of size %dx%d\n", surface->w, surface->h); - SDL_LockSurface(surface); - for (int i = 0; i < font->num_chars; i++) { - BDFFontChar chair = font->chars[i]; - for (int y = 0; y < font->bounds.h; y++) { - int bits_for_row = chair.bitmap[y]; - for (int x = 0; x < 8; x++) { - int bit_index = 7 - x; - int current_bit = bits_for_row & (1 << bit_index); - int xp = x + i * 8; + + const int texture_width = font->num_glyphs * font->width; + const int bits_per_glyph = 8; + SDL_Surface *surface = SDL_CreateRGBSurface(0, texture_width, font->height, 32, 0, 0, 0, 0); + + for (int glyph_idx = 0; glyph_idx < font->num_glyphs; glyph_idx++) { + for (int y = 0; y < font->height; y++) { + for (int x = 0; x < font->width; x++) { + /* + * TODO: Make it possible for the texture atlas to have more + * than one row. + */ + int xp = x + glyph_idx * bits_per_glyph; int yp = y; + + int bit_idx = 8 - 1 - x; + char current_bit = font->glyph_data[glyph_idx * font->bytes_per_glyph + y] & (1 << bit_idx); ((Uint32*)(surface->pixels))[xp + yp * surface->w] = current_bit ? 0xffffffff : 0; } } } - SDL_UnlockSurface(surface); result = SDL_CreateTextureFromSurface(renderer, surface); if (result == NULL) { fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError()); } SDL_FreeSurface(surface); + + printf("Created font texture atlas of size %dx%d\n", surface->w, surface->h); return result; } -/* - * Loads a BDF font file into a data structure. - * TODO: This is extremely atrocious! - */ -BDFFontInfo font_load(const char *filename) +PSFFont font_load(const char *filename) { - FILE *fp; - char *line = NULL; - size_t len = 0; - ssize_t bytes_read; - - BDFFontInfo result; - result.bounds.x = 0; - result.bounds.y = 0; - result.bounds.w = 0; - result.bounds.h = 0; - result.chars = NULL; - result.num_chars = 0; - for (int i = 0; i < 128; i++) { - result.char_index_for_code_point[i] = 0; - } - - fp = fopen(filename, "r"); - if (fp == NULL) { - fprintf(stderr, "Failed to open file from %s\n", filename); - return; - } + PSFFont font; - int is_reading_bitmap = 0; - int char_counter = -1; - while ((bytes_read = getline(&line, &len, fp)) != -1) { - if (strncmp(line, "FONTBOUNDINGBOX", 15) == 0) { - sscanf(line, "FONTBOUNDINGBOX %d %d %d %d\n", &result.bounds.w, - &result.bounds.h, - &result.bounds.x, - &result.bounds.y); + FILE *fp = fopen(filename, "rb"); - } + fread(&font.magic, 4, 1, fp); + assert(font.magic == PSF_MAGIC_NUMBER); - if (strncmp(line, "CHARS", 5) == 0) { - sscanf(line, "CHARS %d\n", &result.num_chars); - result.chars = malloc(result.num_chars * sizeof(BDFFontChar)); - } + fread(&font.version, 4, 1, fp); + fread(&font.header_size, 4, 1, fp); + fread(&font.flags, 4, 1, fp); + fread(&font.num_glyphs, 4, 1, fp); + fread(&font.bytes_per_glyph, 4, 1, fp); + fread(&font.height, 4, 1, fp); + fread(&font.width, 4, 1, fp); - if (strncmp(line, "STARTCHAR", 9) == 0) { - char_counter++; - result.chars[char_counter].code_point = 0; - result.chars[char_counter].next_glyph_offset.x = 0; - result.chars[char_counter].next_glyph_offset.y = 0; - result.chars[char_counter].bounds.x = 0; - result.chars[char_counter].bounds.y = 0; - result.chars[char_counter].bounds.w = 0; - result.chars[char_counter].bounds.h = 0; - result.chars[char_counter].bitmap = NULL; - result.chars[char_counter].bitmap_size = 0; - } + /* TODO: Implement unicode translation table. */ - if (strncmp(line, "ENCODING", 8) == 0) { - int code_point = 0; - sscanf(line, "ENCODING %d\n", &code_point); - if (code_point < 256) - result.char_index_for_code_point[code_point] = char_counter; - result.chars[char_counter].code_point = code_point; - } - - if (strncmp(line, "DWIDTH", 6) == 0) { - sscanf(line, "DWIDTH %d %d\n", &result.chars[char_counter].next_glyph_offset.x, - &result.chars[char_counter].next_glyph_offset.y); - } - - if (strncmp(line, "BBX", 3) == 0) { - sscanf(line, "BBX %d %d %d %d\n", &result.chars[char_counter].bounds.w, - &result.chars[char_counter].bounds.h, - &result.chars[char_counter].bounds.x, - &result.chars[char_counter].bounds.y); - result.chars[char_counter].bounds.x += char_counter * 8; - result.chars[char_counter].bounds.y = -result.chars[char_counter].bounds.y; - } - - if (strncmp(line, "BITMAP", 6) == 0) { - is_reading_bitmap = 1; - } - - if (is_reading_bitmap) { - if (strncmp(line, "ENDCHAR", 7) == 0) { - is_reading_bitmap = 0; - continue; - } - - BDFFontChar *chair = &result.chars[char_counter]; - chair->bitmap = realloc(chair->bitmap, chair->bitmap_size++); - chair->bitmap[chair->bitmap_size - 1] = strtol(line, NULL, 16); - } - } + size_t glyph_buffer_size = font.num_glyphs * font.bytes_per_glyph; + font.glyph_data = malloc(glyph_buffer_size); + fread(font.glyph_data, font.bytes_per_glyph, font.num_glyphs, fp); fclose(fp); - if (line) { free(line); } - return result; + printf("Loaded a font with %d glyphs of size %dx%d (%d bytes per glyph)\n", + font.num_glyphs, font.width, font.height, font.bytes_per_glyph); + return font; } -void font_destroy(BDFFontInfo *font) +void font_destroy(PSFFont *font) { - for (int i = 0; i < font->num_chars; i++) - free(font->chars[i].bitmap); - free(font->chars); + free(font->glyph_data); } @@ -3,23 +3,25 @@ #include <SDL2/SDL.h> +#define PSF_MAGIC_NUMBER 0x864ab572 + typedef struct { - int code_point; - SDL_Point next_glyph_offset; - SDL_Rect bounds; - char *bitmap; - int bitmap_size; -} BDFFontChar; +} PSFFontHeader; typedef struct { - SDL_Rect bounds; - BDFFontChar *chars; - int num_chars; - int char_index_for_code_point[128]; -} BDFFontInfo; + uint32_t magic; + uint32_t version; + uint32_t header_size; + uint32_t flags; + uint32_t num_glyphs; + uint32_t bytes_per_glyph; + uint32_t height; + uint32_t width; + uint8_t *glyph_data; +} PSFFont; -BDFFontInfo font_load(const char *); -SDL_Texture *font_create_texture(SDL_Renderer *, BDFFontInfo *); -void font_destroy(BDFFontInfo *); +PSFFont font_load(const char *); +SDL_Texture *font_create_texture(SDL_Renderer *, PSFFont *); +void font_destroy(PSFFont *); #endif @@ -11,7 +11,7 @@ static SDL_Window *window = NULL; static SDL_Renderer *renderer = NULL; static SDL_Texture *font_texture = NULL; -static BDFFontInfo font; +static PSFFont font; void window_init() { @@ -34,7 +34,7 @@ void window_init() return; } - font = font_load("ter-u12n.bdf"); + font = font_load("terminus/ter-u12n.psf"); font_texture = font_create_texture(renderer, &font); SDL_ShowWindow(window); @@ -93,6 +93,8 @@ int window_handle_event(struct editor_state *editor) static void draw_font_text(struct append_buffer *buffer) { SDL_Rect dstrect = { 0, 0, 0, 0 }; + SDL_Rect srcrect = { 0, 0, 0, 0 }; + for (int i = 0; i < buffer->length; i++) { const char letter = buffer->buffer[i]; if (letter > 128) { @@ -100,23 +102,20 @@ static void draw_font_text(struct append_buffer *buffer) continue; } - const int char_index = font.char_index_for_code_point[letter]; - BDFFontChar *glyph = &font.chars[char_index]; - if (glyph == NULL) { - fprintf(stderr, "Font doesn't have character %c", letter); - continue; - } + dstrect.w = font.width; + dstrect.h = font.height; - dstrect.w = glyph->bounds.w; - dstrect.h = glyph->bounds.h; - SDL_RenderCopy(renderer, font_texture, &glyph->bounds, &dstrect); + srcrect.x = letter * 8; + srcrect.y = 0; + srcrect.w = font.width; + srcrect.h = font.height; + SDL_RenderCopy(renderer, font_texture, &srcrect, &dstrect); if (letter == '\n') { dstrect.x = 0; - dstrect.y += font.bounds.h; + dstrect.y += font.height; } else { - dstrect.x += glyph->next_glyph_offset.x; - dstrect.y += glyph->next_glyph_offset.y; + dstrect.x += font.width; } } } |