From 7e6637dce62351a60a357588eb813eded1f576ee Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Wed, 15 Oct 2025 13:58:33 +0100 Subject: [PATCH] Create text module for displaying messages --- build.sh | 2 +- game.c | 50 ++---------------------- text.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ text.h | 6 +++ 4 files changed, 128 insertions(+), 47 deletions(-) create mode 100644 text.c create mode 100644 text.h diff --git a/build.sh b/build.sh index 53faf61..39fc7a9 100755 --- a/build.sh +++ b/build.sh @@ -8,4 +8,4 @@ defs="-D_POSIX_C_SOURCE=200809L" $cc $warn $flags $libs $defs \ -o asteroids \ - fb.c game.c input.c main.c maths.c renderer.c rng.c + fb.c game.c input.c main.c maths.c renderer.c rng.c text.c diff --git a/game.c b/game.c index 38c680c..760de80 100644 --- a/game.c +++ b/game.c @@ -2,6 +2,7 @@ #include "input.h" #include "renderer.h" +#include "text.h" #include "rng.h" #include @@ -51,10 +52,7 @@ #define MAX_SHAPES_PER_ENTITY 2 #define MAX_COLLISIONS 128U -#define GAME_OVER_WIDTH 24 -#define GAME_OVER_HEIGHT 8 -#define GAME_OVER_SCALE 0.025 -#define GAME_OVER_COUNTER_MASK (1 << 6) +#define COUNTER_MASK (1 << 6) #define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) @@ -103,40 +101,6 @@ static const vec2_t fire_verts[] = { }; static const vec2_t shot_verts[] = { { 0.0, -0.02 }, { 0.0, 0.02 } }; -static const vec2_t game_over_verts[][MAX_VERTS] = { - // G - { { -10, 4 }, { -12, 4 }, { -12, -4 }, { -10, -4 }, { -10, 0 } }, - // A - { { -9, -4 }, { -8, 4 }, { -7, -4 } }, - { { -8.75, -2 }, { -7.25, -2 } }, - // M - { { -6, -4 }, { -6, 4 }, { -5, -4 }, { -4, 4 }, { -4, -4 } }, - // E - { { -1, 4 }, { -3, 4 }, { -3, -4 }, { -1, -4 } }, - { { -3, 0 }, { -2, 0 } }, - // O - { { 1, 4 }, { 1, -4 }, { 3, -4 }, { 3, 4 }, { 1, 4 } }, - // V - { { 4, 4 }, { 5, -4 }, { 6, 4 } }, - // E - { { 9, 4 }, { 7, 4 }, { 7, -4 }, { 9, -4 } }, - { { 7, 0 }, { 8, 0 } }, - // R - { { 10, -4 }, { 10, 4 }, { 12, 4 }, { 12, -2 }, { 10, -2 }, { 12, -4 } }, -}; -static const unsigned game_over_lens[NELEMS(game_over_verts)] = { - 5, 3, 2, 5, 4, 2, 5, 3, 4, 2, 6, -}; -static const mat3_t game_over_transform = { - { GAME_OVER_SCALE, 0, 0 }, - { 0, GAME_OVER_SCALE, 0 }, - { 0, 0, 1 }, -}; -static const vec2_t game_over_bg = { - .x = (GAME_OVER_WIDTH + 2) * GAME_OVER_SCALE, - .y = (GAME_OVER_HEIGHT + 2) * GAME_OVER_SCALE, -}; - static entity_t entities[MAX_ENTITIES]; static mat3_t transforms[MAX_ENTITIES]; static shape_t shapes[MAX_SHAPES]; @@ -530,12 +494,6 @@ void game_draw() shapes[i].connect); } - if (dead && !(counter & GAME_OVER_COUNTER_MASK)) { - renderer_clear_rect((vec2_t) { 0, 0 }, game_over_bg); - for (unsigned i = 0; i < NELEMS(game_over_verts); ++i) { - renderer_draw( - game_over_verts[i], game_over_lens[i], game_over_transform, - false); - } - } + if (dead && !(counter & COUNTER_MASK)) + text_draw("GAME OVER"); } diff --git a/text.c b/text.c new file mode 100644 index 0000000..cf87e51 --- /dev/null +++ b/text.c @@ -0,0 +1,117 @@ +#include "text.h" + +#include "renderer.h" + +#include + +#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) + +#define MAX_LINES 2 + +#define TEXT_HEIGHT 8 +#define TEXT_SCALE 0.025 +#define LETTER_WIDTH 3 +#define SPACE_WIDTH 1 + +typedef struct { + unsigned line_count; + unsigned line_lens[MAX_LINES]; + vec2_t lines[MAX_LINES][MAX_VERTS]; +} glyph_t; + +static const mat3_t text_transform = { + { TEXT_SCALE, 0, 0 }, + { 0, TEXT_SCALE, 0 }, + { 0, 0, 1 }, +}; + +static const glyph_t font[] = { + ['A'] = { + .line_count = 2, + .line_lens = { 3, 2 }, + .lines = { + { { -1, -4 }, { 0, 4 }, { 1, -4 } }, + { { -0.75, -2 }, { 0.75, -2 } }, + }, + }, + ['E'] = { + .line_count = 2, + .line_lens = { 4, 2 }, + .lines = { + { { 1, 4 }, { -1, 4 }, { -1, -4 }, { 1, -4 } }, + { { -1, -2 }, { 0, -2 } }, + }, + }, + ['G'] = { + .line_count = 1, + .line_lens = { 5 }, + .lines = { + { { 1, 4 }, { -1, 4 }, { -1, -4 }, { 1, -4 }, { 1, -2 } }, + }, + }, + ['M'] = { + .line_count = 1, + .line_lens = { 5 }, + .lines = { + { { -1, -4 }, { -1, 4 }, { 0, -4 }, { 1, 4 }, { 1, -4 } }, + }, + }, + ['O'] = { + .line_count = 1, + .line_lens = { 5 }, + .lines = { + { { -1, 4 }, { -1, -4 }, { 1, -4 }, { 1, 4 }, { -1, 4 } }, + }, + }, + ['R'] = { + .line_count = 1, + .line_lens = { 6 }, + .lines = { + { + { -1, -4 }, { -1, 4 }, { 1, 4 }, + { 1, -2 }, { -1, -2 }, { 1, -4 }, + }, + }, + }, + ['V'] = { + .line_count = 1, + .line_lens = { 3 }, + .lines = { + { { -1, 4 }, { 0, -4 }, { 1, 4 } }, + }, + }, +}; + +void text_draw(const char *s) +{ + int width = 0; + for (const char *p = s; *p != '\0'; ++p) + width += *p == ' ' ? SPACE_WIDTH : LETTER_WIDTH; + --width; + + const vec2_t bg_size = { + .x = TEXT_SCALE * (width + 2), + .y = TEXT_SCALE * (TEXT_HEIGHT + 2), + }; + renderer_clear_rect((vec2_t) { 0, 0 }, bg_size); + + int x = -width / 2 + 1; + for (const char *p = s; *p != '\0'; ++p) { + if (*p == ' ') { + x += SPACE_WIDTH; + } else { + const unsigned c = (unsigned)*p; + assert(c < NELEMS(font) && font[c].line_count != 0); + const glyph_t *g = font + c; + + const vec2_t t = { .x = x }; + const mat3_t m + = mat3_mul_mat3(text_transform, mat3_translation(t)); + + for (unsigned i = 0; i < g->line_count; ++i) + renderer_draw(g->lines[i], g->line_lens[i], m, false); + + x += LETTER_WIDTH; + } + } +} diff --git a/text.h b/text.h new file mode 100644 index 0000000..6f50f8e --- /dev/null +++ b/text.h @@ -0,0 +1,6 @@ +#ifndef TEXT_H +#define TEXT_H + +void text_draw(const char *s); + +#endif