2 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
4 * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5 * Jerremy Koot (jkoot@snes9x.com)
7 * Super FX C emulator code
8 * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
10 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
12 * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13 * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14 * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
16 * DOS port code contains the works of other authors. See headers in
19 * Snes9x homepage: http://www.snes9x.com
21 * Permission to use, copy, modify and distribute Snes9x in both binary and
22 * source form, for non-commercial purposes, is hereby granted without fee,
23 * providing that this license information and copyright notice appear with
24 * all copies and any derived work.
26 * This software is provided 'as-is', without any express or implied
27 * warranty. In no event shall the authors be held liable for any damages
28 * arising from the use of this software.
30 * Snes9x is freeware for PERSONAL USE only. Commercial users should
31 * seek permission of the copyright holders first. Commercial use includes
32 * charging money for Snes9x or software derived from Snes9x.
34 * The copyright holders request that bug fixes and improvements to the code
35 * should be forwarded to them so everyone can benefit from the modifications
38 * Super NES and Super Nintendo Entertainment System are trademarks of
39 * Nintendo Co., Limited and its subsidiary companies.
55 #define USE_CRAZY_OPTS
60 #define GFX_PIX_SIZE 1
62 void ComputeClipWindows();
63 static void S9xDisplayFrameRate();
64 static void S9xDisplayString(const char *string);
66 extern uint8 BitShifts[8][4];
67 extern uint8 TileShifts[8][4];
68 extern uint8 PaletteShifts[8][4];
69 extern uint8 PaletteMasks[8][4];
70 extern uint8 Depths[8][4];
71 extern uint8 BGSizes [2];
73 extern NormalTileRenderer DrawTilePtr;
74 extern ClippedTileRenderer DrawClippedTilePtr;
75 extern NormalTileRenderer DrawHiResTilePtr;
76 extern ClippedTileRenderer DrawHiResClippedTilePtr;
77 extern LargePixelRenderer DrawLargePixelPtr;
81 extern struct SLineData LineData[240];
82 extern struct SLineMatrixData LineMatrixData [240];
84 extern uint8 Mode7Depths [2];
87 (GFX.r212c & (1 << (N)) && \
88 !(PPU.BG_Forced & (1 << (N))))
90 #define SUB_OR_ADD(N) \
91 (GFX.r2131 & (1 << (N)))
94 ((GFX.r2130 & 0x30) != 0x30 && \
96 (GFX.r212d & (1 << N)) && \
97 !(PPU.BG_Forced & (1 << (N))))
99 #define ANYTHING_ON_SUB \
100 ((GFX.r2130 & 0x30) != 0x30 && \
104 #define ADD_OR_SUB_ON_ANYTHING \
107 #define BLACK BUILD_PIXEL(0,0,0)
109 bool8 S9xGraphicsInit ()
111 register uint32 PixelOdd = 1;
112 register uint32 PixelEven = 2;
114 #ifdef GFX_MULTI_FORMAT
115 if (GFX.BuildPixel == NULL)
116 S9xSetRenderPixelFormat (RGB565);
119 for (uint8 bitshift = 0; bitshift < 4; bitshift++)
121 for (register int i = 0; i < 16; i++)
123 register uint32 h = 0;
124 register uint32 l = 0;
126 #if defined(LSB_FIRST)
145 h |= (PixelOdd << 24);
147 h |= (PixelOdd << 16);
149 h |= (PixelOdd << 8);
153 l |= (PixelOdd << 24);
155 l |= (PixelOdd << 16);
157 l |= (PixelOdd << 8);
162 odd_high[bitshift][i] = h;
163 odd_low[bitshift][i] = l;
166 #if defined(LSB_FIRST)
172 h |= PixelEven << 16;
174 h |= PixelEven << 24;
180 l |= PixelEven << 16;
182 l |= PixelEven << 24;
185 h |= (PixelEven << 24);
187 h |= (PixelEven << 16);
189 h |= (PixelEven << 8);
193 l |= (PixelEven << 24);
195 l |= (PixelEven << 16);
197 l |= (PixelEven << 8);
202 even_high[bitshift][i] = h;
203 even_low[bitshift][i] = l;
209 GFX.InfoStringTimeout = 0;
210 GFX.InfoString = NULL;
213 IPPU.OBJChanged = TRUE;
215 IPPU.DirectColourMapsNeedRebuild = TRUE;
216 DrawTilePtr = DrawTile16;
217 DrawClippedTilePtr = DrawClippedTile16;
218 DrawLargePixelPtr = DrawLargePixel16;
219 DrawHiResTilePtr= DrawHiResTile16;
220 DrawHiResClippedTilePtr = DrawHiResClippedTile16;
221 S9xFixColourBrightness();
223 if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
226 if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
227 !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
231 free ((char *) GFX.ZERO_OR_X2);
232 GFX.ZERO_OR_X2 = NULL;
236 free ((char *) GFX.X2);
243 // Build a lookup table that multiplies a packed RGB value by 2 with
245 for (r = 0; r <= MAX_RED; r++)
250 for (g = 0; g <= MAX_GREEN; g++)
255 for (b = 0; b <= MAX_BLUE; b++)
260 GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
261 GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
265 ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
266 ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
267 // Build a lookup table that if the top bit of the color value is zero
268 // then the value is zero, otherwise multiply the value by 2. Used by
269 // the color subtraction code.
271 #if defined(OLD_COLOUR_BLENDING)
272 for (r = 0; r <= MAX_RED; r++)
275 if ((r2 & 0x10) == 0)
278 r2 = (r2 << 1) & MAX_RED;
280 for (g = 0; g <= MAX_GREEN; g++)
283 if ((g2 & GREEN_HI_BIT) == 0)
286 g2 = (g2 << 1) & MAX_GREEN;
288 for (b = 0; b <= MAX_BLUE; b++)
291 if ((b2 & 0x10) == 0)
294 b2 = (b2 << 1) & MAX_BLUE;
296 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
297 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
302 for (r = 0; r <= MAX_RED; r++)
305 if ((r2 & 0x10) == 0)
308 r2 = (r2 << 1) & MAX_RED;
312 for (g = 0; g <= MAX_GREEN; g++)
315 if ((g2 & GREEN_HI_BIT) == 0)
318 g2 = (g2 << 1) & MAX_GREEN;
322 for (b = 0; b <= MAX_BLUE; b++)
325 if ((b2 & 0x10) == 0)
328 b2 = (b2 << 1) & MAX_BLUE;
332 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
333 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
339 // Build a lookup table that if the top bit of the color value is zero
340 // then the value is zero, otherwise its just the value.
341 for (r = 0; r <= MAX_RED; r++)
344 if ((r2 & 0x10) == 0)
349 for (g = 0; g <= MAX_GREEN; g++)
352 if ((g2 & GREEN_HI_BIT) == 0)
356 for (b = 0; b <= MAX_BLUE; b++)
359 if ((b2 & 0x10) == 0)
364 GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
365 GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
373 void S9xGraphicsDeinit (void)
375 // Free any memory allocated in S9xGraphicsInit
378 free ((char *) GFX.X2);
383 free ((char *) GFX.ZERO_OR_X2);
384 GFX.ZERO_OR_X2 = NULL;
388 free ((char *) GFX.ZERO);
393 void S9xBuildDirectColourMaps ()
395 for (uint32 p = 0; p < 8; p++)
397 for (uint32 c = 0; c < 256; c++)
400 DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
401 ((c & 0x38) >> 1) | (p & 2),
402 ((c & 0xc0) >> 3) | (p & 4));
405 IPPU.DirectColourMapsNeedRebuild = FALSE;
408 void S9xStartScreenRefresh()
410 if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0) {
411 free(GFX.InfoString);
412 GFX.InfoString = NULL;
417 if (IPPU.RenderThisFrame) {
418 if (!S9xInitUpdate()) {
419 IPPU.RenderThisFrame = FALSE;
423 IPPU.PreviousLine = IPPU.CurrentLine = 0;
424 IPPU.MaxBrightness = PPU.Brightness;
425 IPPU.LatchedBlanking = PPU.ForcedBlanking;
426 IPPU.LatchedInterlace = (Memory.FillRAM[0x2133] & 1);
427 IPPU.RenderedScreenWidth = 256;
428 IPPU.RenderedScreenHeight = PPU.ScreenHeight;
429 IPPU.DoubleWidthPixels = FALSE;
431 PPU.RecomputeClipWindows = TRUE;
435 void RenderLine (uint8 C)
437 if (IPPU.RenderThisFrame)
440 LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
441 LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
442 LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
443 LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
447 struct SLineMatrixData *p = &LineMatrixData [C];
448 p->MatrixA = PPU.MatrixA;
449 p->MatrixB = PPU.MatrixB;
450 p->MatrixC = PPU.MatrixC;
451 p->MatrixD = PPU.MatrixD;
452 p->CentreX = PPU.CentreX;
453 p->CentreY = PPU.CentreY;
458 if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
459 PPU.BG[2].HOffset == 0xe000)
461 LineData[C].BG[2].VOffset = 0xe1;
462 LineData[C].BG[2].HOffset = 0;
468 LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
469 LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
470 LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
471 LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
475 IPPU.CurrentLine = C + 1;
480 void S9xEndScreenRefresh()
482 IPPU.HDMAStarted = FALSE;
484 if (IPPU.RenderThisFrame) {
487 IPPU.RenderedFramesCount++;
489 if (IPPU.ColorsChanged) {
490 IPPU.ColorsChanged = FALSE;
493 if (Settings.DisplayFrameRate) {
494 S9xDisplayFrameRate();
497 if (GFX.InfoString) {
498 S9xDisplayString(GFX.InfoString);
501 S9xDeinitUpdate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight);
509 if (CPU.Flags & FRAME_ADVANCE_FLAG)
511 if (ICPU.FrameAdvanceCount)
513 ICPU.FrameAdvanceCount--;
514 IPPU.RenderThisFrame = TRUE;
519 CPU.Flags &= ~FRAME_ADVANCE_FLAG;
520 CPU.Flags |= DEBUG_MODE_FLAG;
525 if (CPU.SRAMModified)
527 if (!CPU.AutoSaveTimer)
529 if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
530 CPU.SRAMModified = FALSE;
534 if (!--CPU.AutoSaveTimer)
537 CPU.SRAMModified = FALSE;
543 void S9xSetInfoString (const char * fmt, ...)
548 if (vasprintf(&GFX.InfoString, fmt, ap) > 0) {
549 GFX.InfoStringTimeout = 120;
552 GFX.InfoStringTimeout = 0;
558 static inline void SelectTileRenderer (bool normal)
562 DrawTilePtr = DrawTile16;
563 DrawClippedTilePtr = DrawClippedTile16;
564 DrawLargePixelPtr = DrawLargePixel16;
568 if (GFX.r2131 & 0x80)
570 if (GFX.r2131 & 0x40)
574 DrawTilePtr = DrawTile16Sub1_2;
575 DrawClippedTilePtr = DrawClippedTile16Sub1_2;
579 // Fixed colour substraction
580 DrawTilePtr = DrawTile16FixedSub1_2;
581 DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
583 DrawLargePixelPtr = DrawLargePixel16Sub1_2;
587 DrawTilePtr = DrawTile16Sub;
588 DrawClippedTilePtr = DrawClippedTile16Sub;
589 DrawLargePixelPtr = DrawLargePixel16Sub;
594 if (GFX.r2131 & 0x40)
598 DrawTilePtr = DrawTile16Add1_2;
599 DrawClippedTilePtr = DrawClippedTile16Add1_2;
603 // Fixed colour addition
604 DrawTilePtr = DrawTile16FixedAdd1_2;
605 DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
607 DrawLargePixelPtr = DrawLargePixel16Add1_2;
611 DrawTilePtr = DrawTile16Add;
612 DrawClippedTilePtr = DrawClippedTile16Add;
613 DrawLargePixelPtr = DrawLargePixel16Add;
624 switch (PPU.OBJSizeSelect)
655 int FirstSprite = PPU.FirstSprite & 0x7f;
660 if (PPU.OBJ [S].Size)
665 long VPos = PPU.OBJ [S].VPos;
667 if (VPos >= PPU.ScreenHeight)
669 if (PPU.OBJ [S].HPos < 256 && PPU.OBJ [S].HPos > -Size &&
670 VPos < PPU.ScreenHeight && VPos > -Size)
672 GFX.OBJList [C++] = S;
674 GFX.VPositions[S] = VPos;
677 } while (S != FirstSprite);
679 // Terminate the list
680 GFX.OBJList [C] = -1;
681 IPPU.OBJChanged = FALSE;
684 static void DrawOBJS (bool OnMain = FALSE, uint8 D = 0)
687 uint32 BaseTile, Tile;
693 BG.TileAddress = PPU.OBJNameBase;
694 BG.StartPalette = 128;
697 BG.Buffer = IPPU.TileCache [TILE_4BIT];
698 BG.Buffered = IPPU.TileCached [TILE_4BIT];
699 BG.NameSelect = PPU.OBJNameSelect;
700 BG.DirectColourMode = FALSE;
705 for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
707 int VPos = GFX.VPositions [S];
708 int Size = GFX.Sizes[S];
712 if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
715 if (OnMain && SUB_OR_ADD(4))
717 SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
720 BaseTile = PPU.OBJ[S].Name | (PPU.OBJ[S].Palette << 10);
722 if (PPU.OBJ[S].HFlip)
724 BaseTile += ((Size >> 3) - 1) | H_FLIP;
727 if (PPU.OBJ[S].VFlip)
730 int clipcount = GFX.pCurrentClip->Count [4];
734 GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
736 for (int clip = 0; clip < clipcount; clip++)
740 if (!GFX.pCurrentClip->Count [4])
747 Left = GFX.pCurrentClip->Left [clip][4];
748 Right = GFX.pCurrentClip->Right [clip][4];
751 if (Right <= Left || PPU.OBJ[S].HPos + Size <= Left ||
752 PPU.OBJ[S].HPos >= Right)
755 for (int Y = 0; Y < Size; Y += 8)
757 if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
764 if ((StartLine = VPos + Y) < (int) GFX.StartY)
766 StartLine = GFX.StartY - StartLine;
767 LineCount = 8 - StartLine;
774 if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
775 if ((LineCount -= Last) <= 0)
778 TileLine = StartLine << 3;
779 O = (VPos + Y + StartLine) * GFX.PPL;
780 if (!PPU.OBJ[S].VFlip)
781 Tile = BaseTile + (Y << 1);
783 Tile = BaseTile + ((Size - Y - 8) << 1);
785 int Middle = Size >> 3;
786 if (PPU.OBJ[S].HPos < Left)
788 Tile += ((Left - PPU.OBJ[S].HPos) >> 3) * TileInc;
789 Middle -= (Left - PPU.OBJ[S].HPos) >> 3;
790 O += Left * GFX_PIX_SIZE;
791 if ((Offset = (Left - PPU.OBJ[S].HPos) & 7))
793 O -= Offset * GFX_PIX_SIZE;
795 int Width = Right - Left;
798 (*DrawClippedTilePtr) (Tile, O, Offset, W,
799 TileLine, LineCount);
805 O += 8 * GFX_PIX_SIZE;
809 O += PPU.OBJ[S].HPos * GFX_PIX_SIZE;
811 if (PPU.OBJ[S].HPos + Size >= Right)
813 Middle -= ((PPU.OBJ[S].HPos + Size + 7) -
815 Offset = (Right - (PPU.OBJ[S].HPos + Size)) & 7;
820 for (int X = 0; X < Middle; X++, O += 8 * GFX_PIX_SIZE,
823 (*DrawTilePtr) (Tile, O, TileLine, LineCount);
827 (*DrawClippedTilePtr) (Tile, O, 0, Offset,
828 TileLine, LineCount);
836 static void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
845 uint8 depths [2] = {Z1, Z2};
848 BG.StartPalette = bg << 5;
852 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
854 if (PPU.BG[bg].SCSize & 1)
859 if (PPU.BG[bg].SCSize & 2)
864 if (PPU.BG[bg].SCSize & 1)
873 if (BG.TileSize == 16)
884 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
886 uint32 VOffset = LineData [Y].BG[bg].VOffset;
887 uint32 HOffset = LineData [Y].BG[bg].HOffset;
888 uint32 MosaicOffset = Y % PPU.Mosaic;
890 for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
891 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
892 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
895 uint32 MosaicLine = VOffset + Y - MosaicOffset;
897 if (Y + Lines > GFX.EndY)
898 Lines = GFX.EndY + 1 - Y;
899 uint32 VirtAlign = (MosaicLine & 7) << 3;
904 uint32 ScreenLine = MosaicLine >> OffsetShift;
905 uint32 Rem16 = MosaicLine & 15;
907 if (ScreenLine & 0x20)
912 b1 += (ScreenLine & 0x1f) << 5;
913 b2 += (ScreenLine & 0x1f) << 5;
918 uint32 ClipCount = GFX.pCurrentClip->Count [bg];
919 uint32 HPos = HOffset;
920 uint32 PixWidth = PPU.Mosaic;
925 for (uint32 clip = 0; clip < ClipCount; clip++)
927 if (GFX.pCurrentClip->Count [bg])
929 Left = GFX.pCurrentClip->Left [clip][bg];
930 Right = GFX.pCurrentClip->Right [clip][bg];
931 uint32 r = Left % PPU.Mosaic;
932 HPos = HOffset + Left;
933 PixWidth = PPU.Mosaic - r;
935 uint32 s = Y * GFX.PPL + Left * GFX_PIX_SIZE;
936 for (uint32 x = Left; x < Right; x += PixWidth,
937 s += PixWidth * GFX_PIX_SIZE,
938 HPos += PixWidth, PixWidth = PPU.Mosaic)
940 uint32 Quot = (HPos & OffsetMask) >> 3;
942 if (x + PixWidth >= Right)
943 PixWidth = Right - x;
945 if (BG.TileSize == 8)
948 t = b2 + (Quot & 0x1f);
955 t = b2 + ((Quot >> 1) & 0x1f);
957 t = b1 + (Quot >> 1);
960 Tile = READ_2BYTES (t);
961 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
964 if (BG.TileSize != 8)
968 // Horizontal flip, but what about vertical flip ?
971 // Both horzontal & vertical flip
974 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
980 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
987 // Horizontal flip only
990 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
996 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1004 // No horizontal flip, but is there a vertical flip ?
1007 // Vertical flip only
1010 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1016 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1026 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1032 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1040 (*DrawLargePixelPtr) (Tile, s, HPos & 7, PixWidth,
1047 static void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1061 int VOffsetOffset = BGMode == 4 ? 0 : 32;
1062 uint8 depths [2] = {Z1, Z2};
1064 BG.StartPalette = 0;
1066 BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
1068 if (PPU.BG[2].SCSize & 1)
1073 if (PPU.BG[2].SCSize & 2)
1078 if (PPU.BG[2].SCSize & 1)
1083 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1085 if (PPU.BG[bg].SCSize & 1)
1090 if (PPU.BG[bg].SCSize & 2)
1094 if (PPU.BG[bg].SCSize & 1)
1099 static const int Lines = 1;
1102 int OffsetEnableMask = 1 << (bg + 13);
1104 if (BG.TileSize == 16)
1115 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
1117 uint32 VOff = LineData [Y].BG[2].VOffset;
1118 uint32 HOff = LineData [Y].BG[2].HOffset;
1120 int ScreenLine = VOff >> 3;
1127 if (ScreenLine & 0x20)
1128 s1 = BPS2, s2 = BPS3;
1130 s1 = BPS0, s2 = BPS1;
1132 s1 += (ScreenLine & 0x1f) << 5;
1133 s2 += (ScreenLine & 0x1f) << 5;
1135 int clipcount = GFX.pCurrentClip->Count [bg];
1139 for (int clip = 0; clip < clipcount; clip++)
1144 if (!GFX.pCurrentClip->Count [bg])
1151 Left = GFX.pCurrentClip->Left [clip][bg];
1152 Right = GFX.pCurrentClip->Right [clip][bg];
1160 uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
1171 uint32 TotalCount = 0;
1172 uint32 MaxCount = 8;
1174 uint32 s = Left * GFX_PIX_SIZE + Y * GFX.PPL;
1175 bool left_hand_edge = (Left == 0);
1176 Width = Right - Left;
1179 MaxCount = 8 - (Left & 7);
1181 while (Left < Right)
1185 // The SNES offset-per-tile background mode has a
1186 // hardware limitation that the offsets cannot be set
1187 // for the tile at the left-hand edge of the screen.
1188 VOffset = LineData [Y].BG[bg].VOffset;
1189 HOffset = LineHOffset;
1190 left_hand_edge = false;
1194 // All subsequent offset tile data is shifted left by one,
1195 // hence the - 1 below.
1196 Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
1199 s0 = s2 + (Quot2 & 0x1f);
1203 HCellOffset = READ_2BYTES (s0);
1207 VOffset = LineData [Y].BG[bg].VOffset;
1208 HOffset=LineHOffset;
1209 if ((HCellOffset & OffsetEnableMask))
1211 if (HCellOffset & 0x8000)
1212 VOffset = HCellOffset + 1;
1214 HOffset = HCellOffset;
1219 VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
1220 if ((VCellOffset & OffsetEnableMask))
1221 VOffset = VCellOffset + 1;
1223 VOffset = LineData [Y].BG[bg].VOffset;
1225 if ((HCellOffset & OffsetEnableMask))
1226 HOffset = (HCellOffset & ~7)|(LineHOffset&7);
1228 HOffset=LineHOffset;
1231 VirtAlign = ((Y + VOffset) & 7) << 3;
1232 ScreenLine = (VOffset + Y) >> OffsetShift;
1234 if (((VOffset + Y) & 15) > 7)
1245 if (ScreenLine & 0x20)
1250 b1 += (ScreenLine & 0x1f) << 5;
1251 b2 += (ScreenLine & 0x1f) << 5;
1253 HPos = (HOffset + Left) & OffsetMask;
1257 if (BG.TileSize == 8)
1260 t = b2 + (Quot & 0x1f);
1267 t = b2 + ((Quot >> 1) & 0x1f);
1269 t = b1 + (Quot >> 1);
1272 if (MaxCount + TotalCount > Width)
1273 MaxCount = Width - TotalCount;
1278 if (Count > MaxCount)
1281 s -= Offset * GFX_PIX_SIZE;
1282 Tile = READ_2BYTES(t);
1283 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1285 if (BG.TileSize == 8)
1286 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines);
1289 if (!(Tile & (V_FLIP | H_FLIP)))
1291 // Normal, unflipped
1292 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1293 s, Offset, Count, VirtAlign, Lines);
1301 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1302 s, Offset, Count, VirtAlign, Lines);
1307 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1308 s, Offset, Count, VirtAlign, Lines);
1314 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1315 s, Offset, Count, VirtAlign, Lines);
1320 TotalCount += Count;
1321 s += (Offset + Count) * GFX_PIX_SIZE;
1328 static void DrawBackgroundMode5 (uint32 /*BGMODE*/, uint32 bg, uint8 Z1, uint8 Z2)
1332 uint8 depths [2] = {Z1, Z2};
1341 BG.StartPalette = 0;
1343 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1345 if ((PPU.BG[bg].SCSize & 1))
1350 if ((PPU.BG[bg].SCSize & 2))
1355 if ((PPU.BG[bg].SCSize & 1))
1364 if (BG.TileSize == 16)
1366 VOffsetMask = 0x3ff;
1371 VOffsetMask = 0x1ff;
1374 int endy = GFX.EndY;
1376 for (int Y = GFX.StartY; Y <= endy; Y += Lines)
1379 uint32 VOffset = LineData [y].BG[bg].VOffset;
1380 uint32 HOffset = LineData [y].BG[bg].HOffset;
1381 int VirtAlign = (Y + VOffset) & 7;
1383 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1384 if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
1385 (HOffset != LineData [y + Lines].BG[bg].HOffset))
1389 if (Y + Lines > endy)
1390 Lines = endy + 1 - Y;
1392 int ScreenLine = (VOffset + Y) >> VOffsetShift;
1395 if (((VOffset + Y) & 15) > 7)
1408 if (ScreenLine & 0x20)
1413 b1 += (ScreenLine & 0x1f) << 5;
1414 b2 += (ScreenLine & 0x1f) << 5;
1416 int clipcount = GFX.pCurrentClip->Count [bg];
1419 for (int clip = 0; clip < clipcount; clip++)
1424 if (!GFX.pCurrentClip->Count [bg])
1431 Left = GFX.pCurrentClip->Left [clip][bg] * 2;
1432 Right = GFX.pCurrentClip->Right [clip][bg] * 2;
1438 intptr_t s = (Left>>1) * GFX_PIX_SIZE + Y * GFX.PPL;
1439 uint32 HPos = (HOffset + Left * GFX_PIX_SIZE) & 0x3ff;
1441 uint32 Quot = HPos >> 3;
1446 t = b2 + ((Quot >> 1) & 0x1f);
1448 t = b1 + (Quot >> 1);
1450 Width = Right - Left;
1451 // Left hand edge clipped tile
1454 int Offset = (HPos & 7);
1459 Tile = READ_2BYTES (t);
1460 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1462 if (BG.TileSize == 8)
1464 if (!(Tile & H_FLIP))
1466 // Normal, unflipped
1467 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1468 s, Offset, Count, VirtAlign, Lines);
1473 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1474 s, Offset, Count, VirtAlign, Lines);
1479 if (!(Tile & (V_FLIP | H_FLIP)))
1481 // Normal, unflipped
1482 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1483 s, Offset, Count, VirtAlign, Lines);
1491 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1492 s, Offset, Count, VirtAlign, Lines);
1497 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1498 s, Offset, Count, VirtAlign, Lines);
1504 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1505 s, Offset, Count, VirtAlign, Lines);
1512 else if (Quot == 127)
1518 // Middle, unclipped tiles
1519 Count = Width - Count;
1520 int Middle = Count >> 3;
1522 for (int C = Middle; C > 0; s += 4, Quot++, C--)
1524 Tile = READ_2BYTES(t);
1525 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1526 if (BG.TileSize == 8)
1528 if (!(Tile & H_FLIP))
1530 // Normal, unflipped
1531 (*DrawHiResTilePtr) (Tile + (Quot & 1),
1532 s, VirtAlign, Lines);
1537 (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1538 s, VirtAlign, Lines);
1543 if (!(Tile & (V_FLIP | H_FLIP)))
1545 // Normal, unflipped
1546 (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1547 s, VirtAlign, Lines);
1555 (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1556 s, VirtAlign, Lines);
1561 (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1562 s, VirtAlign, Lines);
1568 (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1569 s, VirtAlign, Lines);
1581 // Right-hand edge clipped tiles
1584 Tile = READ_2BYTES(t);
1585 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1586 if (BG.TileSize == 8)
1588 if (!(Tile & H_FLIP))
1590 // Normal, unflipped
1591 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1592 s, 0, Count, VirtAlign, Lines);
1597 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1598 s, 0, Count, VirtAlign, Lines);
1603 if (!(Tile & (V_FLIP | H_FLIP)))
1605 // Normal, unflipped
1606 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1607 s, 0, Count, VirtAlign, Lines);
1615 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1616 s, 0, Count, VirtAlign, Lines);
1621 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1622 s, 0, Count, VirtAlign, Lines);
1628 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1629 s, 0, Count, VirtAlign, Lines);
1637 static void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1639 BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1640 BG.BitShift = BitShifts[BGMode][bg];
1641 BG.TileShift = TileShifts[BGMode][bg];
1642 BG.TileAddress = PPU.BG[bg].NameBase << 1;
1644 BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1645 BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1646 BG.PaletteShift = PaletteShifts[BGMode][bg];
1647 BG.PaletteMask = PaletteMasks[BGMode][bg];
1648 BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1651 if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1653 DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1660 if (Settings.WrestlemaniaArcade)
1662 case 4: // Used by Puzzle Bobble
1663 DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1667 case 6: // XXX: is also offset per tile.
1668 DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1684 uint8 depths [2] = {Z1, Z2};
1687 BG.StartPalette = bg << 5;
1689 BG.StartPalette = 0;
1691 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1693 if (PPU.BG[bg].SCSize & 1)
1698 if (PPU.BG[bg].SCSize & 2)
1703 if (PPU.BG[bg].SCSize & 1)
1712 if (BG.TileSize == 16)
1723 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1725 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1726 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1727 int VirtAlign = (Y + VOffset) & 7;
1729 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1730 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1731 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1734 if (Y + Lines > GFX.EndY)
1735 Lines = GFX.EndY + 1 - Y;
1739 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1742 if (((VOffset + Y) & 15) > 7)
1755 if (ScreenLine & 0x20)
1760 b1 += (ScreenLine & 0x1f) << 5;
1761 b2 += (ScreenLine & 0x1f) << 5;
1763 int clipcount = GFX.pCurrentClip->Count [bg];
1766 for (int clip = 0; clip < clipcount; clip++)
1771 if (!GFX.pCurrentClip->Count [bg])
1778 Left = GFX.pCurrentClip->Left [clip][bg];
1779 Right = GFX.pCurrentClip->Right [clip][bg];
1785 intptr_t s = Left * GFX_PIX_SIZE + Y * GFX.PPL;
1786 uint32 HPos = (HOffset + Left) & OffsetMask;
1788 uint32 Quot = HPos >> 3;
1792 if (BG.TileSize == 8)
1795 t = b2 + (Quot & 0x1f);
1802 t = b2 + ((Quot >> 1) & 0x1f);
1804 t = b1 + (Quot >> 1);
1807 Width = Right - Left;
1808 // Left hand edge clipped tile
1811 uint32 Offset = (HPos & 7);
1815 s -= Offset * GFX_PIX_SIZE;
1816 Tile = READ_2BYTES(t);
1817 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1819 if (BG.TileSize == 8)
1821 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1826 if (!(Tile & (V_FLIP | H_FLIP)))
1828 // Normal, unflipped
1829 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1830 s, Offset, Count, VirtAlign, Lines);
1838 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1839 s, Offset, Count, VirtAlign, Lines);
1844 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1845 s, Offset, Count, VirtAlign, Lines);
1851 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
1852 Offset, Count, VirtAlign, Lines);
1856 if (BG.TileSize == 8)
1861 else if (Quot == 63)
1869 else if (Quot == 127)
1873 s += 8 * GFX_PIX_SIZE;
1876 // Middle, unclipped tiles
1877 Count = Width - Count;
1878 int Middle = Count >> 3;
1880 for (int C = Middle; C > 0; s += 8 * GFX_PIX_SIZE, Quot++, C--)
1882 Tile = READ_2BYTES(t);
1883 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1885 if (BG.TileSize != 8)
1889 // Horizontal flip, but what about vertical flip ?
1892 // Both horzontal & vertical flip
1893 (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
1898 // Horizontal flip only
1899 (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
1905 // No horizontal flip, but is there a vertical flip ?
1908 // Vertical flip only
1909 (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
1915 (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
1922 (*DrawTilePtr) (Tile, s, VirtAlign, Lines);
1925 if (BG.TileSize == 8)
1944 // Right-hand edge clipped tiles
1947 Tile = READ_2BYTES(t);
1948 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1950 if (BG.TileSize == 8)
1951 (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
1955 if (!(Tile & (V_FLIP | H_FLIP)))
1957 // Normal, unflipped
1958 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
1959 Count, VirtAlign, Lines);
1967 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1968 s, 0, Count, VirtAlign,
1974 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1975 s, 0, Count, VirtAlign,
1982 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1983 s, 0, Count, VirtAlign,
1992 #define RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
1993 const uint8 bmask = MASK; \
1994 for (int x = startx; x != endx; \
1995 x += (HFLIP ? -1 : 1), AA += aa, CC += cc, p++, d++) \
1997 int X = ((AA + BB) >> 8) & 0x3ff; \
1998 int Y = ((CC + DD) >> 8) & 0x3ff; \
1999 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2000 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2001 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2009 #define RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,CFILT) \
2010 register int AABB = AA + BB; \
2011 register int CCDD = CC + DD; \
2012 const uint8 bmask = MASK; \
2013 for (int x = startx; x != endx; \
2014 x += (HFLIP ? -1 : 1), AABB += aa, CCDD += cc, p++, d++) \
2016 register uint16 X = ((AABB) >> 8) CFILT; \
2017 register uint16 Y = ((CCDD) >> 8) CFILT; \
2019 if (((X | Y) & ~0x3ff) == 0) { \
2020 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2021 uint8 b = TileData[((Y & 7) << 4) + ((X & 7) << 1)]; \
2022 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2023 if (z > *d && b) { \
2027 } else if (REPEAT == 3) { \
2028 X = (x + HOffset) & 7; \
2029 Y = (yy + CentreY) & 7; \
2030 uint8 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2031 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2032 if (z > *d && b) { \
2039 #define RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,MASK,PRIOMASK) \
2040 for (uint32 clip = 0; clip < ClipCount; clip++) \
2042 if (GFX.pCurrentClip->Count [bg]) \
2044 Left = GFX.pCurrentClip->Left [clip][bg]; \
2045 Right = GFX.pCurrentClip->Right [clip][bg]; \
2046 if (Right <= Left) \
2049 register TYPE *p = (TYPE *) Screen + Left; \
2050 register uint8 *d = Depth + Left; \
2054 startx = Right - 1; \
2068 xx = startx + (HOffset - CentreX) % 1023; \
2070 xx = startx + HOffset - CentreX; \
2071 int AA = l->MatrixA * xx; \
2072 int CC = l->MatrixC * xx; \
2076 RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2077 } else if (DEZAEMON) { \
2078 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,& 0x7ff) \
2080 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,) \
2084 #ifdef USE_CRAZY_OPTS
2086 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON) \
2087 if (GFX.Mode7PriorityMask) { \
2088 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0x7f,0x80) \
2090 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0xff,0x00) \
2093 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,HFLIP) \
2094 if (Settings.Dezaemon && PPU.Mode7Repeat) { \
2095 switch (PPU.Mode7Repeat) { \
2096 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,1); break; \
2097 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,1); break; \
2098 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,1); break; \
2101 switch (PPU.Mode7Repeat) { \
2102 case 0: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,0,0); break; \
2103 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,0); break; \
2104 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,0); break; \
2105 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,0); break; \
2109 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC) \
2110 if (PPU.Mode7HFlip) { \
2111 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,1); \
2113 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,0); \
2116 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2117 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC)
2121 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2122 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,PPU.Mode7HFlip,PPU.Mode7Repeat,Settings.Dezaemon,GFX.Mode7Mask,GFX.Mode7PriorityMask)
2126 #define RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2127 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2131 int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2132 int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2134 int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2135 int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2137 if (PPU.Mode7VFlip) \
2138 yy = 261 - (int) Line; \
2142 if (PPU.Mode7Repeat == 0) \
2143 yy += (VOffset - CentreY) % 1023; \
2145 yy += VOffset - CentreY; \
2146 int BB = l->MatrixB * yy + (CentreX << 8); \
2147 int DD = l->MatrixD * yy + (CentreY << 8); \
2149 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2152 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2155 uint8 * const VRAM1 = Memory.VRAM + 1; \
2156 if (GFX.r2130 & 1) \
2158 if (IPPU.DirectColourMapsNeedRebuild) \
2159 S9xBuildDirectColourMaps (); \
2160 GFX.ScreenColors = DirectColourMaps [0]; \
2163 GFX.ScreenColors = IPPU.ScreenColors; \
2168 uint32 Right = 256; \
2169 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2174 Screen += GFX.StartY * GFX.Pitch; \
2175 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2176 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2177 RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2180 static void DrawBGMode7Background16 (uint8 *Screen, int bg)
2182 RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2185 static void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2187 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2188 (*(d + GFX.DepthDelta) != 1 ?
2189 COLOR_ADD (GFX.ScreenColors [b & bmask],
2191 COLOR_ADD (GFX.ScreenColors [b & bmask],
2193 GFX.ScreenColors [b & bmask]);
2196 static void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2198 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2199 (*(d + GFX.DepthDelta) != 1 ?
2200 COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2202 COLOR_ADD (GFX.ScreenColors [b & bmask],
2204 GFX.ScreenColors [b & bmask]);
2207 static void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2209 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2210 (*(d + GFX.DepthDelta) != 1 ?
2211 COLOR_SUB (GFX.ScreenColors [b & bmask],
2213 COLOR_SUB (GFX.ScreenColors [b & bmask],
2215 GFX.ScreenColors [b & bmask]);
2218 static void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2220 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2221 (*(d + GFX.DepthDelta) != 1 ?
2222 COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2224 COLOR_SUB (GFX.ScreenColors [b & bmask],
2226 GFX.ScreenColors [b & bmask]);
2229 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2232 uint8 *VRAM1 = Memory.VRAM + 1; \
2233 if (GFX.r2130 & 1) \
2235 if (IPPU.DirectColourMapsNeedRebuild) \
2236 S9xBuildDirectColourMaps (); \
2237 GFX.ScreenColors = DirectColourMaps [0]; \
2240 GFX.ScreenColors = IPPU.ScreenColors; \
2246 uint32 Right = 256; \
2247 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2252 Screen += GFX.StartY * GFX.Pitch; \
2253 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2254 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2255 bool allowSimpleCase = false; \
2256 if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2257 && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2258 && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2260 allowSimpleCase = true; \
2262 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2266 int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2267 int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2269 int CentreX = ((int) l->CentreX << M7) >> M7; \
2270 int CentreY = ((int) l->CentreY << M7) >> M7; \
2272 if (PPU.Mode7VFlip) \
2273 yy = 261 - (int) Line; \
2277 if (PPU.Mode7Repeat == 0) \
2278 yy += (VOffset - CentreY) % 1023; \
2280 yy += VOffset - CentreY; \
2281 bool simpleCase = false; \
2284 /* Make a special case for the identity matrix, since it's a common case and */ \
2285 /* can be done much more quickly without special effects */ \
2286 if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2288 BB = CentreX << 8; \
2289 DD = (yy + CentreY) << 8; \
2290 simpleCase = true; \
2294 BB = l->MatrixB * yy + (CentreX << 8); \
2295 DD = l->MatrixD * yy + (CentreY << 8); \
2298 for (uint32 clip = 0; clip < ClipCount; clip++) \
2300 if (GFX.pCurrentClip->Count [bg]) \
2302 Left = GFX.pCurrentClip->Left [clip][bg]; \
2303 Right = GFX.pCurrentClip->Right [clip][bg]; \
2304 if (Right <= Left) \
2307 TYPE *p = (TYPE *) Screen + Left; \
2308 uint8 *d = Depth + Left; \
2310 if (PPU.Mode7HFlip) \
2312 startx = Right - 1; \
2327 if (PPU.Mode7Repeat == 0) \
2328 xx = startx + (HOffset - CentreX) % 1023; \
2330 xx = startx + HOffset - CentreX; \
2338 AA = l->MatrixA * xx; \
2339 CC = l->MatrixC * xx; \
2343 if (!PPU.Mode7Repeat) \
2348 int X = ((AA + BB) >> 8) & 0x3ff; \
2349 int Y = (DD >> 8) & 0x3ff; \
2350 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2351 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2352 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2353 if (GFX.Z1 > *d && b) \
2355 TYPE theColor = COLORFUNC; \
2356 *p = (FUNC) | ALPHA_BITS_MASK; \
2359 AA += aa, p++, d++; \
2361 } while (x != endx); \
2367 int X = (AA + BB) >> 8; \
2370 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2376 if (((X | Y) & ~0x3ff) == 0) \
2378 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2379 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2380 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2381 if (GFX.Z1 > *d && b) \
2383 TYPE theColor = COLORFUNC; \
2384 *p = (FUNC) | ALPHA_BITS_MASK; \
2388 else if (PPU.Mode7Repeat == 3) \
2390 X = (x + HOffset) & 7; \
2391 Y = (yy + CentreY) & 7; \
2392 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2393 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2394 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2395 if (GFX.Z1 > *d && b) \
2397 TYPE theColor = COLORFUNC; \
2398 *p = (FUNC) | ALPHA_BITS_MASK; \
2402 AA += aa; p++; d++; \
2404 } while (x != endx); \
2407 else if (!PPU.Mode7Repeat) \
2409 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2410 /* the location of one point in the _sampled_ image, and weight them according */ \
2411 /* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
2414 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2415 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2416 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2417 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2418 /* You can think of this as a kind of mipmapping. */ \
2419 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2421 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2423 uint32 xPos = AA + BB; \
2424 uint32 xPix = xPos >> 8; \
2425 uint32 yPos = CC + DD; \
2426 uint32 yPix = yPos >> 8; \
2427 uint32 X = xPix & 0x3ff; \
2428 uint32 Y = yPix & 0x3ff; \
2429 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2430 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2431 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2432 if (GFX.Z1 > *d && b) \
2434 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2435 uint32 X10 = (xPix + dir) & 0x3ff; \
2436 uint32 Y01 = (yPix + dir) & 0x3ff; \
2437 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2438 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2439 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2440 uint32 p1 = COLORFUNC; \
2441 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2442 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2443 uint32 p2 = COLORFUNC; \
2444 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2445 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2446 uint32 p4 = COLORFUNC; \
2447 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2448 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2449 uint32 p3 = COLORFUNC; \
2450 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2451 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2452 uint32 Xdel = (xPos >> 3) & 0x1F; \
2453 uint32 Ydel = (yPos >> 3) & 0x1F; \
2454 uint32 XY = (Xdel*Ydel) >> 5; \
2455 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2456 uint32 area2 = Xdel - XY; \
2457 uint32 area3 = Ydel - XY; \
2458 uint32 area4 = XY; \
2459 uint32 tempColor = ((area1 * p1) + \
2462 (area4 * p4)) >> 5; \
2463 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2464 *p = (FUNC) | ALPHA_BITS_MASK; \
2470 /* The oversampling method: get the colors at four corners of a square */ \
2471 /* in the _displayed_ image, and average them. It's sharp and clean, but */ \
2472 /* gives the usual huge pixels when the source image gets "close." */ \
2474 /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2475 uint32 aaDelX = aa >> 1; \
2476 uint32 ccDelX = cc >> 1; \
2477 uint32 bbDelY = l->MatrixB >> 1; \
2478 uint32 ddDelY = l->MatrixD >> 1; \
2479 /* Offset the location within the source image so that the four sampled points */ \
2480 /* center around where the single point would otherwise have been drawn. */ \
2481 BB -= (bbDelY >> 1); \
2482 DD -= (ddDelY >> 1); \
2483 AA -= (aaDelX >> 1); \
2484 CC -= (ccDelX >> 1); \
2485 uint32 BB10 = BB + aaDelX; \
2486 uint32 BB01 = BB + bbDelY; \
2487 uint32 BB11 = BB + aaDelX + bbDelY; \
2488 uint32 DD10 = DD + ccDelX; \
2489 uint32 DD01 = DD + ddDelY; \
2490 uint32 DD11 = DD + ccDelX + ddDelY; \
2491 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2493 uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2494 uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2495 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2496 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2497 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2498 if (GFX.Z1 > *d && b) \
2500 /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2501 /* source image that we're going to examine. */ \
2502 uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2503 uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2504 uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2505 uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2506 uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2507 uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2508 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2509 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2510 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2511 TYPE p1 = COLORFUNC; \
2512 b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2513 TYPE p2 = COLORFUNC; \
2514 b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2515 TYPE p3 = COLORFUNC; \
2516 b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2517 TYPE p4 = COLORFUNC; \
2518 TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2519 *p = (FUNC) | ALPHA_BITS_MASK; \
2527 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2529 uint32 xPos = AA + BB; \
2530 uint32 xPix = xPos >> 8; \
2531 uint32 yPos = CC + DD; \
2532 uint32 yPix = yPos >> 8; \
2537 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2543 if (((X | Y) & ~0x3ff) == 0) \
2545 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2546 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2547 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2548 if (GFX.Z1 > *d && b) \
2550 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2551 uint32 X10 = (xPix + dir) & 0x3ff; \
2552 uint32 Y01 = (yPix + dir) & 0x3ff; \
2553 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2554 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2555 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2556 uint32 p1 = COLORFUNC; \
2557 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2558 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2559 uint32 p2 = COLORFUNC; \
2560 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2561 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2562 uint32 p4 = COLORFUNC; \
2563 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2564 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2565 uint32 p3 = COLORFUNC; \
2566 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2567 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2568 uint32 Xdel = (xPos >> 3) & 0x1F; \
2569 uint32 Ydel = (yPos >> 3) & 0x1F; \
2570 uint32 XY = (Xdel*Ydel) >> 5; \
2571 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2572 uint32 area2 = Xdel - XY; \
2573 uint32 area3 = Ydel - XY; \
2574 uint32 area4 = XY; \
2575 uint32 tempColor = ((area1 * p1) + \
2578 (area4 * p4)) >> 5; \
2579 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2580 *p = (FUNC) | ALPHA_BITS_MASK; \
2586 if (PPU.Mode7Repeat == 3) \
2588 X = (x + HOffset) & 7; \
2589 Y = (yy + CentreY) & 7; \
2590 uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2591 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2592 if (GFX.Z1 > *d && b) \
2594 TYPE theColor = COLORFUNC; \
2595 *p = (FUNC) | ALPHA_BITS_MASK; \
2605 static inline uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2607 register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2608 ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2609 ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2610 ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2611 register uint32 y = (A & TWO_LOW_BITS_MASK) +
2612 (B & TWO_LOW_BITS_MASK) +
2613 (C & TWO_LOW_BITS_MASK) +
2614 (D & TWO_LOW_BITS_MASK);
2615 y = (y>>2) & TWO_LOW_BITS_MASK;
2619 static void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2621 RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2624 static void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2626 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2627 (*(d + GFX.DepthDelta) != 1 ?
2628 (COLOR_ADD (theColor,
2630 (COLOR_ADD (theColor,
2631 GFX.FixedColour))) :
2632 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2635 static void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2637 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2638 (*(d + GFX.DepthDelta) != 1 ?
2639 COLOR_ADD1_2 (theColor,
2641 COLOR_ADD (theColor,
2643 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2646 static void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2648 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2649 (*(d + GFX.DepthDelta) != 1 ?
2650 COLOR_SUB (theColor,
2652 COLOR_SUB (theColor,
2654 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2657 static void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2659 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2660 (*(d + GFX.DepthDelta) != 1 ?
2661 COLOR_SUB1_2 (theColor,
2663 COLOR_SUB (theColor,
2665 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2668 #define _BUILD_SETUP(F) \
2669 GFX.BuildPixel = BuildPixel##F; \
2670 GFX.BuildPixel2 = BuildPixel2##F; \
2671 GFX.DecomposePixel = DecomposePixel##F; \
2672 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2673 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2674 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2675 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2676 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2677 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2678 MAX_RED = MAX_RED_##F; \
2679 MAX_GREEN = MAX_GREEN_##F; \
2680 MAX_BLUE = MAX_BLUE_##F; \
2681 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2682 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2683 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2684 GREEN_LOW_BIT_MASK_##F | \
2685 BLUE_LOW_BIT_MASK_##F); \
2686 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2687 GREEN_HI_BIT_MASK_##F | \
2688 BLUE_HI_BIT_MASK_##F); \
2689 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2690 GREEN_HI_BIT_MASK_##F | \
2691 BLUE_HI_BIT_MASK_##F) << 1); \
2692 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2693 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2694 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2695 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2696 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2697 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2698 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2699 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2700 ~TWO_LOW_BITS_MASK ) >> 2);
2702 static void RenderScreen(uint8 *Screen, bool sub, bool force_no_add, uint8 D)
2704 bool BG0, BG1, BG2, BG3, OB;
2710 GFX.pCurrentClip = &IPPU.Clip [0];
2711 BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2712 BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2713 BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2714 BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2715 OB = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2719 GFX.pCurrentClip = &IPPU.Clip [1];
2720 BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2721 BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2722 BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2723 BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2724 OB = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2727 sub |= force_no_add;
2729 if (PPU.BGMode <= 1)
2733 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2738 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2739 DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2743 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2744 DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2748 SelectTileRenderer (sub || !SUB_OR_ADD(2));
2749 DrawBackground (PPU.BGMode, 2, D + 3,
2750 (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2752 if (BG3 && PPU.BGMode == 0)
2754 SelectTileRenderer (sub || !SUB_OR_ADD(3));
2755 DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2758 else if (PPU.BGMode != 7)
2762 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2767 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2768 DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2770 if (PPU.BGMode != 6 && BG1)
2772 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2773 DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2780 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2783 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2787 if (Memory.FillRAM [0x2133] & 0x40)
2789 GFX.Mode7Mask = 0x7f;
2790 GFX.Mode7PriorityMask = 0x80;
2791 Mode7Depths [0] = 5 + D;
2792 Mode7Depths [1] = 9 + D;
2797 GFX.Mode7Mask = 0xff;
2798 GFX.Mode7PriorityMask = 0;
2799 Mode7Depths [0] = 5 + D;
2800 Mode7Depths [1] = 5 + D;
2803 if (sub || !SUB_OR_ADD(0))
2805 if (!Settings.Mode7Interpolate)
2806 DrawBGMode7Background16 (Screen, bg);
2808 DrawBGMode7Background16_i (Screen, bg);
2812 if (GFX.r2131 & 0x80)
2814 if (GFX.r2131 & 0x40)
2816 if (!Settings.Mode7Interpolate)
2817 DrawBGMode7Background16Sub1_2 (Screen, bg);
2819 DrawBGMode7Background16Sub1_2_i (Screen, bg);
2823 if (!Settings.Mode7Interpolate)
2824 DrawBGMode7Background16Sub (Screen, bg);
2826 DrawBGMode7Background16Sub_i (Screen, bg);
2831 if (GFX.r2131 & 0x40)
2833 if (!Settings.Mode7Interpolate)
2834 DrawBGMode7Background16Add1_2 (Screen, bg);
2836 DrawBGMode7Background16Add1_2_i (Screen, bg);
2840 if (!Settings.Mode7Interpolate)
2841 DrawBGMode7Background16Add (Screen, bg);
2843 DrawBGMode7Background16Add_i (Screen, bg);
2853 static void DisplayChar(uint8 *Screen, uint8 c)
2855 int line = (((c & 0x7f) - 32) >> 4) * font_height;
2856 int offset = (((c & 0x7f) - 32) & 15) * font_width;
2859 uint16 *s = (uint16 *) Screen;
2860 for (h = 0; h < font_height; h++, line++,
2861 s += GFX.PPL - font_width)
2863 for (w = 0; w < font_width; w++, s++)
2865 uint8 p = font [line][offset + w];
2876 static void S9xDisplayFrameRate()
2878 const unsigned int char_width = (font_width - 1) * sizeof (uint16);
2879 uint8 *Screen = GFX.Screen + 2 +
2880 (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch;
2884 if (Settings.TurboMode) {
2885 len = sprintf(string, "%u",
2886 IPPU.DisplayedRenderedFrameCount);
2888 len = sprintf(string, "%2u/%02u",
2889 IPPU.DisplayedRenderedFrameCount,
2890 (unsigned int) Memory.ROMFramesPerSecond);
2893 for (int i = 0; i < len; i++) {
2894 DisplayChar(Screen, string[i]);
2895 Screen += char_width;
2899 static void S9xDisplayString(const char *string)
2901 const unsigned int char_width = (font_width - 1) * sizeof (uint16);
2902 uint8 *Screen = GFX.Screen + 2 +
2903 (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch;
2904 int len = strlen (string);
2905 int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
2909 for (i = 0; i < len; i++, char_count++)
2911 if (char_count >= max_chars || string [i] < 32)
2913 Screen -= char_width * max_chars;
2914 Screen += font_height * GFX.Pitch;
2915 if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
2917 char_count -= max_chars;
2919 if (string [i] < 32)
2921 DisplayChar (Screen, string [i]);
2922 Screen += char_width;
2926 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
2932 unsigned char *memoryfillram = Memory.FillRAM;
2934 // get local copies of vid registers to be used later
2935 GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN
2936 GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
2937 GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
2938 GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
2940 // If external sync is off and
2941 // main screens have not been configured the same as the sub screen and
2942 // color addition and subtraction has been diabled then
2944 // anything else it is 0
2945 GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
2946 (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
2947 (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
2949 // If sprite data has been changed then go through and
2950 // refresh the sprites.
2951 if (IPPU.OBJChanged)
2956 if (PPU.RecomputeClipWindows)
2958 ComputeClipWindows ();
2959 PPU.RecomputeClipWindows = FALSE;
2962 GFX.StartY = IPPU.PreviousLine;
2963 if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
2964 GFX.EndY = PPU.ScreenHeight - 1;
2966 uint32 starty = GFX.StartY;
2967 uint32 endy = GFX.EndY;
2969 #ifndef RC_OPTIMIZED
2970 if (Settings.SupportHiRes &&
2971 (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace)) {
2972 if (PPU.BGMode == 5 || PPU.BGMode == 6) {
2973 IPPU.RenderedScreenWidth = 512;
2977 if (IPPU.LatchedInterlace) {
2978 starty = GFX.StartY * 2;
2979 endy = GFX.EndY * 2 + 1;
2982 if (!IPPU.DoubleWidthPixels) {
2983 // The game has switched from lo-res to hi-res mode part way down
2984 // the screen. Scale any existing lo-res pixels on screen
2985 for (register uint32 y = 0; y < GFX.StartY; y++) {
2986 register uint16 *p =
2987 (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
2988 register uint16 *q =
2989 (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
2990 for (register int x = 255; x >= 0; x--, p--, q -= 2) {
2995 IPPU.DoubleWidthPixels = TRUE;
2998 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3000 uint32 black = BLACK | (BLACK << 16);
3002 // Are we worrying about transparencies?
3003 if (Settings.Transparency)
3007 GFX.r2131 = 0x5f; //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3008 GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3009 Memory.FillRAM [0x212d]) & 15;
3010 GFX.r212c &= ~GFX.r212d; // make sure the main BG reg is the reverse of the sub BG reg
3011 GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3014 // Check to see if any transparency effects are currently in use
3015 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3016 (GFX.r2130 & 0x30) != 0x30 &&
3017 !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3019 // transparency effects in use, so lets get busy!
3020 struct ClipData *pClip;
3022 GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3023 IPPU.XB [PPU.FixedColourGreen],
3024 IPPU.XB [PPU.FixedColourBlue]);
3025 fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3026 // Clear the z-buffer, marking areas 'covered' by the fixed
3027 // colour as depth 1.
3028 pClip = &IPPU.Clip [1];
3030 // Clear the z-buffer
3032 if (pClip->Count [5])
3035 // Colour window enabled.
3037 for (uint32 y = starty; y <= endy; y++)
3039 ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3040 IPPU.RenderedScreenWidth);
3041 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3042 IPPU.RenderedScreenWidth);
3044 if (IPPU.Clip [0].Count [5])
3046 memset ((GFX.SubScreen + y * GFX.Pitch), black, IPPU.RenderedScreenWidth);
3048 for (uint32 c = 0; c < pClip->Count [5]; c++)
3050 if (pClip->Right [c][5] > pClip->Left [c][5])
3052 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3053 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3054 if (IPPU.Clip [0].Count [5])
3056 // Blast, have to clear the sub-screen to the fixed-colour
3057 // because there is a colour window in effect clipping
3058 // the main screen that will allow the sub-screen
3059 // 'underneath' to show through.
3060 memset ((GFX.SubScreen + y * GFX.Pitch) + pClip->Left [c][5] * x2,
3062 pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3068 #else // NOT RC_OPTIMIZED
3069 // loop around all of the lines being updated
3070 for (uint32 y = starty; y <= endy; y++)
3072 // Clear the subZbuffer
3073 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3074 IPPU.RenderedScreenWidth>>2);
3075 // Clear the Zbuffer
3076 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3077 IPPU.RenderedScreenWidth>>2);
3079 // if there is clipping then clear subscreen to a black color
3080 if (IPPU.Clip [0].Count [5])
3082 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch), black, IPPU.RenderedScreenWidth>>1);
3085 // loop through all window clippings
3086 for (uint32 c = 0; c < pClip->Count [5]; c++)
3088 if (pClip->Right [c][5] > pClip->Left [c][5])
3090 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3091 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3092 if (IPPU.Clip [0].Count [5])
3094 // Blast, have to clear the sub-screen to the fixed-colour
3095 // because there is a colour window in effect clipping
3096 // the main screen that will allow the sub-screen
3097 // 'underneath' to show through.
3099 register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch);
3100 register uint16 *q = p + pClip->Right [c][5] * x2;
3101 p += pClip->Left [c][5] * x2;
3104 *p++ = (uint16) GFX.FixedColour;
3114 // No windows are clipping the main screen
3115 // this simplifies the screen clearing process
3118 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3121 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3122 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3126 for (uint32 y = starty; y <= endy; y++)
3128 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3129 IPPU.RenderedScreenWidth);
3130 memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3131 IPPU.RenderedScreenWidth);
3135 if (IPPU.Clip [0].Count [5])
3137 // Blast, have to clear the sub-screen to the fixed-colour
3138 // because there is a colour window in effect clipping
3139 // the main screen that will allow the sub-screen
3140 // 'underneath' to show through.
3141 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3143 memset ((GFX.SubScreen + starty * GFX.Pitch),
3144 GFX.FixedColour | (GFX.FixedColour << 16),
3145 GFX.Pitch * (endy - starty - 1));
3149 for (uint32 y = starty; y <= endy; y++)
3151 memset ((GFX.SubScreen + y * GFX.Pitch),
3152 GFX.FixedColour | (GFX.FixedColour << 16),
3153 IPPU.RenderedScreenWidth);
3158 #else // NOT RC_OPTIMIZED
3159 // loop through all of the lines to be updated
3160 for (uint32 y = starty; y <= endy; y++)
3162 // Clear the Zbuffer
3163 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3164 IPPU.RenderedScreenWidth>>2);
3165 // clear the sub Zbuffer to 1
3166 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3167 IPPU.RenderedScreenWidth>>2);
3168 if (IPPU.Clip [0].Count [5])
3170 // Blast, have to clear the sub-screen to the fixed-colour
3171 // because there is a colour window in effect clipping
3172 // the main screen that will allow the sub-screen
3173 // 'underneath' to show through.
3176 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch), fixedColour,
3177 IPPU.RenderedScreenWidth>>1);
3184 if (ANYTHING_ON_SUB)
3186 GFX.DB = GFX.SubZBuffer;
3187 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3190 if (IPPU.Clip [0].Count [5])
3192 for (uint32 y = starty; y <= endy; y++)
3194 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch);
3195 register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3196 register uint8 *e = d + SNES_WIDTH;
3201 *p = *(p + GFX.Delta);
3210 GFX.DB = GFX.ZBuffer;
3211 RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3214 uint32 back = IPPU.ScreenColors [0];
3219 pClip = &IPPU.Clip [0];
3221 for (uint32 y = starty; y <= endy; y++)
3223 if (!(Count = pClip->Count [5]))
3230 for (uint32 b = 0; b < Count; b++)
3232 if (pClip->Count [5])
3234 Left = pClip->Left [b][5] * x2;
3235 Right = pClip->Right [b][5] * x2;
3240 if (GFX.r2131 & 0x80)
3242 if (GFX.r2131 & 0x40)
3244 // Subtract, halving the result.
3245 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3246 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3247 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3248 register uint8 *e = d + Right;
3249 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3259 *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3274 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3275 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3276 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3277 register uint8 *e = d + Right;
3278 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3288 *p = COLOR_SUB (back, *(p + GFX.Delta));
3302 if (GFX.r2131 & 0x40)
3304 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3305 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3306 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3307 register uint8 *e = d + Right;
3308 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3317 *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3332 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3333 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3334 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3335 register uint8 *e = d + Right;
3336 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3345 *p = COLOR_ADD (back, *(p + GFX.Delta));
3359 if (!pClip->Count [5])
3361 // The backdrop has not been cleared yet - so
3362 // copy the sub-screen to the main screen
3363 // or fill it with the back-drop colour if the
3364 // sub-screen is clear.
3365 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3366 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3367 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3368 register uint8 *e = d + Right;
3377 *p = *(p + GFX.Delta);
3379 *p = GFX.FixedColour;
3396 // Subscreen not being added to back
3397 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3398 pClip = &IPPU.Clip [0];
3400 if (pClip->Count [5])
3402 for (uint32 y = starty; y <= endy; y++)
3404 for (uint32 b = 0; b < pClip->Count [5]; b++)
3406 uint32 Left = pClip->Left [b][5] * x2;
3407 uint32 Right = pClip->Right [b][5] * x2;
3408 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3409 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3410 register uint8 *e = d + Right;
3424 for (uint32 y = starty; y <= endy; y++)
3426 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch);
3427 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3428 register uint8 *e = d + 256 * x2;
3448 // 16bit and transparency but currently no transparency effects in
3451 // get the back colour of the current screen
3452 uint32 back = IPPU.ScreenColors [0] |
3453 (IPPU.ScreenColors [0] << 16);
3455 // if forceblanking in use then use black instead of the back color
3456 if (PPU.ForcedBlanking)
3459 // not sure what Clip is used for yet
3460 // could be a check to see if there is any clipping present?
3461 if (IPPU.Clip [0].Count[5])
3465 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3467 memset (GFX.Screen + starty * GFX.Pitch, black,
3468 GFX.Pitch * (endy - starty - 1));
3472 for (uint32 y = starty; y <= endy; y++)
3474 memset (GFX.Screen + y * GFX.Pitch, black,
3478 for (uint32 y = starty; y <= endy; y++)
3480 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3482 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3485 memset ((GFX.Screen + y * GFX.Pitch) + IPPU.Clip [0].Left [c][5] * x2,
3487 IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3492 // loop through all of the lines that are going to be updated as part of this screen update
3493 for (uint32 y = starty; y <= endy; y++)
3495 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), black,
3496 IPPU.RenderedScreenWidth>>1);
3500 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3502 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3504 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch); // get pointer to current line in screen buffer
3505 register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3506 p += IPPU.Clip [0].Left [c][5] * x2;
3509 *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3519 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3521 memset (GFX.Screen + starty * GFX.Pitch, back,
3522 GFX.Pitch * (endy - starty - 1));
3526 for (uint32 y = starty; y <= endy; y++)
3528 memset (GFX.Screen + y * GFX.Pitch, back,
3533 // there is no clipping to worry about so just fill with the back colour
3534 for (uint32 y = starty; y <= endy; y++)
3536 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), back,
3537 IPPU.RenderedScreenWidth>>1);
3542 // If Forced blanking is not in effect
3543 if (!PPU.ForcedBlanking)
3546 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3548 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3549 GFX.ZPitch * (endy - starty - 1));
3553 for (uint32 y = starty; y <= endy; y++)
3555 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3560 // Clear the Zbuffer for each of the lines which are going to be updated
3561 for (uint32 y = starty; y <= endy; y++)
3563 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3567 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3568 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3572 else // Transparencys are disabled, ahh lovely ... nice and easy.
3574 // get back colour to be used in clearing the screen
3575 register uint32 back;
3576 if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3577 (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3579 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3580 (IPPU.XB[PPU.FixedColourGreen] << 6) |
3581 (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3582 back = (back << 16) | back;
3586 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3589 // if Forcedblanking in use then back colour becomes black
3590 if (PPU.ForcedBlanking)
3594 SelectTileRenderer (TRUE); //selects the tile renderers to be used
3595 // TRUE means to use the default
3596 // FALSE means use best renderer based on current
3597 // graphics register settings
3600 // now clear all graphics lines which are being updated using the back colour
3601 for (register uint32 y = starty; y <= endy; y++)
3603 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), back,
3604 IPPU.RenderedScreenWidth>>1);
3607 if (!PPU.ForcedBlanking)
3609 // Loop through all lines being updated and clear the
3610 // zbuffer for each of the lines
3611 for (uint32 y = starty; y <= endy; y++)
3613 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3614 IPPU.RenderedScreenWidth>>2);
3616 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3617 GFX.pCurrentClip = &IPPU.Clip [0];
3619 // Define an inline function to handle clipping
3620 #define FIXCLIP(n) \
3621 if (GFX.r212c & (1 << (n))) \
3622 GFX.pCurrentClip = &IPPU.Clip [0]; \
3624 GFX.pCurrentClip = &IPPU.Clip [1]
3626 // Define an inline function to handle which BGs are being displayed
3627 #define DISPLAY(n) \
3629 (!(PPU.BG_Forced & n) && (GFX.r212c & n)) || \
3630 (((GFX.r212d & n) && subadd)) \
3633 uint8 subadd = GFX.r2131 & 0x3f;
3635 // go through all BGS are check if they need to be displayed
3636 bool BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3637 bool BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3638 bool BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3639 bool BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3640 bool OB = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3642 if (PPU.BGMode <= 1)
3644 // screen modes 0 and 1
3653 DrawBackground (PPU.BGMode, 0, 10, 14);
3658 DrawBackground (PPU.BGMode, 1, 9, 13);
3663 DrawBackground (PPU.BGMode, 2, 3,
3664 (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3666 if (BG3 && PPU.BGMode == 0)
3669 DrawBackground (PPU.BGMode, 3, 2, 5);
3672 else if (PPU.BGMode != 7)
3674 // screen modes 2 and up but not mode 7
3683 DrawBackground (PPU.BGMode, 0, 5, 13);
3685 if (BG1 && PPU.BGMode != 6)
3688 DrawBackground (PPU.BGMode, 1, 2, 9);
3699 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3703 if (Memory.FillRAM [0x2133] & 0x40)
3705 GFX.Mode7Mask = 0x7f;
3706 GFX.Mode7PriorityMask = 0x80;
3707 Mode7Depths [0] = 5;
3708 Mode7Depths [1] = 9;
3713 GFX.Mode7Mask = 0xff;
3714 GFX.Mode7PriorityMask = 0;
3715 Mode7Depths [0] = 5;
3716 Mode7Depths [1] = 5;
3720 if (!Settings.Mode7Interpolate)
3722 DrawBGMode7Background16 (GFX.Screen, bg);
3726 DrawBGMode7Background16_i (GFX.Screen, bg);
3732 #ifndef RC_OPTIMIZE // no hi res
3733 if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3735 if (IPPU.DoubleWidthPixels)
3737 // Mixure of background modes used on screen - scale width
3738 // of all non-mode 5 and 6 pixels.
3739 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3741 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3742 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3743 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3748 if (IPPU.LatchedInterlace)
3750 // Interlace is enabled - double the height of all non-mode 5 and 6
3752 for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3754 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch),
3755 (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch),
3761 IPPU.PreviousLine = IPPU.CurrentLine;
3764 #ifdef GFX_MULTI_FORMAT
3766 #define _BUILD_PIXEL(F) \
3767 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
3769 return (BUILD_PIXEL_##F(R,G,B)); \
3771 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
3773 return (BUILD_PIXEL2_##F(R,G,B)); \
3775 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
3777 DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
3780 _BUILD_PIXEL(RGB565)
3781 _BUILD_PIXEL(RGB555)
3782 _BUILD_PIXEL(BGR565)
3783 _BUILD_PIXEL(BGR555)
3784 _BUILD_PIXEL(GBR565)
3785 _BUILD_PIXEL(GBR555)
3786 _BUILD_PIXEL(RGB5551)
3788 bool8 S9xSetRenderPixelFormat (int format)
3790 extern uint32 current_graphic_format;
3792 current_graphic_format = format;
3797 _BUILD_SETUP(RGB565)
3800 _BUILD_SETUP(RGB555)
3803 _BUILD_SETUP(BGR565)
3806 _BUILD_SETUP(BGR555)
3809 _BUILD_SETUP(GBR565)
3812 _BUILD_SETUP(GBR555)
3815 _BUILD_SETUP(RGB5551)