diff options
Diffstat (limited to 'src/ppu.c')
-rw-r--r-- | src/ppu.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/src/ppu.c b/src/ppu.c new file mode 100644 index 0000000..f626604 --- /dev/null +++ b/src/ppu.c | |||
@@ -0,0 +1,418 @@ | |||
1 | #include "ppu.h" | ||
2 | #include "bd-font.c" | ||
3 | |||
4 | /* | ||
5 | Copyright (c) 2021 Devine Lu Linvega | ||
6 | Copyright (c) 2021 Andrew Alderwick | ||
7 | Copyright (c) 2021 Adrian "asie" Siekierka | ||
8 | Copyright (c) 2021 Bad Diode | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software for any | ||
11 | purpose with or without fee is hereby granted, provided that the above | ||
12 | copyright notice and this permission notice appear in all copies. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
15 | WITH REGARD TO THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #define FG_FRONT ((u32*)(MEM_VRAM)) | ||
19 | #define BG_FRONT ((u32*)(MEM_VRAM + KB(20))) | ||
20 | #define FG_BACK ((u32*)(MEM_VRAM + KB(44))) | ||
21 | #define BG_BACK ((u32*)(MEM_VRAM + KB(64))) | ||
22 | #define TILE_MAP ((u32*)(MEM_VRAM + KB(40))) | ||
23 | #define FONT_DATA ((u32*)(MEM_VRAM + KB(84))) | ||
24 | |||
25 | // Keyboard. | ||
26 | #define SPRITE_START_IDX 640 | ||
27 | |||
28 | static u32 unpack_icon_lut[256] = { | ||
29 | 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, | ||
30 | 0x00000101, 0x00000110, 0x00000111, 0x00001000, 0x00001001, | ||
31 | 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, | ||
32 | 0x00001111, 0x00010000, 0x00010001, 0x00010010, 0x00010011, | ||
33 | 0x00010100, 0x00010101, 0x00010110, 0x00010111, 0x00011000, | ||
34 | 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, | ||
35 | 0x00011110, 0x00011111, 0x00100000, 0x00100001, 0x00100010, | ||
36 | 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111, | ||
37 | 0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, | ||
38 | 0x00101101, 0x00101110, 0x00101111, 0x00110000, 0x00110001, | ||
39 | 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, | ||
40 | 0x00110111, 0x00111000, 0x00111001, 0x00111010, 0x00111011, | ||
41 | 0x00111100, 0x00111101, 0x00111110, 0x00111111, 0x01000000, | ||
42 | 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, | ||
43 | 0x01000110, 0x01000111, 0x01001000, 0x01001001, 0x01001010, | ||
44 | 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111, | ||
45 | 0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, | ||
46 | 0x01010101, 0x01010110, 0x01010111, 0x01011000, 0x01011001, | ||
47 | 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, | ||
48 | 0x01011111, 0x01100000, 0x01100001, 0x01100010, 0x01100011, | ||
49 | 0x01100100, 0x01100101, 0x01100110, 0x01100111, 0x01101000, | ||
50 | 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, | ||
51 | 0x01101110, 0x01101111, 0x01110000, 0x01110001, 0x01110010, | ||
52 | 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111, | ||
53 | 0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, | ||
54 | 0x01111101, 0x01111110, 0x01111111, 0x10000000, 0x10000001, | ||
55 | 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, | ||
56 | 0x10000111, 0x10001000, 0x10001001, 0x10001010, 0x10001011, | ||
57 | 0x10001100, 0x10001101, 0x10001110, 0x10001111, 0x10010000, | ||
58 | 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, | ||
59 | 0x10010110, 0x10010111, 0x10011000, 0x10011001, 0x10011010, | ||
60 | 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111, | ||
61 | 0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, | ||
62 | 0x10100101, 0x10100110, 0x10100111, 0x10101000, 0x10101001, | ||
63 | 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, | ||
64 | 0x10101111, 0x10110000, 0x10110001, 0x10110010, 0x10110011, | ||
65 | 0x10110100, 0x10110101, 0x10110110, 0x10110111, 0x10111000, | ||
66 | 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, | ||
67 | 0x10111110, 0x10111111, 0x11000000, 0x11000001, 0x11000010, | ||
68 | 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111, | ||
69 | 0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, | ||
70 | 0x11001101, 0x11001110, 0x11001111, 0x11010000, 0x11010001, | ||
71 | 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, | ||
72 | 0x11010111, 0x11011000, 0x11011001, 0x11011010, 0x11011011, | ||
73 | 0x11011100, 0x11011101, 0x11011110, 0x11011111, 0x11100000, | ||
74 | 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, | ||
75 | 0x11100110, 0x11100111, 0x11101000, 0x11101001, 0x11101010, | ||
76 | 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111, | ||
77 | 0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, | ||
78 | 0x11110101, 0x11110110, 0x11110111, 0x11111000, 0x11111001, | ||
79 | 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, | ||
80 | 0x11111111 | ||
81 | }; | ||
82 | |||
83 | static u32 unpack_icon_lut_flipx[256] = { | ||
84 | 0x00000000, 0x10000000, 0x01000000, 0x11000000, 0x00100000, | ||
85 | 0x10100000, 0x01100000, 0x11100000, 0x00010000, 0x10010000, | ||
86 | 0x01010000, 0x11010000, 0x00110000, 0x10110000, 0x01110000, | ||
87 | 0x11110000, 0x00001000, 0x10001000, 0x01001000, 0x11001000, | ||
88 | 0x00101000, 0x10101000, 0x01101000, 0x11101000, 0x00011000, | ||
89 | 0x10011000, 0x01011000, 0x11011000, 0x00111000, 0x10111000, | ||
90 | 0x01111000, 0x11111000, 0x00000100, 0x10000100, 0x01000100, | ||
91 | 0x11000100, 0x00100100, 0x10100100, 0x01100100, 0x11100100, | ||
92 | 0x00010100, 0x10010100, 0x01010100, 0x11010100, 0x00110100, | ||
93 | 0x10110100, 0x01110100, 0x11110100, 0x00001100, 0x10001100, | ||
94 | 0x01001100, 0x11001100, 0x00101100, 0x10101100, 0x01101100, | ||
95 | 0x11101100, 0x00011100, 0x10011100, 0x01011100, 0x11011100, | ||
96 | 0x00111100, 0x10111100, 0x01111100, 0x11111100, 0x00000010, | ||
97 | 0x10000010, 0x01000010, 0x11000010, 0x00100010, 0x10100010, | ||
98 | 0x01100010, 0x11100010, 0x00010010, 0x10010010, 0x01010010, | ||
99 | 0x11010010, 0x00110010, 0x10110010, 0x01110010, 0x11110010, | ||
100 | 0x00001010, 0x10001010, 0x01001010, 0x11001010, 0x00101010, | ||
101 | 0x10101010, 0x01101010, 0x11101010, 0x00011010, 0x10011010, | ||
102 | 0x01011010, 0x11011010, 0x00111010, 0x10111010, 0x01111010, | ||
103 | 0x11111010, 0x00000110, 0x10000110, 0x01000110, 0x11000110, | ||
104 | 0x00100110, 0x10100110, 0x01100110, 0x11100110, 0x00010110, | ||
105 | 0x10010110, 0x01010110, 0x11010110, 0x00110110, 0x10110110, | ||
106 | 0x01110110, 0x11110110, 0x00001110, 0x10001110, 0x01001110, | ||
107 | 0x11001110, 0x00101110, 0x10101110, 0x01101110, 0x11101110, | ||
108 | 0x00011110, 0x10011110, 0x01011110, 0x11011110, 0x00111110, | ||
109 | 0x10111110, 0x01111110, 0x11111110, 0x00000001, 0x10000001, | ||
110 | 0x01000001, 0x11000001, 0x00100001, 0x10100001, 0x01100001, | ||
111 | 0x11100001, 0x00010001, 0x10010001, 0x01010001, 0x11010001, | ||
112 | 0x00110001, 0x10110001, 0x01110001, 0x11110001, 0x00001001, | ||
113 | 0x10001001, 0x01001001, 0x11001001, 0x00101001, 0x10101001, | ||
114 | 0x01101001, 0x11101001, 0x00011001, 0x10011001, 0x01011001, | ||
115 | 0x11011001, 0x00111001, 0x10111001, 0x01111001, 0x11111001, | ||
116 | 0x00000101, 0x10000101, 0x01000101, 0x11000101, 0x00100101, | ||
117 | 0x10100101, 0x01100101, 0x11100101, 0x00010101, 0x10010101, | ||
118 | 0x01010101, 0x11010101, 0x00110101, 0x10110101, 0x01110101, | ||
119 | 0x11110101, 0x00001101, 0x10001101, 0x01001101, 0x11001101, | ||
120 | 0x00101101, 0x10101101, 0x01101101, 0x11101101, 0x00011101, | ||
121 | 0x10011101, 0x01011101, 0x11011101, 0x00111101, 0x10111101, | ||
122 | 0x01111101, 0x11111101, 0x00000011, 0x10000011, 0x01000011, | ||
123 | 0x11000011, 0x00100011, 0x10100011, 0x01100011, 0x11100011, | ||
124 | 0x00010011, 0x10010011, 0x01010011, 0x11010011, 0x00110011, | ||
125 | 0x10110011, 0x01110011, 0x11110011, 0x00001011, 0x10001011, | ||
126 | 0x01001011, 0x11001011, 0x00101011, 0x10101011, 0x01101011, | ||
127 | 0x11101011, 0x00011011, 0x10011011, 0x01011011, 0x11011011, | ||
128 | 0x00111011, 0x10111011, 0x01111011, 0x11111011, 0x00000111, | ||
129 | 0x10000111, 0x01000111, 0x11000111, 0x00100111, 0x10100111, | ||
130 | 0x01100111, 0x11100111, 0x00010111, 0x10010111, 0x01010111, | ||
131 | 0x11010111, 0x00110111, 0x10110111, 0x01110111, 0x11110111, | ||
132 | 0x00001111, 0x10001111, 0x01001111, 0x11001111, 0x00101111, | ||
133 | 0x10101111, 0x01101111, 0x11101111, 0x00011111, 0x10011111, | ||
134 | 0x01011111, 0x11011111, 0x00111111, 0x10111111, 0x01111111, | ||
135 | 0x11111111 | ||
136 | }; | ||
137 | |||
138 | static u32 dirty_tiles[21] = {0}; | ||
139 | |||
140 | void | ||
141 | putcolors(u8 *addr) { | ||
142 | int i; | ||
143 | for(i = 0; i < 4; ++i) { | ||
144 | u8 | ||
145 | r = (*(addr + i / 2) >> (!(i % 2) << 2)) & 0x0f, | ||
146 | g = (*(addr + 2 + i / 2) >> (!(i % 2) << 2)) & 0x0f, | ||
147 | b = (*(addr + 4 + i / 2) >> (!(i % 2) << 2)) & 0x0f; | ||
148 | PAL_BUFFER_BG[i] = rgb15( | ||
149 | (r << 1) | (r >> 3), | ||
150 | (g << 1) | (g >> 3), | ||
151 | (b << 1) | (b >> 3)); | ||
152 | for (size_t j = 0; j < 16; ++j) { | ||
153 | PAL_BUFFER_SPRITES[i * 16 + j] = rgb15( | ||
154 | (r << 1) | (r >> 3), | ||
155 | (g << 1) | (g >> 3), | ||
156 | (b << 1) | (b >> 3)); | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | IWRAM_CODE | ||
162 | void | ||
163 | putpixel(u32 *layer, u16 x, u16 y, u8 color) { | ||
164 | if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; | ||
165 | size_t tile_x = x / 8; | ||
166 | size_t tile_y = y / 8; | ||
167 | size_t start_col = x % 8; | ||
168 | size_t start_row = y % 8; | ||
169 | size_t pos = (start_row + ((tile_x + tile_y * 32) * 8)); | ||
170 | size_t shift = start_col * 4; | ||
171 | layer[pos] = (layer[pos] & (~(0xF << shift))) | (color << shift); | ||
172 | dirty_tiles[tile_y] |= 1 << tile_x; | ||
173 | } | ||
174 | |||
175 | IWRAM_CODE | ||
176 | void | ||
177 | puticn(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy) { | ||
178 | u8 sprline; | ||
179 | u16 v; | ||
180 | u32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3)); | ||
181 | |||
182 | u32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8)); | ||
183 | u32 *layerptr = &layer[layerpos]; | ||
184 | u32 shift = (x & 7) << 2; | ||
185 | u32 *lut_expand = flipx ? unpack_icon_lut : unpack_icon_lut_flipx; | ||
186 | |||
187 | if (flipy) flipy = 7; | ||
188 | |||
189 | if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; | ||
190 | |||
191 | if (color != 0x05 && color != 0x0a && color != 0x0f) { | ||
192 | u64 mask = ~((u64)0xFFFFFFFF << shift); | ||
193 | |||
194 | for (v = 0; v < 8; v++, layerptr++) { | ||
195 | if ((y + v) >= SCREEN_HEIGHT) break; | ||
196 | |||
197 | sprline = sprite[v ^ flipy]; | ||
198 | u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift; | ||
199 | data |= (u64)(lut_expand[sprline ^ 0xFF] * (color >> 2)) << shift; | ||
200 | |||
201 | layerptr[0] = (layerptr[0] & mask) | data; | ||
202 | layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); | ||
203 | |||
204 | if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; | ||
205 | } | ||
206 | } else { | ||
207 | for (v = 0; v < 8; v++, layerptr++) { | ||
208 | if ((y + v) >= SCREEN_HEIGHT) break; | ||
209 | |||
210 | sprline = sprite[v ^ flipy]; | ||
211 | u64 mask = ~((u64)(lut_expand[sprline] * 0xF) << shift); | ||
212 | u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift; | ||
213 | |||
214 | layerptr[0] = (layerptr[0] & mask) | data; | ||
215 | layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); | ||
216 | |||
217 | if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | dirty_tiles[y >> 3] |= dirtyflag; | ||
222 | dirty_tiles[(y + 7) >> 3] |= dirtyflag; | ||
223 | } | ||
224 | |||
225 | IWRAM_CODE | ||
226 | void | ||
227 | putfontchar(u32 *layer, u16 tile_x, u16 tile_y, u8 ch, u8 color) { | ||
228 | u32 pos = (tile_x + tile_y * 32) * 8; | ||
229 | u32 *tile_data = &layer[pos]; | ||
230 | u32 *font_data = &FONT_DATA[8 * ch]; | ||
231 | for (size_t i = 0; i < 8; ++i) { | ||
232 | tile_data[i] = font_data[i] * color; | ||
233 | } | ||
234 | dirty_tiles[tile_y] |= 1 << tile_x; | ||
235 | } | ||
236 | |||
237 | IWRAM_CODE | ||
238 | void | ||
239 | putchr(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, | ||
240 | u8 flipx, u8 flipy) { | ||
241 | u8 sprline1, sprline2; | ||
242 | u16 v; | ||
243 | u32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3)); | ||
244 | |||
245 | u32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8)); | ||
246 | u32 *layerptr = &layer[layerpos]; | ||
247 | u32 shift = (x & 7) << 2; | ||
248 | u32 *lut_expand = flipx ? unpack_icon_lut : unpack_icon_lut_flipx; | ||
249 | |||
250 | if (flipy) flipy = 7; | ||
251 | |||
252 | if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; | ||
253 | |||
254 | u64 mask = ~((u64)0xFFFFFFFF << shift); | ||
255 | u32 colconst = (color >> 2) * 0x11111111; | ||
256 | |||
257 | for (v = 0; v < 8; v++, layerptr++) { | ||
258 | if ((y + v) >= SCREEN_HEIGHT) break; | ||
259 | |||
260 | sprline1 = sprite[v ^ flipy]; | ||
261 | sprline2 = sprite[(v ^ flipy) | 8]; | ||
262 | |||
263 | u32 data32 = | ||
264 | (lut_expand[sprline1] * (color & 3)) | ||
265 | + (lut_expand[sprline2] * ((color & 1) << 1)) | ||
266 | + colconst; | ||
267 | u64 data = ((u64) (data32 & 0x33333333)) << shift; | ||
268 | |||
269 | layerptr[0] = (layerptr[0] & mask) | data; | ||
270 | layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); | ||
271 | |||
272 | if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; | ||
273 | } | ||
274 | |||
275 | dirty_tiles[y >> 3] |= dirtyflag; | ||
276 | dirty_tiles[(y + 7) >> 3] |= dirtyflag; | ||
277 | } | ||
278 | |||
279 | IWRAM_CODE | ||
280 | void | ||
281 | flipbuf(Ppu *p) { | ||
282 | Tile *mem_fg = FG_FRONT; | ||
283 | Tile *mem_bg = BG_FRONT; | ||
284 | for (size_t j = 0; j < 20; ++j) { | ||
285 | if (dirty_tiles[j] == 0) { | ||
286 | continue; | ||
287 | } | ||
288 | |||
289 | size_t k = 1; | ||
290 | for (size_t i = 0; i < 30; ++i, k <<= 1) { | ||
291 | if (dirty_tiles[j] & k) { | ||
292 | Tile *tile_fg = p->fg; | ||
293 | Tile *tile_bg = p->bg; | ||
294 | mem_fg[i + j * 32] = tile_fg[i + j * 32]; | ||
295 | mem_bg[i + j * 32] = tile_bg[i + j * 32]; | ||
296 | } | ||
297 | } | ||
298 | dirty_tiles[j] = 0; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | typedef struct KeyboardChar { | ||
303 | int x; | ||
304 | int y; | ||
305 | u8 symbol; | ||
306 | } KeyboardChar; | ||
307 | |||
308 | static u8 cursor_position = 0; | ||
309 | |||
310 | #define KEYBOARD_ROW_SIZE 12 | ||
311 | #define KEYBOARD_START_TILE_X (30 / 2 - KEYBOARD_ROW_SIZE / 2) | ||
312 | #define KEYBOARD_START_TILE_Y (20 / 2 - 3) | ||
313 | |||
314 | KeyboardChar keyboard[] = { | ||
315 | {0, 0, '!'}, {0, 0, '?'}, {0, 0, '@'}, {0, 0, '#'}, {0, 0, '$'}, {0, 0, '%'}, {0, 0, '^'}, {0, 0, '&'}, {0, 0, '*'}, {0, 0, '"'}, {0, 0, '\''}, {0, 0, 0x7f}, | ||
316 | {0, 0, '('}, {0, 0, ')'}, {0, 0, '['}, {0, 0, ']'}, {0, 0, '{'}, {0, 0, '}'}, {0, 0, '<'}, {0, 0, '>'}, {0, 0, '+'}, {0, 0, '-'}, {0, 0, '='}, {0, 0, 0x14}, | ||
317 | {0, 0, '0'}, {0, 0, '1'}, {0, 0, '2'}, {0, 0, '3'}, {0, 0, '4'}, {0, 0, '5'}, {0, 0, '6'}, {0, 0, '7'}, {0, 0, '8'}, {0, 0, '9'}, {0, 0, '~'}, {0, 0, 0x18}, | ||
318 | {0, 0, 'a'}, {0, 0, 'b'}, {0, 0, 'c'}, {0, 0, 'd'}, {0, 0, 'e'}, {0, 0, 'f'}, {0, 0, 'g'}, {0, 0, 'h'}, {0, 0, 'i'}, {0, 0, 'j'}, {0, 0, '/'}, {0, 0, 0x19}, | ||
319 | {0, 0, 'k'}, {0, 0, 'l'}, {0, 0, 'm'}, {0, 0, 'n'}, {0, 0, 'o'}, {0, 0, 'p'}, {0, 0, 'q'}, {0, 0, 'r'}, {0, 0, 's'}, {0, 0, 't'}, {0, 0, '\\'}, {0, 0, 0x1b}, | ||
320 | {0, 0, 'u'}, {0, 0, 'v'}, {0, 0, 'w'}, {0, 0, 'x'}, {0, 0, 'y'}, {0, 0, 'z'}, {0, 0, ','}, {0, 0, '.'}, {0, 0, ';'}, {0, 0, ':'}, {0, 0, '_'}, {0, 0, 0x1a}, | ||
321 | }; | ||
322 | |||
323 | void | ||
324 | toggle_keyboard(void) { | ||
325 | for (size_t i = 0; i < LEN(keyboard); ++i) { | ||
326 | OBJ_ATTR_0(i) ^= OBJ_HIDDEN; | ||
327 | } | ||
328 | OBJ_ATTR_0(127) ^= OBJ_HIDDEN; | ||
329 | } | ||
330 | |||
331 | void | ||
332 | update_cursor(u8 pos) { | ||
333 | cursor_position = CLAMP(pos, 0, LEN(keyboard) - 1); | ||
334 | OBJ_ATTR_0(127) = (OBJ_ATTR_0(127) & ~0xFF) | ||
335 | | OBJ_Y_COORD(keyboard[cursor_position].y); | ||
336 | OBJ_ATTR_1(127) = (OBJ_ATTR_0(127) & ~0x1FF) | ||
337 | | OBJ_X_COORD(keyboard[cursor_position].x); | ||
338 | } | ||
339 | |||
340 | int | ||
341 | initppu(Ppu *p, u8 hor, u8 ver, u8 pad) { | ||
342 | p->hor = hor; | ||
343 | p->ver = ver; | ||
344 | p->pad = pad; | ||
345 | p->width = (8 * p->hor + p->pad * 2); | ||
346 | p->height = (8 * p->ver + p->pad * 2); | ||
347 | |||
348 | // Initialize display mode and bg palette. | ||
349 | DISP_CTRL = DISP_MODE_0 | DISP_BG_0 | DISP_BG_1 | DISP_OBJ; | ||
350 | |||
351 | // Initialize backgrounds. | ||
352 | u8 cb_fg = 0; | ||
353 | u8 cb_bg = 1; | ||
354 | u8 sb_fg = 20; | ||
355 | u8 sb_bg = 21; | ||
356 | BG_CTRL(0) = BG_CHARBLOCK(cb_fg) | BG_SCREENBLOCK(sb_fg) | BG_PRIORITY(1); | ||
357 | BG_CTRL(1) = BG_CHARBLOCK(cb_bg) | BG_SCREENBLOCK(sb_bg) | BG_PRIORITY(2); | ||
358 | |||
359 | // Clear front buffer. | ||
360 | p->fg = FG_FRONT; | ||
361 | p->bg = BG_FRONT; | ||
362 | |||
363 | // Use DMA to clear VRAM. | ||
364 | u32 fill = 0; | ||
365 | dma_fill(p->fg, fill, KB(20), 3); | ||
366 | dma_fill(p->bg, fill, KB(20), 3); | ||
367 | |||
368 | // Clear back buffer. | ||
369 | p->fg = FG_BACK; | ||
370 | p->bg = BG_BACK; | ||
371 | dma_fill(p->fg, fill, KB(20), 3); | ||
372 | dma_fill(p->bg, fill, KB(20), 3); | ||
373 | |||
374 | // Initialize default palette. | ||
375 | PAL_BUFFER_BG[0] = COLOR_BLACK; | ||
376 | PAL_BUFFER_BG[1] = COLOR_WHITE; | ||
377 | PAL_BUFFER_BG[2] = COLOR_RED; | ||
378 | PAL_BUFFER_BG[3] = COLOR_BLUE; | ||
379 | for (size_t i = 0; i < 16; ++i) { | ||
380 | PAL_BUFFER_SPRITES[i] = COLOR_BLACK; | ||
381 | PAL_BUFFER_SPRITES[1 * 16] = COLOR_WHITE; | ||
382 | PAL_BUFFER_SPRITES[2 * 16] = COLOR_RED; | ||
383 | PAL_BUFFER_SPRITES[3 * 16] = COLOR_BLUE; | ||
384 | } | ||
385 | |||
386 | // Initialize background memory map. | ||
387 | u16 *mem_map_fg = SCREENBLOCK_MEM[sb_fg]; | ||
388 | u16 *mem_map_bg = SCREENBLOCK_MEM[sb_bg]; | ||
389 | size_t k = 0; | ||
390 | for (size_t i = 0; i < 32 * 20; ++i, ++k) { | ||
391 | mem_map_fg[i] = k; | ||
392 | mem_map_bg[i] = k + 32 * 4; | ||
393 | } | ||
394 | |||
395 | // Load font data into VRAM. | ||
396 | unpack_tiles(&bd_font, FONT_DATA, 256); | ||
397 | |||
398 | // Initialize keyboard sprites. | ||
399 | int tile_x = KEYBOARD_START_TILE_X; | ||
400 | int tile_y = KEYBOARD_START_TILE_Y; | ||
401 | for (size_t i = 0; i < sizeof(keyboard) / sizeof(keyboard[0]); ++i) { | ||
402 | keyboard[i].x = tile_x * 8; | ||
403 | keyboard[i].y = tile_y * 8; | ||
404 | OBJ_ATTR_0(i) = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(keyboard[i].y) | OBJ_HIDDEN; | ||
405 | OBJ_ATTR_1(i) = OBJ_SIZE_SMALL | OBJ_X_COORD(keyboard[i].x); | ||
406 | OBJ_ATTR_2(i) = (SPRITE_START_IDX + keyboard[i].symbol) | OBJ_PAL_BANK(0); | ||
407 | tile_x++; | ||
408 | if (tile_x - KEYBOARD_START_TILE_X >= KEYBOARD_ROW_SIZE) { | ||
409 | tile_x = KEYBOARD_START_TILE_X; | ||
410 | tile_y++; | ||
411 | } | ||
412 | } | ||
413 | OBJ_ATTR_0(127) = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(keyboard[cursor_position].y) | OBJ_HIDDEN; | ||
414 | OBJ_ATTR_1(127) = OBJ_SIZE_SMALL | OBJ_X_COORD(keyboard[cursor_position].x); | ||
415 | OBJ_ATTR_2(127) = (SPRITE_START_IDX + 0xdb) | OBJ_PAL_BANK(3); | ||
416 | |||
417 | return 1; | ||
418 | } | ||