1 /*****************************************************************************\ 2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. 3 This file is licensed under the Snes9x License. 4 For further information, consult the LICENSE file in the root directory. 5 \*****************************************************************************/ 6 7 #ifndef _TILEIMPL_H_ 8 #define _TILEIMPL_H_ 9 10 #include "snes9x.h" 11 #include "ppu.h" 12 #include "tile.h" 13 14 extern struct SLineMatrixData LineMatrixData[240]; 15 16 17 namespace TileImpl { 18 19 struct BPProgressive 20 { 21 enum { Pitch = 1 }; GetBPProgressive22 static alwaysinline uint32 Get(uint32 StartLine) { return StartLine; } 23 }; 24 25 // Interlace: Only draw every other line, so we'll redefine bpstart_t and Pitch to do so. 26 // Otherwise, it's the same as Normal2x1/Hires2x1. 27 struct BPInterlace 28 { 29 enum { Pitch = 2 }; GetBPInterlace30 static alwaysinline uint32 Get(uint32 StartLine) { return StartLine * 2 + BG.InterlaceLine; } 31 }; 32 33 34 // The 1x1 pixel plotter, for speedhacking modes. 35 template<class MATH, class BPSTART> 36 struct Normal1x1Base 37 { 38 enum { Pitch = BPSTART::Pitch }; 39 typedef BPSTART bpstart_t; 40 41 static void Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2); 42 }; 43 44 template<class MATH> 45 struct Normal1x1 : public Normal1x1Base<MATH, BPProgressive> {}; 46 47 48 // The 2x1 pixel plotter, for normal rendering when we've used hires/interlace already this frame. 49 template<class MATH, class BPSTART> 50 struct Normal2x1Base 51 { 52 enum { Pitch = BPSTART::Pitch }; 53 typedef BPSTART bpstart_t; 54 55 static void Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2); 56 }; 57 58 template<class MATH> 59 struct Normal2x1 : public Normal2x1Base<MATH, BPProgressive> {}; 60 template<class MATH> 61 struct Interlace : public Normal2x1Base<MATH, BPInterlace> {}; 62 63 64 // Hires pixel plotter, this combines the main and subscreen pixels as appropriate to render hires or pseudo-hires images. 65 // Use it only on the main screen, subscreen should use Normal2x1 instead. 66 // Hires math: 67 // Main pixel is mathed as normal: Main(x, y) * Sub(x, y). 68 // Sub pixel is mathed somewhat weird: Basically, for Sub(x + 1, y) we apply the same operation we applied to Main(x, y) 69 // (e.g. no math, add fixed, add1/2 subscreen) using Main(x, y) as the "corresponding subscreen pixel". 70 // Also, color window clipping clips Sub(x + 1, y) if Main(x, y) is clipped, not Main(x + 1, y). 71 // We don't know how Sub(0, y) is handled. 72 template<class MATH, class BPSTART> 73 struct HiresBase 74 { 75 enum { Pitch = BPSTART::Pitch }; 76 typedef BPSTART bpstart_t; 77 78 static void Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2); 79 }; 80 81 template<class MATH> 82 struct Hires : public HiresBase<MATH, BPProgressive> {}; 83 template<class MATH> 84 struct HiresInterlace : public HiresBase<MATH, BPInterlace> {}; 85 86 87 class CachedTile 88 { 89 public: CachedTile(uint32 tile)90 CachedTile(uint32 tile) : Tile(tile) {} 91 GetCachedTile()92 alwaysinline void GetCachedTile() 93 { 94 TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift); 95 if (Tile & 0x100) 96 TileAddr += BG.NameSelect; 97 TileAddr &= 0xffff; 98 TileNumber = TileAddr >> BG.TileShift; 99 if (Tile & H_FLIP) 100 { 101 pCache = &BG.BufferFlip[TileNumber << 6]; 102 if (!BG.BufferedFlip[TileNumber]) 103 BG.BufferedFlip[TileNumber] = BG.ConvertTileFlip(pCache, TileAddr, Tile & 0x3ff); 104 } 105 else 106 { 107 pCache = &BG.Buffer[TileNumber << 6]; 108 if (!BG.Buffered[TileNumber]) 109 BG.Buffered[TileNumber] = BG.ConvertTile(pCache, TileAddr, Tile & 0x3ff); 110 } 111 } 112 IsBlankTile()113 alwaysinline bool IsBlankTile() const 114 { 115 return ((Tile & H_FLIP) ? BG.BufferedFlip[TileNumber] : BG.Buffered[TileNumber]) == BLANK_TILE; 116 } 117 SelectPalette()118 alwaysinline void SelectPalette() const 119 { 120 if (BG.DirectColourMode) 121 { 122 GFX.RealScreenColors = DirectColourMaps[(Tile >> 10) & 7]; 123 } 124 else 125 GFX.RealScreenColors = &IPPU.ScreenColors[((Tile >> BG.PaletteShift) & BG.PaletteMask) + BG.StartPalette]; 126 GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; 127 } 128 Ptr()129 alwaysinline uint8* Ptr() const 130 { 131 return pCache; 132 } 133 134 private: 135 uint8 *pCache; 136 uint32 Tile; 137 uint32 TileNumber; 138 uint32 TileAddr; 139 }; 140 141 142 struct NOMATH 143 { CalcNOMATH144 static alwaysinline uint16 Calc(uint16 Main, uint16 Sub, uint8 SD) 145 { 146 return Main; 147 } 148 }; 149 typedef NOMATH Blend_None; 150 151 template<class Op> 152 struct REGMATH 153 { CalcREGMATH154 static alwaysinline uint16 Calc(uint16 Main, uint16 Sub, uint8 SD) 155 { 156 return Op::fn(Main, (SD & 0x20) ? Sub : GFX.FixedColour); 157 } 158 }; 159 typedef REGMATH<COLOR_ADD> Blend_Add; 160 typedef REGMATH<COLOR_SUB> Blend_Sub; 161 typedef REGMATH<COLOR_ADD_BRIGHTNESS> Blend_AddBrightness; 162 163 template<class Op> 164 struct MATHF1_2 165 { CalcMATHF1_2166 static alwaysinline uint16 Calc(uint16 Main, uint16 Sub, uint8 SD) 167 { 168 return GFX.ClipColors ? Op::fn(Main, GFX.FixedColour) : Op::fn1_2(Main, GFX.FixedColour); 169 } 170 }; 171 typedef MATHF1_2<COLOR_ADD> Blend_AddF1_2; 172 typedef MATHF1_2<COLOR_SUB> Blend_SubF1_2; 173 174 template<class Op> 175 struct MATHS1_2 176 { CalcMATHS1_2177 static alwaysinline uint16 Calc(uint16 Main, uint16 Sub, uint8 SD) 178 { 179 return GFX.ClipColors ? REGMATH<Op>::Calc(Main, Sub, SD) : (SD & 0x20) ? Op::fn1_2(Main, Sub) : Op::fn(Main, GFX.FixedColour); 180 } 181 }; 182 typedef MATHS1_2<COLOR_ADD> Blend_AddS1_2; 183 typedef MATHS1_2<COLOR_SUB> Blend_SubS1_2; 184 typedef MATHS1_2<COLOR_ADD_BRIGHTNESS> Blend_AddS1_2Brightness; 185 186 template< 187 template<class PIXEL_> class TILE, 188 template<class MATH> class PIXEL 189 > 190 struct Renderers 191 { 192 enum { Pitch = PIXEL<Blend_None>::Pitch }; 193 typedef typename TILE< PIXEL<Blend_None> >::call_t call_t; 194 195 static call_t Functions[9]; 196 }; 197 198 #ifdef _TILEIMPL_CPP_ 199 template< 200 template<class PIXEL_> class TILE, 201 template<class MATH> class PIXEL 202 > 203 typename Renderers<TILE, PIXEL>::call_t Renderers<TILE, PIXEL>::Functions[9] = 204 { 205 TILE< PIXEL<Blend_None> >::Draw, 206 TILE< PIXEL<Blend_Add> >::Draw, 207 TILE< PIXEL<Blend_AddF1_2> >::Draw, 208 TILE< PIXEL<Blend_AddS1_2> >::Draw, 209 TILE< PIXEL<Blend_Sub> >::Draw, 210 TILE< PIXEL<Blend_SubF1_2> >::Draw, 211 TILE< PIXEL<Blend_SubS1_2> >::Draw, 212 TILE< PIXEL<Blend_AddBrightness> >::Draw, 213 TILE< PIXEL<Blend_AddS1_2Brightness> >::Draw, 214 }; 215 #endif 216 217 // Basic routine to render an unclipped tile. 218 // Input parameters: 219 // bpstart_t = either StartLine or (StartLine * 2 + BG.InterlaceLine), 220 // so interlace modes can render every other line from the tile. 221 // Pitch = 1 or 2, again so interlace can count lines properly. 222 // DRAW_PIXEL(N, M) is a routine to actually draw the pixel. N is the pixel in the row to draw, 223 // and M is a test which if false means the pixel should be skipped. 224 // Z1 is the "draw if Z1 > cur_depth". 225 // Z2 is the "cur_depth = new_depth". OBJ need the two separate. 226 // Pix is the pixel to draw. 227 228 #define OFFSET_IN_LINE \ 229 uint32 OffsetInLine = Offset % GFX.RealPPL; 230 #define DRAW_PIXEL(N, M) PIXEL::Draw(N, M, Offset, OffsetInLine, Pix, Z1, Z2) 231 #define Z1 GFX.Z1 232 #define Z2 GFX.Z2 233 234 template<class PIXEL> 235 struct DrawTile16 236 { 237 typedef void (*call_t)(uint32, uint32, uint32, uint32); 238 239 enum { Pitch = PIXEL::Pitch }; 240 typedef typename PIXEL::bpstart_t bpstart_t; 241 DrawDrawTile16242 static void Draw(uint32 Tile, uint32 Offset, uint32 StartLine, uint32 LineCount) 243 { 244 CachedTile cache(Tile); 245 int32 l; 246 uint8 *bp, Pix; 247 248 cache.GetCachedTile(); 249 if (cache.IsBlankTile()) 250 return; 251 cache.SelectPalette(); 252 253 if (!(Tile & (V_FLIP | H_FLIP))) 254 { 255 bp = cache.Ptr() + bpstart_t::Get(StartLine); 256 OFFSET_IN_LINE; 257 for (l = LineCount; l > 0; l--, bp += 8 * Pitch, Offset += GFX.PPL) 258 { 259 for (int x = 0; x < 8; x++) { 260 Pix = bp[x]; DRAW_PIXEL(x, Pix); 261 } 262 } 263 } 264 else 265 if (!(Tile & V_FLIP)) 266 { 267 bp = cache.Ptr() + bpstart_t::Get(StartLine); 268 OFFSET_IN_LINE; 269 for (l = LineCount; l > 0; l--, bp += 8 * Pitch, Offset += GFX.PPL) 270 { 271 for (int x = 0; x < 8; x++) { 272 Pix = bp[7 - x]; DRAW_PIXEL(x, Pix); 273 } 274 } 275 } 276 else 277 if (!(Tile & H_FLIP)) 278 { 279 bp = cache.Ptr() + 56 - bpstart_t::Get(StartLine); 280 OFFSET_IN_LINE; 281 for (l = LineCount; l > 0; l--, bp -= 8 * Pitch, Offset += GFX.PPL) 282 { 283 for (int x = 0; x < 8; x++) { 284 Pix = bp[x]; DRAW_PIXEL(x, Pix); 285 } 286 } 287 } 288 else 289 { 290 bp = cache.Ptr() + 56 - bpstart_t::Get(StartLine); 291 OFFSET_IN_LINE; 292 for (l = LineCount; l > 0; l--, bp -= 8 * Pitch, Offset += GFX.PPL) 293 { 294 for (int x = 0; x < 8; x++) { 295 Pix = bp[7 - x]; DRAW_PIXEL(x, Pix); 296 } 297 } 298 } 299 } 300 }; 301 302 #undef Z1 303 #undef Z2 304 305 // Basic routine to render a clipped tile. Inputs same as above. 306 307 #define Z1 GFX.Z1 308 #define Z2 GFX.Z2 309 310 template<class PIXEL> 311 struct DrawClippedTile16 312 { 313 typedef void (*call_t)(uint32, uint32, uint32, uint32, uint32, uint32); 314 315 enum { Pitch = PIXEL::Pitch }; 316 typedef typename PIXEL::bpstart_t bpstart_t; 317 DrawDrawClippedTile16318 static void Draw(uint32 Tile, uint32 Offset, uint32 StartPixel, uint32 Width, uint32 StartLine, uint32 LineCount) 319 { 320 CachedTile cache(Tile); 321 int32 l; 322 uint8 *bp, Pix, w; 323 324 cache.GetCachedTile(); 325 if (cache.IsBlankTile()) 326 return; 327 cache.SelectPalette(); 328 329 if (!(Tile & (V_FLIP | H_FLIP))) 330 { 331 bp = cache.Ptr() + bpstart_t::Get(StartLine); 332 OFFSET_IN_LINE; 333 for (l = LineCount; l > 0; l--, bp += 8 * Pitch, Offset += GFX.PPL) 334 { 335 w = Width; 336 switch (StartPixel) 337 { 338 case 0: Pix = bp[0]; DRAW_PIXEL(0, Pix); if (!--w) break; /* Fall through */ 339 case 1: Pix = bp[1]; DRAW_PIXEL(1, Pix); if (!--w) break; /* Fall through */ 340 case 2: Pix = bp[2]; DRAW_PIXEL(2, Pix); if (!--w) break; /* Fall through */ 341 case 3: Pix = bp[3]; DRAW_PIXEL(3, Pix); if (!--w) break; /* Fall through */ 342 case 4: Pix = bp[4]; DRAW_PIXEL(4, Pix); if (!--w) break; /* Fall through */ 343 case 5: Pix = bp[5]; DRAW_PIXEL(5, Pix); if (!--w) break; /* Fall through */ 344 case 6: Pix = bp[6]; DRAW_PIXEL(6, Pix); if (!--w) break; /* Fall through */ 345 case 7: Pix = bp[7]; DRAW_PIXEL(7, Pix); break; 346 } 347 } 348 } 349 else 350 if (!(Tile & V_FLIP)) 351 { 352 bp = cache.Ptr() + bpstart_t::Get(StartLine); 353 OFFSET_IN_LINE; 354 for (l = LineCount; l > 0; l--, bp += 8 * Pitch, Offset += GFX.PPL) 355 { 356 w = Width; 357 switch (StartPixel) 358 { 359 case 0: Pix = bp[7]; DRAW_PIXEL(0, Pix); if (!--w) break; /* Fall through */ 360 case 1: Pix = bp[6]; DRAW_PIXEL(1, Pix); if (!--w) break; /* Fall through */ 361 case 2: Pix = bp[5]; DRAW_PIXEL(2, Pix); if (!--w) break; /* Fall through */ 362 case 3: Pix = bp[4]; DRAW_PIXEL(3, Pix); if (!--w) break; /* Fall through */ 363 case 4: Pix = bp[3]; DRAW_PIXEL(4, Pix); if (!--w) break; /* Fall through */ 364 case 5: Pix = bp[2]; DRAW_PIXEL(5, Pix); if (!--w) break; /* Fall through */ 365 case 6: Pix = bp[1]; DRAW_PIXEL(6, Pix); if (!--w) break; /* Fall through */ 366 case 7: Pix = bp[0]; DRAW_PIXEL(7, Pix); break; 367 } 368 } 369 } 370 else 371 if (!(Tile & H_FLIP)) 372 { 373 bp = cache.Ptr() + 56 - bpstart_t::Get(StartLine); 374 OFFSET_IN_LINE; 375 for (l = LineCount; l > 0; l--, bp -= 8 * Pitch, Offset += GFX.PPL) 376 { 377 w = Width; 378 switch (StartPixel) 379 { 380 case 0: Pix = bp[0]; DRAW_PIXEL(0, Pix); if (!--w) break; /* Fall through */ 381 case 1: Pix = bp[1]; DRAW_PIXEL(1, Pix); if (!--w) break; /* Fall through */ 382 case 2: Pix = bp[2]; DRAW_PIXEL(2, Pix); if (!--w) break; /* Fall through */ 383 case 3: Pix = bp[3]; DRAW_PIXEL(3, Pix); if (!--w) break; /* Fall through */ 384 case 4: Pix = bp[4]; DRAW_PIXEL(4, Pix); if (!--w) break; /* Fall through */ 385 case 5: Pix = bp[5]; DRAW_PIXEL(5, Pix); if (!--w) break; /* Fall through */ 386 case 6: Pix = bp[6]; DRAW_PIXEL(6, Pix); if (!--w) break; /* Fall through */ 387 case 7: Pix = bp[7]; DRAW_PIXEL(7, Pix); break; 388 } 389 } 390 } 391 else 392 { 393 bp = cache.Ptr() + 56 - bpstart_t::Get(StartLine); 394 OFFSET_IN_LINE; 395 for (l = LineCount; l > 0; l--, bp -= 8 * Pitch, Offset += GFX.PPL) 396 { 397 w = Width; 398 switch (StartPixel) 399 { 400 case 0: Pix = bp[7]; DRAW_PIXEL(0, Pix); if (!--w) break; /* Fall through */ 401 case 1: Pix = bp[6]; DRAW_PIXEL(1, Pix); if (!--w) break; /* Fall through */ 402 case 2: Pix = bp[5]; DRAW_PIXEL(2, Pix); if (!--w) break; /* Fall through */ 403 case 3: Pix = bp[4]; DRAW_PIXEL(3, Pix); if (!--w) break; /* Fall through */ 404 case 4: Pix = bp[3]; DRAW_PIXEL(4, Pix); if (!--w) break; /* Fall through */ 405 case 5: Pix = bp[2]; DRAW_PIXEL(5, Pix); if (!--w) break; /* Fall through */ 406 case 6: Pix = bp[1]; DRAW_PIXEL(6, Pix); if (!--w) break; /* Fall through */ 407 case 7: Pix = bp[0]; DRAW_PIXEL(7, Pix); break; 408 } 409 } 410 } 411 } 412 }; 413 414 #undef Z1 415 #undef Z2 416 417 // Basic routine to render a single mosaic pixel. 418 // DRAW_PIXEL, bpstart_t, Z1, Z2 and Pix are the same as above, but Pitch is not used. 419 420 #define Z1 GFX.Z1 421 #define Z2 GFX.Z2 422 423 template<class PIXEL> 424 struct DrawMosaicPixel16 425 { 426 typedef void (*call_t)(uint32, uint32, uint32, uint32, uint32, uint32); 427 428 typedef typename PIXEL::bpstart_t bpstart_t; 429 DrawDrawMosaicPixel16430 static void Draw(uint32 Tile, uint32 Offset, uint32 StartLine, uint32 StartPixel, uint32 Width, uint32 LineCount) 431 { 432 CachedTile cache(Tile); 433 int32 l, w; 434 uint8 Pix; 435 436 cache.GetCachedTile(); 437 if (cache.IsBlankTile()) 438 return; 439 cache.SelectPalette(); 440 441 if (Tile & H_FLIP) 442 StartPixel = 7 - StartPixel; 443 444 if (Tile & V_FLIP) 445 Pix = cache.Ptr()[56 - bpstart_t::Get(StartLine) + StartPixel]; 446 else 447 Pix = cache.Ptr()[bpstart_t::Get(StartLine) + StartPixel]; 448 449 if (Pix) 450 { 451 OFFSET_IN_LINE; 452 for (l = LineCount; l > 0; l--, Offset += GFX.PPL) 453 { 454 for (w = Width - 1; w >= 0; w--) 455 DRAW_PIXEL(w, 1); 456 } 457 } 458 } 459 }; 460 461 #undef Z1 462 #undef Z2 463 464 // Basic routine to render the backdrop. 465 // DRAW_PIXEL is the same as above, but since we're just replicating a single pixel there's no need for Pitch or bpstart_t 466 // (or interlace at all, really). 467 // The backdrop is always depth = 1, so Z1 = Z2 = 1. And backdrop is always color 0. 468 469 #define Z1 1 470 #define Z2 1 471 #define Pix 0 472 473 template<class PIXEL> 474 struct DrawBackdrop16 475 { 476 typedef void (*call_t)(uint32 Offset, uint32 Left, uint32 Right); 477 DrawDrawBackdrop16478 static void Draw(uint32 Offset, uint32 Left, uint32 Right) 479 { 480 uint32 l, x; 481 482 GFX.RealScreenColors = IPPU.ScreenColors; 483 GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; 484 485 OFFSET_IN_LINE; 486 for (l = GFX.StartY; l <= GFX.EndY; l++, Offset += GFX.PPL) 487 { 488 for (x = Left; x < Right; x++) 489 DRAW_PIXEL(x, 1); 490 } 491 } 492 }; 493 494 #undef Pix 495 #undef Z1 496 #undef Z2 497 #undef DRAW_PIXEL 498 499 // Basic routine to render a chunk of a Mode 7 BG. 500 // Mode 7 has no interlace, so bpstart_t and Pitch are unused. 501 // We get some new parameters, so we can use the same DRAW_TILE to do BG1 or BG2: 502 // DCMODE tests if Direct Color should apply. 503 // BG is the BG, so we use the right clip window. 504 // MASK is 0xff or 0x7f, the 'color' portion of the pixel. 505 // We define Z1/Z2 to either be constant 5 or to vary depending on the 'priority' portion of the pixel. 506 507 #define CLIP_10_BIT_SIGNED(a) (((a) & 0x2000) ? ((a) | ~0x3ff) : ((a) & 0x3ff)) 508 509 #define DRAW_PIXEL(N, M) PIXEL::Draw(N, M, Offset, OffsetInLine, Pix, OP::Z1(D, b), OP::Z2(D, b)) 510 511 struct DrawMode7BG1_OP 512 { 513 enum { 514 MASK = 0xff, 515 BG = 0 516 }; Z1DrawMode7BG1_OP517 static uint8 Z1(int D, uint8 b) { return D + 7; } Z2DrawMode7BG1_OP518 static uint8 Z2(int D, uint8 b) { return D + 7; } DCMODEDrawMode7BG1_OP519 static uint8 DCMODE() { return Memory.FillRAM[0x2130] & 1; } 520 }; 521 struct DrawMode7BG2_OP 522 { 523 enum { 524 MASK = 0x7f, 525 BG = 1 526 }; Z1DrawMode7BG2_OP527 static uint8 Z1(int D, uint8 b) { return D + ((b & 0x80) ? 11 : 3); } Z2DrawMode7BG2_OP528 static uint8 Z2(int D, uint8 b) { return D + ((b & 0x80) ? 11 : 3); } DCMODEDrawMode7BG2_OP529 static uint8 DCMODE() { return 0; } 530 }; 531 532 template<class PIXEL, class OP> 533 struct DrawTileNormal 534 { 535 typedef void (*call_t)(uint32 Left, uint32 Right, int D); 536 DrawDrawTileNormal537 static void Draw(uint32 Left, uint32 Right, int D) 538 { 539 uint8 *VRAM1 = Memory.VRAM + 1; 540 541 if (OP::DCMODE()) 542 { 543 GFX.RealScreenColors = DirectColourMaps[0]; 544 } 545 else 546 GFX.RealScreenColors = IPPU.ScreenColors; 547 548 GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; 549 550 int aa, cc; 551 int startx; 552 553 uint32 Offset = GFX.StartY * GFX.PPL; 554 struct SLineMatrixData *l = &LineMatrixData[GFX.StartY]; 555 556 OFFSET_IN_LINE; 557 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Offset += GFX.PPL, l++) 558 { 559 int yy, starty; 560 561 int32 HOffset = ((int32) l->M7HOFS << 19) >> 19; 562 int32 VOffset = ((int32) l->M7VOFS << 19) >> 19; 563 564 int32 CentreX = ((int32) l->CentreX << 19) >> 19; 565 int32 CentreY = ((int32) l->CentreY << 19) >> 19; 566 567 if (PPU.Mode7VFlip) 568 starty = 255 - (int) (Line + 1); 569 else 570 starty = Line + 1; 571 572 yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); 573 574 int BB = ((l->MatrixB * starty) & ~63) + ((l->MatrixB * yy) & ~63) + (CentreX << 8); 575 int DD = ((l->MatrixD * starty) & ~63) + ((l->MatrixD * yy) & ~63) + (CentreY << 8); 576 577 if (PPU.Mode7HFlip) 578 { 579 startx = Right - 1; 580 aa = -l->MatrixA; 581 cc = -l->MatrixC; 582 } 583 else 584 { 585 startx = Left; 586 aa = l->MatrixA; 587 cc = l->MatrixC; 588 } 589 590 int xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); 591 int AA = l->MatrixA * startx + ((l->MatrixA * xx) & ~63); 592 int CC = l->MatrixC * startx + ((l->MatrixC * xx) & ~63); 593 594 uint8 Pix; 595 596 if (!PPU.Mode7Repeat) 597 { 598 for (uint32 x = Left; x < Right; x++, AA += aa, CC += cc) 599 { 600 int X = ((AA + BB) >> 8) & 0x3ff; 601 int Y = ((CC + DD) >> 8) & 0x3ff; 602 603 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); 604 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); 605 606 Pix = b & OP::MASK; DRAW_PIXEL(x, Pix); 607 } 608 } 609 else 610 { 611 for (uint32 x = Left; x < Right; x++, AA += aa, CC += cc) 612 { 613 int X = ((AA + BB) >> 8); 614 int Y = ((CC + DD) >> 8); 615 616 uint8 b; 617 618 if (((X | Y) & ~0x3ff) == 0) 619 { 620 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); 621 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); 622 } 623 else 624 if (PPU.Mode7Repeat == 3) 625 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); 626 else 627 continue; 628 629 Pix = b & OP::MASK; DRAW_PIXEL(x, Pix); 630 } 631 } 632 } 633 } 634 }; 635 636 template<class PIXEL> 637 struct DrawMode7BG1 : public DrawTileNormal<PIXEL, DrawMode7BG1_OP> {}; 638 template<class PIXEL> 639 struct DrawMode7BG2 : public DrawTileNormal<PIXEL, DrawMode7BG2_OP> {}; 640 641 template<class PIXEL, class OP> 642 struct DrawTileMosaic 643 { 644 typedef void (*call_t)(uint32 Left, uint32 Right, int D); 645 DrawDrawTileMosaic646 static void Draw(uint32 Left, uint32 Right, int D) 647 { 648 uint8 *VRAM1 = Memory.VRAM + 1; 649 650 if (OP::DCMODE()) 651 { 652 GFX.RealScreenColors = DirectColourMaps[0]; 653 } 654 else 655 GFX.RealScreenColors = IPPU.ScreenColors; 656 657 GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; 658 659 int aa, cc; 660 int startx, StartY = GFX.StartY; 661 662 int HMosaic = 1, VMosaic = 1, MosaicStart = 0; 663 int32 MLeft = Left, MRight = Right; 664 665 if (PPU.BGMosaic[0]) 666 { 667 VMosaic = PPU.Mosaic; 668 MosaicStart = ((uint32) GFX.StartY - PPU.MosaicStart) % VMosaic; 669 StartY -= MosaicStart; 670 } 671 672 if (PPU.BGMosaic[OP::BG]) 673 { 674 HMosaic = PPU.Mosaic; 675 MLeft -= MLeft % HMosaic; 676 MRight += HMosaic - 1; 677 MRight -= MRight % HMosaic; 678 } 679 680 uint32 Offset = StartY * GFX.PPL; 681 struct SLineMatrixData *l = &LineMatrixData[StartY]; 682 683 OFFSET_IN_LINE; 684 for (uint32 Line = StartY; Line <= GFX.EndY; Line += VMosaic, Offset += VMosaic * GFX.PPL, l += VMosaic) 685 { 686 if (Line + VMosaic > GFX.EndY) 687 VMosaic = GFX.EndY - Line + 1; 688 689 int yy, starty; 690 691 int32 HOffset = ((int32) l->M7HOFS << 19) >> 19; 692 int32 VOffset = ((int32) l->M7VOFS << 19) >> 19; 693 694 int32 CentreX = ((int32) l->CentreX << 19) >> 19; 695 int32 CentreY = ((int32) l->CentreY << 19) >> 19; 696 697 if (PPU.Mode7VFlip) 698 starty = 255 - (int) (Line + 1); 699 else 700 starty = Line + 1; 701 702 yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); 703 704 int BB = ((l->MatrixB * starty) & ~63) + ((l->MatrixB * yy) & ~63) + (CentreX << 8); 705 int DD = ((l->MatrixD * starty) & ~63) + ((l->MatrixD * yy) & ~63) + (CentreY << 8); 706 707 if (PPU.Mode7HFlip) 708 { 709 startx = MRight - 1; 710 aa = -l->MatrixA; 711 cc = -l->MatrixC; 712 } 713 else 714 { 715 startx = MLeft; 716 aa = l->MatrixA; 717 cc = l->MatrixC; 718 } 719 720 int xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); 721 int AA = l->MatrixA * startx + ((l->MatrixA * xx) & ~63); 722 int CC = l->MatrixC * startx + ((l->MatrixC * xx) & ~63); 723 724 uint8 Pix; 725 uint8 ctr = 1; 726 727 if (!PPU.Mode7Repeat) 728 { 729 for (int32 x = MLeft; x < MRight; x++, AA += aa, CC += cc) 730 { 731 if (--ctr) 732 continue; 733 ctr = HMosaic; 734 735 int X = ((AA + BB) >> 8) & 0x3ff; 736 int Y = ((CC + DD) >> 8) & 0x3ff; 737 738 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); 739 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); 740 741 if ((Pix = (b & OP::MASK))) 742 { 743 for (int32 h = MosaicStart; h < VMosaic; h++) 744 { 745 for (int32 w = x + HMosaic - 1; w >= x; w--) 746 DRAW_PIXEL(w + h * GFX.PPL, (w >= (int32) Left && w < (int32) Right)); 747 } 748 } 749 } 750 } 751 else 752 { 753 for (int32 x = MLeft; x < MRight; x++, AA += aa, CC += cc) 754 { 755 if (--ctr) 756 continue; 757 ctr = HMosaic; 758 759 int X = ((AA + BB) >> 8); 760 int Y = ((CC + DD) >> 8); 761 762 uint8 b; 763 764 if (((X | Y) & ~0x3ff) == 0) 765 { 766 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); 767 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); 768 } 769 else 770 if (PPU.Mode7Repeat == 3) 771 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); 772 else 773 continue; 774 775 if ((Pix = (b & OP::MASK))) 776 { 777 for (int32 h = MosaicStart; h < VMosaic; h++) 778 { 779 for (int32 w = x + HMosaic - 1; w >= x; w--) 780 DRAW_PIXEL(w + h * GFX.PPL, (w >= (int32) Left && w < (int32) Right)); 781 } 782 } 783 } 784 } 785 786 MosaicStart = 0; 787 } 788 } 789 }; 790 791 template<class PIXEL> 792 struct DrawMode7MosaicBG1 : public DrawTileMosaic<PIXEL, DrawMode7BG1_OP> {}; 793 template<class PIXEL> 794 struct DrawMode7MosaicBG2 : public DrawTileMosaic<PIXEL, DrawMode7BG2_OP> {}; 795 796 797 #undef DRAW_PIXEL 798 799 } // namespace TileImpl 800 801 #endif 802