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
|
#include "bd-font.c"
// The frontbuffer is located at the beginning of the VRAM, and requires 20KB of
// video memory for 32 * 20 tiles at 4bpp.
#define FRONTBUF ((u32*)(MEM_VRAM))
// Adjust both of these if the location of the map changes. Each screnblock
// requires less than 2KB.
#define FRONTBUF_TILEMAP ((u16*)(MEM_VRAM + KB(20)))
#define FRONTBUF_SB 10
// The backbuffer is located at the end of the VRAM. This can allow us to use
// more backgrounds but eats into the available memory for sprites. This should
// be fine for non sprite intensive applications. If more sprite memory is
// needed, the backbuffer can be located at the end of the background memory
// instead (64KB - 20KB).
#define BACKBUF ((u32*)(MEM_VRAM + KB(96) - KB(20)))
// The font data is located at the end of the frontbuffer memory, after the tile
// map and requires 8KB for 256 8x8 characters at 4bpp. This, along with the
// tilemap information allow us to store the frontbuffer and font for a text
// background in the first 2 charblocks (32KB).
#define FONT_DATA ((u32*)(MEM_VRAM + KB(22)))
#define FONT_TILEMAP ((u16*)(MEM_VRAM + KB(30)))
#define FONT_SB 15
static u32 dirty_tiles[21] = {0};
// TODO: Allow disable bound checking at compile time.
#define BOUNDCHECK_SCREEN() if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return;
IWRAM_CODE
void
draw_pixel(u16 x, u16 y, u8 color) {
BOUNDCHECK_SCREEN();
// Find row position for the given x/y coordinates.
size_t tile_x = x / 8;
size_t tile_y = y / 8;
size_t start_col = x % 8;
size_t start_row = y % 8;
size_t pos = start_row + (tile_x + tile_y * 32) * 8;
// Update backbuffer.
size_t shift = start_col * sizeof(u32);
BACKBUF[pos] = (BACKBUF[pos] & ~(0xF << shift)) | color << shift;
// Mark tile as dirty.
dirty_tiles[tile_y] |= 1 << tile_x;
}
IWRAM_CODE
void
flip_buffer(void) {
// Copy dirty tiles from the backbuffer to the frontbuffer.
Tile *dst = FRONTBUF;
Tile *src = BACKBUF;
for (size_t j = 0; j < 20; ++j) {
if (dirty_tiles[j] == 0) {
continue;
}
for (size_t i = 0, k = 1; i < 30; ++i, k <<= 1) {
if (dirty_tiles[j] & k) {
dst[i + j * 32] = src[i + j * 32];
}
}
dirty_tiles[j] = 0;
}
}
static u16 font_map[256] = {0};
void
renderer_init(void) {
// Initialize display mode and bg palette.
DISP_CTRL = DISP_MODE_0 | DISP_BG_0 | DISP_BG_1 | DISP_OBJ;
// Initialize backgrounds.
BG_CTRL(0) = BG_CHARBLOCK(0) | BG_SCREENBLOCK(FRONTBUF_SB) | BG_PRIORITY(1);
BG_CTRL(1) = BG_CHARBLOCK(1) | BG_SCREENBLOCK(FONT_SB) | BG_PRIORITY(0);
// Use DMA to clear front and back buffers as well as the font memory map.
dma_fill(FRONTBUF, 0, KB(20), 3);
dma_fill(FRONTBUF_TILEMAP, 0, KB(2), 3);
dma_fill(FONT_DATA, 0, KB(8), 3);
dma_fill(FONT_TILEMAP, 0, KB(2), 3);
dma_fill(BACKBUF, 0, KB(20), 3);
// Initialize default palette.
PAL_BUFFER_BG[0] = COLOR_BLACK;
PAL_BUFFER_BG[1] = COLOR_WHITE;
PAL_BUFFER_BG[2] = COLOR_RED;
PAL_BUFFER_BG[3] = COLOR_BLUE;
PAL_BUFFER_BG[4] = COLOR_CYAN;
PAL_BUFFER_BG[5] = COLOR_GREY;
// Initialize background memory map for frontbuffer and font backgorund.
for (size_t i = 0; i < 32 * 20; ++i) {
FRONTBUF_TILEMAP[i] = i;
}
// 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) {
font_map[i] = 192 + i;
}
}
|