Files
asteroids/text.c

285 lines
5.3 KiB
C

#include "text.h"
#include "renderer.h"
#include <assert.h>
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
#define MAX_LINES 2
#define TEXT_HEIGHT 8
#define TEXT_SCALE 0.0125
#define LETTER_WIDTH 3
#define SPACE_WIDTH 1
#define MAX_SCORE_CHARS 4
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[] = {
['0'] = {
.line_count = 1,
.line_lens = { 5 },
.lines = {
{ { -1, 4 }, { -1, -4 }, { 1, -4 }, { 1, 4 }, { -1, 4 } },
},
},
['1'] = {
.line_count = 2,
.line_lens = { 3, 2 },
.lines = {
{ { -1, 4 }, { 0, 4 }, { 0, -4 } },
{ { -1, -4 }, { 1, -4 } },
},
},
['2'] = {
.line_count = 1,
.line_lens = { 6 },
.lines = {
{
{ -1, 4 }, { 1, 4 }, { 1, -2 },
{ -1, -2 }, { -1, -4 }, { 1, -4 },
},
},
},
['3'] = {
.line_count = 1,
.line_lens = { 6 },
.lines = {
{
{ -1, 4 }, { 1, 4 }, { 0, -2 },
{ 1, -2 }, { 1, -4 }, { -1, -4 },
},
},
},
['4'] = {
.line_count = 1,
.line_lens = { 4 },
.lines = {
{ { 1, -2 }, { -1, -2 }, { 1, 4 }, { 1, -4 } }
},
},
['5'] = {
.line_count = 1,
.line_lens = { 6 },
.lines = {
{
{ 1, 4 }, { -1, 4 }, { -1, -2 },
{ 1, -2 }, { 1, -4 }, { -1, -4 },
},
},
},
['6'] = {
.line_count = 1,
.line_lens = { 6 },
.lines = {
{
{ 1, 4 }, { -1, 4 }, { -1, -4 },
{ 1, -4 }, { 1, -2 }, { -1, -2 },
},
},
},
['7'] = {
.line_count = 1,
.line_lens = { 3 },
.lines = {
{ { -1, 4 }, { 1, 4 }, { 0, -4 } },
},
},
['8'] = {
.line_count = 2,
.line_lens = { 5, 2 },
.lines = {
{ { -1, 4 }, { -1, -4 }, { 1, -4 }, { 1, 4 }, { -1, 4 } },
{ { -1, -2 }, { 1, -2 } },
},
},
['9'] = {
.line_count = 1,
.line_lens = { 6 },
.lines = {
{
{ 1, -2 }, { -1, -2 }, { -1, 4 },
{ 1, 4 }, { 1, -4 }, { -1, -4 },
},
},
},
['A'] = {
.line_count = 2,
.line_lens = { 3, 2 },
.lines = {
{ { -1, -4 }, { 0, 4 }, { 1, -4 } },
{ { -0.75, -2 }, { 0.75, -2 } },
},
},
['C'] = {
.line_count = 1,
.line_lens = { 4 },
.lines = {
{ { 1, 4 }, { -1, 4 }, { -1, -4 }, { 1, -4 } },
},
},
['D'] = {
.line_count = 1,
.line_lens = { 5 },
.lines = {
{ { -1, 4 }, { -1, -4 }, { 1, -4 }, { 0, 4 }, { -1, 4 } },
},
},
['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 } },
},
},
['L'] = {
.line_count = 1,
.line_lens = { 3 },
.lines = {
{ { -1, 4 }, { -1, -4 }, { 1, -4 } },
},
},
['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 } },
},
},
['P'] = {
.line_count = 1,
.line_lens = { 5 },
.lines = {
{ { -1, -4 }, { -1, 4 }, { 1, 4 }, { 1, -2 }, { -1, -2 } },
},
},
['R'] = {
.line_count = 1,
.line_lens = { 6 },
.lines = {
{
{ -1, -4 }, { -1, 4 }, { 1, 4 },
{ 1, -2 }, { -1, -2 }, { 1, -4 },
},
},
},
['S'] = {
.line_count = 1,
.line_lens = { 6 },
.lines = {
{
{ 1, 4 }, { -1, 4 }, { -1, -2 },
{ 1, -2 }, { 1, -4 }, { -1, -4 },
},
},
},
['U'] = {
.line_count = 1,
.line_lens = { 4 },
.lines = {
{ { -1, 4 }, { -1, -4 }, { 1, -4 }, { 1, 4 } },
},
},
['V'] = {
.line_count = 1,
.line_lens = { 3 },
.lines = {
{ { -1, 4 }, { 0, -4 }, { 1, 4 } },
},
},
};
static void draw_glyph(unsigned c, vec2_t pos)
{
assert(c < NELEMS(font) && font[c].line_count != 0);
const glyph_t *g = font + c;
const mat3_t m = mat3_mul_mat3(mat3_translation(pos), text_transform);
for (unsigned i = 0; i < g->line_count; ++i)
renderer_draw(g->lines[i], g->line_lens[i], m, false);
}
static void draw_text(const char *s, vec2_t pos)
{
for (const char *p = s; *p != '\0'; ++p) {
if (*p == ' ') {
pos.x += TEXT_SCALE * SPACE_WIDTH;
} else {
draw_glyph((unsigned)*p, pos);
pos.x += TEXT_SCALE * LETTER_WIDTH;
}
}
}
void text_draw_centre(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);
const vec2_t pos = { TEXT_SCALE * (-width / 2.0f + 1), 0 };
draw_text(s, pos);
}
void text_draw_score(unsigned score)
{
char buf[MAX_SCORE_CHARS + 1];
buf[MAX_SCORE_CHARS] = '\0';
for (unsigned i = 0; i < MAX_SCORE_CHARS; ++i) {
const unsigned v = score % 10;
score /= 10;
buf[MAX_SCORE_CHARS - 1 - i] = '0' + v;
}
const int width = LETTER_WIDTH * MAX_SCORE_CHARS - 1;
const vec2_t bg_centre = {
.x = TEXT_SCALE * (width / 2.0f + 2) - aspect,
.y = 1.0f - TEXT_SCALE * (TEXT_HEIGHT / 2.0f + 2),
};
const vec2_t bg_size = {
.x = TEXT_SCALE * (width + 2),
.y = TEXT_SCALE * (TEXT_HEIGHT + 2),
};
renderer_clear_rect(bg_centre, bg_size);
const vec2_t text_pos = {
.x = TEXT_SCALE * 3 - aspect,
.y = bg_centre.y,
};
draw_text(buf, text_pos);
}