aboutsummaryrefslogtreecommitdiffstats
path: root/src/text/text.h
blob: 0bcf090550d07ca6c3a5c16d1d4cbe65235b112d (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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#ifndef TEXT_H
#define TEXT_H

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

#include "font.h"

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};

// Initializes the text engine.
static inline
void
txt_init(u32 *font_data, u16 *font_tilemap, u16 font_offset) {
    // Load font data into VRAM.
    unpack_tiles(&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;
}

// Writes a message to the tile text background.
static inline
void
txt_puts(char *msg) {
    while (*msg) {
        char c = *msg++;
        if (c == '\0') {
            continue;
        }
        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;
        }
    }
}

// Clears the current line on the tile text mode.
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;
}

// Clears the screen on the tile text mode.
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;
}

// Moves the tile mode cursor to the specified position.
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, u8 clr) {
    while (*msg) {
        char c = *msg++;
        Tile *tile = FONT_DATA;
        tile += c;
        draw_tile(x, y, tile, clr, true);
        x += spacing;
    }
}

static inline
void
txt_drawc(char c, size_t x, size_t y, size_t spacing, u8 clr) {
    Tile *tile = FONT_DATA;
    tile += c;
    draw_tile(x, y, tile, clr, 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); \
	}

// Draws text to the screen with formatting starting on the x and y position and
// with custom character spacing.
#define txt_drawf(msg, x, y, s, c, ...) \
	{ \
		char buf[256] = {0}; \
		posprintf(buf, msg, ##__VA_ARGS__); \
		txt_draws(buf, x, y, s, c); \
	}

// Small font is located after the initial ASCII characters, and only supports
// lowercase characters.
// NOTE: Slow, we should do this with a LUT.
#define txt_drawf_small(msg, x, y, s, c, ...) \
	{ \
		char buf[256] = {0}; \
		posprintf(buf, msg, ##__VA_ARGS__); \
		for (size_t i = 0; i < 256; i++) { \
		    if (buf[i] == 0) { \
		        break; \
		    } \
		    if (buf[i] < 'a') { \
                buf[i] += 16 * 6; \
		    } else { \
                buf[i] += 16 * 4; \
		    }\
		} \
		txt_draws(buf, x, y, s, c); \
	}

#endif // TEXT_H