view src/gb/gbGfx.cpp @ 378:5c4a30521d09

created efficient frame-metronome program
author Robert McIntyre <rlm@mit.edu>
date Wed, 11 Apr 2012 11:43:51 -0500
parents f9f4f1b99eed
children
line wrap: on
line source
1 #include <cstring>
3 #include "gbGlobals.h"
4 #include "gbSGB.h"
6 extern int32 layerSettings;
8 u8 gbInvertTab[256] = {
9 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
10 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
11 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
12 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
13 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
14 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
15 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
16 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
17 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
18 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
19 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
20 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
21 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
22 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
23 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
24 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
25 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
26 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
27 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
28 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
29 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
30 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
31 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
32 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
33 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
34 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
35 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
36 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
37 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
38 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
39 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
40 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
41 };
43 u16 gbLineMix[160];
45 void gbRenderLine()
46 {
47 u8 *bank0;
48 u8 *bank1;
49 if (gbCgbMode)
50 {
51 bank0 = &gbVram[0x0000];
52 bank1 = &gbVram[0x2000];
53 }
54 else
55 {
56 bank0 = &gbMemory[0x8000];
57 bank1 = NULL;
58 }
60 int tile_map = 0x1800;
61 if ((register_LCDC & 8) != 0)
62 tile_map = 0x1c00;
64 int tile_pattern = 0x0800;
66 if ((register_LCDC & 16) != 0)
67 tile_pattern = 0x0000;
69 int x = 0;
70 int y = register_LY;
72 if (y >= 144)
73 return;
75 // int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip;
77 int sx = register_SCX;
78 int sy = register_SCY;
80 sy += y;
82 sy &= 255;
84 int tx = sx >> 3;
85 int ty = sy >> 3;
87 int bx = 1 << (7 - (sx & 7));
88 int by = sy & 7;
90 int tile_map_line_y = tile_map + ty * 32;
92 int tile_map_address = tile_map_line_y + tx;
94 u8 attrs = 0;
95 if (bank1 != NULL)
96 attrs = bank1[tile_map_address];
98 u8 tile = bank0[tile_map_address];
100 tile_map_address++;
102 if ((register_LCDC & 16) == 0)
103 {
104 if (tile < 128)
105 tile += 128;
106 else
107 tile -= 128;
108 }
110 int tile_pattern_address = tile_pattern + tile * 16 + by*2;
112 if (register_LCDC & 0x80)
113 {
114 if ((register_LCDC & 0x01 || gbCgbMode) && (layerSettings & 0x0100))
115 {
116 while (x < 160)
117 {
118 u8 tile_a = 0;
119 u8 tile_b = 0;
121 if (attrs & 0x40)
122 {
123 tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2;
124 }
126 if (attrs & 0x08)
127 {
128 tile_a = bank1[tile_pattern_address++];
129 tile_b = bank1[tile_pattern_address];
130 }
131 else
132 {
133 tile_a = bank0[tile_pattern_address++];
134 tile_b = bank0[tile_pattern_address];
135 }
137 if (attrs & 0x20)
138 {
139 tile_a = gbInvertTab[tile_a];
140 tile_b = gbInvertTab[tile_b];
141 }
143 while (bx > 0)
144 {
145 u8 c = (tile_a & bx) ? 1 : 0;
146 c += ((tile_b & bx) ? 2 : 0);
148 gbLineBuffer[x] = c; // mark the gbLineBuffer color
150 if (attrs & 0x80)
151 gbLineBuffer[x] |= 0x300;
153 if (gbCgbMode)
154 {
155 c = c + (attrs & 7)*4;
156 }
157 else
158 {
159 c = gbBgp[c];
160 if (gbSgbMode && !gbCgbMode)
161 {
162 int dx = x >> 3;
163 int dy = y >> 3;
165 int palette = gbSgbATF[dy * 20 + dx];
167 if (c == 0)
168 palette = 0;
170 c = c + 4*palette;
171 }
172 }
173 gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c]] :
174 gbPalette[c];
175 x++;
176 if (x >= 160)
177 break;
178 bx >>= 1;
179 }
180 tx++;
181 if (tx == 32)
182 tx = 0;
183 bx = 128;
185 if (bank1)
186 attrs = bank1[tile_map_line_y + tx];
188 tile = bank0[tile_map_line_y + tx];
190 if ((register_LCDC & 16) == 0)
191 {
192 if (tile < 128)
193 tile += 128;
194 else
195 tile -= 128;
196 }
197 tile_pattern_address = tile_pattern + tile * 16 + by * 2;
198 }
199 }
200 else
201 {
202 for (int i = 0; i < 160; i++)
203 {
204 gbLineMix[i] = gbPalette[0];
205 gbLineBuffer[i] = 0;
206 }
207 }
209 // do the window display
210 if ((register_LCDC & 0x20) && (layerSettings & 0x2000))
211 {
212 int wy = register_WY;
214 if (y >= wy)
215 {
216 int wx = register_WX;
217 wx -= 7;
219 if (wx <= 159 && gbWindowLine <= 143)
220 {
221 tile_map = 0x1800;
223 if ((register_LCDC & 0x40) != 0)
224 tile_map = 0x1c00;
226 if (gbWindowLine == -1)
227 {
228 gbWindowLine = 0;
229 }
231 tx = 0;
232 ty = gbWindowLine >> 3;
234 bx = 128;
235 by = gbWindowLine & 7;
237 if (wx < 0)
238 {
239 bx >>= (-wx);
240 wx = 0;
241 }
243 tile_map_line_y = tile_map + ty * 32;
245 tile_map_address = tile_map_line_y + tx;
247 x = wx;
249 tile = bank0[tile_map_address];
250 u8 attrs = 0;
251 if (bank1)
252 attrs = bank1[tile_map_address];
253 tile_map_address++;
255 if ((register_LCDC & 16) == 0)
256 {
257 if (tile < 128)
258 tile += 128;
259 else
260 tile -= 128;
261 }
263 tile_pattern_address = tile_pattern + tile * 16 + by*2;
265 while (x < 160)
266 {
267 u8 tile_a = 0;
268 u8 tile_b = 0;
270 if (attrs & 0x40)
271 {
272 tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2;
273 }
275 if (attrs & 0x08)
276 {
277 tile_a = bank1[tile_pattern_address++];
278 tile_b = bank1[tile_pattern_address];
279 }
280 else
281 {
282 tile_a = bank0[tile_pattern_address++];
283 tile_b = bank0[tile_pattern_address];
284 }
286 if (attrs & 0x20)
287 {
288 tile_a = gbInvertTab[tile_a];
289 tile_b = gbInvertTab[tile_b];
290 }
292 while (bx > 0)
293 {
294 u8 c = (tile_a & bx) != 0 ? 1 : 0;
295 c += ((tile_b & bx) != 0 ? 2 : 0);
297 if (attrs & 0x80)
298 gbLineBuffer[x] = 0x300 + c;
299 else
300 gbLineBuffer[x] = 0x100 + c;
302 if (gbCgbMode)
303 {
304 c = c + (attrs & 7) * 4;
305 }
306 else
307 {
308 c = gbBgp[c];
309 if (gbSgbMode && !gbCgbMode)
310 {
311 int dx = x >> 3;
312 int dy = y >> 3;
314 int palette = gbSgbATF[dy * 20 + dx];
316 if (c == 0)
317 palette = 0;
319 c = c + 4*palette;
320 }
321 }
322 gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c]] :
323 gbPalette[c];
324 x++;
325 if (x >= 160)
326 break;
327 bx >>= 1;
328 }
329 tx++;
330 if (tx == 32)
331 tx = 0;
332 bx = 128;
333 tile = bank0[tile_map_line_y + tx];
334 if (bank1)
335 attrs = bank1[tile_map_line_y + tx];
337 if ((register_LCDC & 16) == 0)
338 {
339 if (tile < 128)
340 tile += 128;
341 else
342 tile -= 128;
343 }
344 tile_pattern_address = tile_pattern + tile * 16 + by * 2;
345 }
346 gbWindowLine++;
347 }
348 }
349 }
350 }
351 else
352 {
353 for (int i = 0; i < 160; i++)
354 {
355 gbLineMix[i] = gbPalette[0];
356 gbLineBuffer[i] = 0;
357 }
358 }
359 }
361 void gbDrawSpriteTile(int tile, int x, int y, int t, int flags,
362 int size, int spriteNumber)
363 {
364 u8 *bank0;
365 u8 *bank1;
366 if (gbCgbMode)
367 {
368 if (register_VBK & 1)
369 {
370 bank0 = &gbVram[0x0000];
371 bank1 = &gbVram[0x2000];
372 }
373 else
374 {
375 bank0 = &gbVram[0x0000];
376 bank1 = &gbVram[0x2000];
377 }
378 }
379 else
380 {
381 bank0 = &gbMemory[0x8000];
382 bank1 = NULL;
383 }
385 int init = 0x0000;
387 // int yLine = (y+gbBorderRowSkip) * gbBorderLineSkip;
389 u8 *pal = gbObp0;
391 int flipx = (flags & 0x20);
392 int flipy = (flags & 0x40);
394 if ((flags & 0x10))
395 pal = gbObp1;
397 if (flipy)
398 {
399 t = (size ? 15 : 7) - t;
400 }
402 int prio = flags & 0x80;
404 int address = init + tile * 16 + 2*t;
405 int a = 0;
406 int b = 0;
408 if (gbCgbMode && flags & 0x08)
409 {
410 a = bank1[address++];
411 b = bank1[address++];
412 }
413 else
414 {
415 a = bank0[address++];
416 b = bank0[address++];
417 }
419 for (int xx = 0; xx < 8; xx++)
420 {
421 u8 mask = 1 << (7-xx);
422 u8 c = 0;
423 if ((a & mask))
424 c++;
425 if ((b & mask))
426 c += 2;
428 if (c == 0)
429 continue;
431 int xxx = xx+x;
432 if (flipx)
433 xxx = (7-xx+x);
435 if (xxx < 0 || xxx > 159)
436 continue;
438 u16 color = gbLineBuffer[xxx];
440 if (prio)
441 {
442 if (color < 0x200 && ((color & 0xFF) != 0))
443 continue;
444 }
445 if (color >= 0x300 && color != 0x300)
446 continue;
447 else if (color >= 0x200 && color < 0x300)
448 {
449 int sprite = color & 0xff;
451 int spriteX = gbMemory[0xfe00 + 4 * sprite + 1] - 8;
453 if (spriteX == x)
454 {
455 if (sprite < spriteNumber)
456 continue;
457 }
458 else
459 {
460 if (gbCgbMode)
461 {
462 if (sprite < spriteNumber)
463 continue;
464 }
465 else
466 {
467 if (spriteX < x+8)
468 continue;
469 }
470 }
471 }
473 gbLineBuffer[xxx] = 0x200 + spriteNumber;
475 // make sure that sprites will work even in CGB mode
476 if (gbCgbMode)
477 {
478 c = c + (flags & 0x07)*4 + 32;
479 }
480 else
481 {
482 c = pal[c];
484 if (gbSgbMode && !gbCgbMode)
485 {
486 int dx = xxx >> 3;
487 int dy = y >> 3;
489 int palette = gbSgbATF[dy * 20 + dx];
491 if (c == 0)
492 palette = 0;
494 c = c + 4*palette;
495 }
496 else
497 {
498 c += 4;
499 }
500 }
502 gbLineMix[xxx] = gbColorOption ? gbColorFilter[gbPalette[c]] :
503 gbPalette[c];
504 }
505 }
507 void gbDrawSprites()
508 {
509 int x = 0;
510 int y = 0;
511 int count = 0;
513 int size = (register_LCDC & 4);
515 if (!(register_LCDC & 0x80))
516 return;
518 if ((register_LCDC & 2) && (layerSettings & 0x1000))
519 {
520 int yc = register_LY;
522 int address = 0xfe00;
523 for (int i = 0; i < 40; i++)
524 {
525 y = gbMemory[address++];
526 x = gbMemory[address++];
527 int tile = gbMemory[address++];
528 if (size)
529 tile &= 254;
530 int flags = gbMemory[address++];
532 if (x > 0 && y > 0 && x < 168 && y < 160)
533 {
534 // check if sprite intersects current line
535 int t = yc -y + 16;
536 if (size && t >= 0 && t < 16)
537 {
538 gbDrawSpriteTile(tile, x-8, yc, t, flags, size, i);
539 count++;
540 }
541 else if (!size && t >= 0 && t < 8)
542 {
543 gbDrawSpriteTile(tile, x-8, yc, t, flags, size, i);
544 count++;
545 }
546 }
547 // sprite limit reached!
548 if (count >= 10)
549 break;
550 }
551 }
552 }