aboutsummaryrefslogtreecommitdiffstats
path: root/src/text/text.h
blob: 630f04f1cebcd6fe03d09f543e15f4571d432d82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#ifndef TEXT_H
#define TEXT_H

#include "posprintf.h"
#include "renderer.h"

#include "bd-font.c"

typedef struct TextEngine {
    // Cursor for tiled text mode The X and Y positions correspond to the tile
    // X and Y starting from the top left of the screen. For a 240x160 screen,
    // we have 30x20 tiles available.
    size_t cursor_x;
    size_t cursor_y;

    // Memory location of font tile data and tilemap. Likely located on the
    // VRAM.
    u32 *font_data;
    u16 *font_tilemap;

    // The font map for tiled text. Writing the character stored in this
    // position on the tilemap will show a character on the screen.
    u16 font_map[256];
} TextEngine;

static TextEngine text_engine = {0};

static inline
void
txt_init(u32 *font_data, u16 *font_tilemap, u16 font_offset) {
    // Load font data into VRAM.
    unpack_tiles(&bd_font, font_data, 256);

    // Initialize the font map translation table. That way we can write
    // a character on the text background layer with:
    //     FONT_TILEMAP[tile_x + 32 * tile_y] = font_map['A'];
    for (size_t i = 0; i < 256; ++i) {
        text_engine.font_map[i] = font_offset + i;
    }

    // Initialize remaining variables.
    text_engine.font_data = font_data;
    text_engine.font_tilemap = font_tilemap;
}

static inline
void
txt_putc(char c) {
    if (c == '\0') {
        return;
    }
    if (c == '\n') {
        text_engine.cursor_x = 0;
        text_engine.cursor_y++;
    } else {
        int x = text_engine.cursor_x;
        int y = text_engine.cursor_y;
        text_engine.font_tilemap[x + 32 * y] = text_engine.font_map[(u16)c];
        text_engine.cursor_x += 1;
        if (text_engine.cursor_x >= 30) {
            text_engine.cursor_x = 0;
            text_engine.cursor_y++;
        }
    }
    if (text_engine.cursor_y >= 20) {
        text_engine.cursor_y = 0;
    }
}

static inline
void
txt_puts(char *msg) {
    while (*msg) {
        txt_putc(*msg++);
    }
}

static inline
void
txt_clear_line(void) {
    for (size_t i = 0; i < 30; ++i) {
        int x = text_engine.cursor_x;
        int y = text_engine.cursor_y;
        text_engine.font_tilemap[x + 32 * y] = text_engine.font_map[0];
    }
    text_engine.cursor_x = 0;
}

static inline
void
txt_clear_screen(void) {
    for (size_t j = 0; j < 20; ++j) {
        text_engine.cursor_y = j;
        txt_clear_line();
    }
    text_engine.cursor_x = 0;
    text_engine.cursor_y = 0;
}

static inline
void
txt_position(size_t tile_x, size_t tile_y) {
    text_engine.cursor_x = tile_x;
    text_engine.cursor_y = tile_y;
}

// Draws a message where the first character's top-left corner begins at the
// given x and y position. The character spacing can be adjusted, but beware of
// color merging issues.
static inline
void
txt_draws(char *msg, size_t x, size_t y, size_t spacing) {
    while (*msg) {
        char c = *msg++;
        Tile *tile = FONT_DATA;
        tile += c;
        draw_tile(x, y, tile, true);
        x += spacing;
    }
}

// Print text to the screen with formatting.
#define txt_printf(msg, ...) \
	{ \
		char buf[256] = {0}; \
		posprintf(buf, msg, ##__VA_ARGS__); \
		txt_puts(buf); \
	}

#define txt_drawf(msg, x, y, s, ...) \
	{ \
		char buf[256] = {0}; \
		posprintf(buf, msg, ##__VA_ARGS__); \
		txt_draws(buf, x, y, s); \
	}

#endif // TEXT_H