summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcflip <cflip@cflip.net>2023-01-10 14:14:30 -0700
committercflip <cflip@cflip.net>2023-01-10 14:20:34 -0700
commit9347cf115a12cee9ad3bf9ed18d23ca5336ec0e9 (patch)
treedac5762e8843975fafe40b2efff47d7f0aed39ec
parentc1573dbbb3e70cad8c1f94cbed5b2abf2b124ace (diff)
Use PSF instead of BSF format for fonts
This binary file format is much easier to parse.
-rw-r--r--font.c153
-rw-r--r--font.h30
-rw-r--r--window.c27
3 files changed, 73 insertions, 137 deletions
diff --git a/font.c b/font.c
index 69e500b..01b2c43 100644
--- a/font.c
+++ b/font.c
@@ -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);
}
diff --git a/font.h b/font.h
index 3a19cb1..4f82fca 100644
--- a/font.h
+++ b/font.h
@@ -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
diff --git a/window.c b/window.c
index 027d876..1e6d5f2 100644
--- a/window.c
+++ b/window.c
@@ -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;
}
}
}