blob: 9fe55b22d7a00b2dc20964d3d1fd8a67e8ac9b57 (
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
|
// TODO: For now we pack front/backbuffers together but this make it so that we
// can only use 2 backgrounds. Instead we can move the backbuffer to the end of
// the VRAM. This will give us 3 backgrounds but eats into the available memory
// for sprites but should be fine for non sprite intensive applications.
#define FRONTBUFFER ((u32*)(MEM_VRAM))
#define BACKBUFFER ((u32*)(MEM_VRAM + KB(96) - KB(20)))
// Adjust both of these if the location of the map changes. Each screnblock
// requires 2K.
#define FRONTBUFFER_TILEMAP ((u16*)(MEM_VRAM + KB(20)))
#define FRONTBUFFER_SCREENBLOCK 10
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);
BACKBUFFER[pos] = (BACKBUFFER[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 = FRONTBUFFER;
Tile *src = BACKBUFFER;
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;
}
}
void
renderer_init(void) {
// Initialize display mode and bg palette.
DISP_CTRL = DISP_MODE_0 | DISP_BG_0 | DISP_OBJ;
// Initialize backgrounds.
BG_CTRL(0) = BG_CHARBLOCK(0) | BG_SCREENBLOCK(FRONTBUFFER_SCREENBLOCK);
// TODO: Initialize other backgrounds if needed.
// Use DMA to clear front and back buffers.
dma_fill(FRONTBUFFER, 0, KB(20), 3);
dma_fill(BACKBUFFER, 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 (size_t i = 0; i < 32 * 20; ++i) {
FRONTBUFFER_TILEMAP[i] = i;
}
// // Load font data into VRAM.
// unpack_tiles(&bd_font, FONT_DATA, 256);
}
|