annotate src/gb/gbGfx.cpp @ 615:bd664a9bd863

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