aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.c6
-rw-r--r--src/ppu.c239
-rw-r--r--src/ppu.h6
3 files changed, 169 insertions, 82 deletions
diff --git a/src/main.c b/src/main.c
index 4b2b2d6..0e56897 100644
--- a/src/main.c
+++ b/src/main.c
@@ -136,11 +136,11 @@ screen_talk(Device *d, u8 b0, u8 w) {
136 u8 *layer = d->dat[0xe] >> 4 & 0x1 ? ppu.fg : ppu.bg; 136 u8 *layer = d->dat[0xe] >> 4 & 0x1 ? ppu.fg : ppu.bg;
137 u8 mode = d->dat[0xe] >> 5; 137 u8 mode = d->dat[0xe] >> 5;
138 if(!mode) { 138 if(!mode) {
139 putpixel(layer, x, y, d->dat[0xe] & 0x3); 139 ppu_pixel(layer, x, y, d->dat[0xe] & 0x3);
140 } else if(mode-- & 0x1) { 140 } else if(mode-- & 0x1) {
141 puticn(layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4); 141 ppu_1bpp(layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4);
142 } else { 142 } else {
143 putchr(layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4); 143 ppu_2bpp(layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4);
144 } 144 }
145 } 145 }
146} 146}
diff --git a/src/ppu.c b/src/ppu.c
index f626604..018555f 100644
--- a/src/ppu.c
+++ b/src/ppu.c
@@ -25,7 +25,7 @@ WITH REGARD TO THIS SOFTWARE.
25// Keyboard. 25// Keyboard.
26#define SPRITE_START_IDX 640 26#define SPRITE_START_IDX 640
27 27
28static u32 unpack_icon_lut[256] = { 28static u32 lut_2bpp[256] = {
29 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, 29 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100,
30 0x00000101, 0x00000110, 0x00000111, 0x00001000, 0x00001001, 30 0x00000101, 0x00000110, 0x00000111, 0x00001000, 0x00001001,
31 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, 31 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110,
@@ -80,7 +80,7 @@ static u32 unpack_icon_lut[256] = {
80 0x11111111 80 0x11111111
81}; 81};
82 82
83static u32 unpack_icon_lut_flipx[256] = { 83static u32 lut2bpp_flipx[256] = {
84 0x00000000, 0x10000000, 0x01000000, 0x11000000, 0x00100000, 84 0x00000000, 0x10000000, 0x01000000, 0x11000000, 0x00100000,
85 0x10100000, 0x01100000, 0x11100000, 0x00010000, 0x10010000, 85 0x10100000, 0x01100000, 0x11100000, 0x00010000, 0x10010000,
86 0x01010000, 0x11010000, 0x00110000, 0x10110000, 0x01110000, 86 0x01010000, 0x11010000, 0x00110000, 0x10110000, 0x01110000,
@@ -135,6 +135,14 @@ static u32 unpack_icon_lut_flipx[256] = {
135 0x11111111 135 0x11111111
136}; 136};
137 137
138static u8 blending[5][16] = {
139 {0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0},
140 {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
141 {1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1},
142 {2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2},
143 {1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}
144};
145
138static u32 dirty_tiles[21] = {0}; 146static u32 dirty_tiles[21] = {0};
139 147
140void 148void
@@ -160,7 +168,7 @@ putcolors(u8 *addr) {
160 168
161IWRAM_CODE 169IWRAM_CODE
162void 170void
163putpixel(u32 *layer, u16 x, u16 y, u8 color) { 171ppu_pixel(u32 *layer, u16 x, u16 y, u8 color) {
164 if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; 172 if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return;
165 size_t tile_x = x / 8; 173 size_t tile_x = x / 8;
166 size_t tile_y = y / 8; 174 size_t tile_y = y / 8;
@@ -174,106 +182,185 @@ putpixel(u32 *layer, u16 x, u16 y, u8 color) {
174 182
175IWRAM_CODE 183IWRAM_CODE
176void 184void
177puticn(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy) { 185ppu_1bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy) {
178 u8 sprline; 186 u8 sprline;
179 u16 v; 187 u16 v;
180 u32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3)); 188 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 189
187 if (flipy) flipy = 7; 190 u32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8));
191 u32 *layerptr = &layer[layerpos];
192 u32 shift = (x & 7) << 2;
193 u32 *lut_expand = flipx ? lut_2bpp : lut2bpp_flipx;
188 194
189 if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; 195 if (flipy) flipy = 7;
190 196
191 if (color != 0x05 && color != 0x0a && color != 0x0f) { 197 if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return;
192 u64 mask = ~((u64)0xFFFFFFFF << shift);
193 198
194 for (v = 0; v < 8; v++, layerptr++) { 199 if (blending[4][color]) {
195 if ((y + v) >= SCREEN_HEIGHT) break; 200 u64 mask = ~((u64)0xFFFFFFFF << shift);
196 201
197 sprline = sprite[v ^ flipy]; 202 for (v = 0; v < 8; v++, layerptr++) {
198 u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift; 203 if ((y + v) >= SCREEN_HEIGHT) break;
199 data |= (u64)(lut_expand[sprline ^ 0xFF] * (color >> 2)) << shift;
200 204
201 layerptr[0] = (layerptr[0] & mask) | data; 205 sprline = sprite[v ^ flipy];
202 layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); 206 u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift;
207 data |= (u64)(lut_expand[sprline ^ 0xFF] * (color >> 2)) << shift;
203 208
204 if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; 209 layerptr[0] = (layerptr[0] & mask) | data;
205 } 210 layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32);
206 } else {
207 for (v = 0; v < 8; v++, layerptr++) {
208 if ((y + v) >= SCREEN_HEIGHT) break;
209 211
210 sprline = sprite[v ^ flipy]; 212 if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8;
211 u64 mask = ~((u64)(lut_expand[sprline] * 0xF) << shift); 213 }
212 u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift; 214 } else {
215 for (v = 0; v < 8; v++, layerptr++) {
216 if ((y + v) >= SCREEN_HEIGHT) break;
213 217
214 layerptr[0] = (layerptr[0] & mask) | data; 218 sprline = sprite[v ^ flipy];
215 layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); 219 u64 mask = ~((u64)(lut_expand[sprline] * 0xF) << shift);
220 u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift;
216 221
217 if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; 222 layerptr[0] = (layerptr[0] & mask) | data;
218 } 223 layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32);
219 }
220 224
221 dirty_tiles[y >> 3] |= dirtyflag; 225 if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8;
222 dirty_tiles[(y + 7) >> 3] |= dirtyflag; 226 }
223} 227 }
224 228
225IWRAM_CODE 229 dirty_tiles[y >> 3] |= dirtyflag;
226void 230 dirty_tiles[(y + 7) >> 3] |= dirtyflag;
227putfontchar(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} 231}
236 232
237IWRAM_CODE 233IWRAM_CODE
238void 234void
239putchr(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, 235ppu_2bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color,
240 u8 flipx, u8 flipy) { 236 u8 flipx, u8 flipy) {
241 u8 sprline1, sprline2; 237 u8 sprline1, sprline2;
242 u16 v; 238 u8 xrightedge = x < ((32 - 1) * 8);
243 u32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3)); 239 u16 v, h;
240 u32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3));
241
242 u32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8));
243 u32 *layerptr = &layer[layerpos];
244 u32 shift = (x & 7) << 2;
245
246 if (flipy) flipy = 7;
247
248 if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return;
249
250 if (color == 1) {
251 u32 *lut_expand = flipx ? lut_2bpp : lut2bpp_flipx;
252 u64 mask = ~((u64)0xFFFFFFFF << shift);
253
254 for (v = 0; v < 8; v++, layerptr++) {
255 if ((y + v) >= (24 * 8)) break;
244 256
245 u32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8)); 257 sprline1 = sprite[v ^ flipy];
246 u32 *layerptr = &layer[layerpos]; 258 sprline2 = sprite[(v ^ flipy) | 8];
247 u32 shift = (x & 7) << 2;
248 u32 *lut_expand = flipx ? unpack_icon_lut : unpack_icon_lut_flipx;
249 259
250 if (flipy) flipy = 7; 260 u32 data32 = (lut_expand[sprline1]) | (lut_expand[sprline2] << 1);
261 u64 data = ((u64) (data32 & 0x33333333)) << shift;
251 262
252 if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; 263 layerptr[0] = (layerptr[0] & mask) | data;
264 if (xrightedge) layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32);
265
266 if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8;
267 }
268 } else if (blending[4][color]) {
269 u64 mask = ~((u64)0xFFFFFFFF << shift);
253 270
254 u64 mask = ~((u64)0xFFFFFFFF << shift); 271 for (v = 0; v < 8; v++, layerptr++) {
255 u32 colconst = (color >> 2) * 0x11111111; 272 if ((y + v) >= (24 * 8)) break;
256 273
257 for (v = 0; v < 8; v++, layerptr++) { 274 u8 ch1 = sprite[v ^ flipy];
258 if ((y + v) >= SCREEN_HEIGHT) break; 275 u8 ch2 = sprite[(v ^ flipy) | 8];
276 u32 data32 = 0;
259 277
260 sprline1 = sprite[v ^ flipy]; 278 if (!flipx) {
261 sprline2 = sprite[(v ^ flipy) | 8]; 279 for (h = 0; h < 8; h++) {
280 data32 <<= 4;
262 281
263 u32 data32 = 282 u8 ch = (ch1 & 1) | ((ch2 & 1) << 1);
264 (lut_expand[sprline1] * (color & 3)) 283 data32 |= blending[ch][color];
265 + (lut_expand[sprline2] * ((color & 1) << 1))
266 + colconst;
267 u64 data = ((u64) (data32 & 0x33333333)) << shift;
268 284
269 layerptr[0] = (layerptr[0] & mask) | data; 285 ch1 >>= 1; ch2 >>= 1;
270 layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); 286 }
287 } else {
288 for (h = 0; h < 8; h++) {
289 data32 <<= 4;
271 290
272 if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; 291 u8 ch = (ch1 >> 7) | ((ch2 >> 7) << 1);
273 } 292 data32 |= blending[ch][color];
274 293
275 dirty_tiles[y >> 3] |= dirtyflag; 294 ch1 <<= 1; ch2 <<= 1;
276 dirty_tiles[(y + 7) >> 3] |= dirtyflag; 295 }
296 }
297
298 u64 data = ((u64) (data32 & 0x33333333)) << shift;
299
300 layerptr[0] = (layerptr[0] & mask) | data;
301 if (xrightedge) layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32);
302
303 if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8;
304 }
305 } else {
306 for (v = 0; v < 8; v++, layerptr++) {
307 if ((y + v) >= (24 * 8)) break;
308
309 u8 ch1 = sprite[v ^ flipy];
310 u8 ch2 = sprite[(v ^ flipy) | 8];
311 u32 data32 = 0;
312 u32 mask32 = 0;
313
314 if (!flipx) {
315 for (h = 0; h < 8; h++) {
316 data32 <<= 4; mask32 <<= 4;
317
318 if ((ch1 | ch2) & 1) {
319 u8 ch = (ch1 & 1) | ((ch2 & 1) << 1);
320 data32 |= blending[ch][color];
321 mask32 |= 0xF;
322 }
323
324 ch1 >>= 1; ch2 >>= 1;
325 }
326 } else {
327 for (h = 0; h < 8; h++) {
328 data32 <<= 4; mask32 <<= 4;
329
330 if ((ch1 | ch2) & 128) {
331 u8 ch = (ch1 >> 7) | ((ch2 >> 7) << 1);
332 data32 |= blending[ch][color];
333 mask32 |= 0xF;
334 }
335
336 ch1 <<= 1; ch2 <<= 1;
337 }
338 }
339
340 u64 data = ((u64) (data32 & 0x33333333)) << shift;
341 u64 mask = ~(((u64) (mask32 & 0x33333333)) << shift);
342
343 layerptr[0] = (layerptr[0] & mask) | data;
344 if (xrightedge) layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32);
345
346 if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8;
347 }
348 }
349
350 dirty_tiles[y >> 3] |= dirtyflag;
351 dirty_tiles[(y + 7) >> 3] |= dirtyflag;
352}
353
354IWRAM_CODE
355void
356putfontchar(u32 *layer, u16 tile_x, u16 tile_y, u8 ch, u8 color) {
357 u32 pos = (tile_x + tile_y * 32) * 8;
358 u32 *tile_data = &layer[pos];
359 u32 *font_data = &FONT_DATA[8 * ch];
360 for (size_t i = 0; i < 8; ++i) {
361 tile_data[i] = font_data[i] * color;
362 }
363 dirty_tiles[tile_y] |= 1 << tile_x;
277} 364}
278 365
279IWRAM_CODE 366IWRAM_CODE
diff --git a/src/ppu.h b/src/ppu.h
index 0356b63..b5eb250 100644
--- a/src/ppu.h
+++ b/src/ppu.h
@@ -24,7 +24,7 @@ typedef struct Ppu {
24 24
25int initppu(Ppu *p, u8 hor, u8 ver, u8 pad); 25int initppu(Ppu *p, u8 hor, u8 ver, u8 pad);
26void putcolors(u8 *addr); 26void putcolors(u8 *addr);
27void putpixel(u32 *layer, u16 x, u16 y, u8 color); 27void ppu_pixel(u32 *layer, u16 x, u16 y, u8 color);
28void puticn(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy); 28void ppu_1bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy);
29void putchr(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy); 29void ppu_2bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy);
30#endif // UXNGBA_PPU_H 30#endif // UXNGBA_PPU_H