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.
56 #define USE_CRAZY_OPTS
61 #define GFX_PIX_SIZE 1
63 void ComputeClipWindows();
64 static void S9xDisplayFrameRate();
65 static void S9xDisplayString(const char *string);
67 extern uint8 BitShifts[8][4];
68 extern uint8 TileShifts[8][4];
69 extern uint8 PaletteShifts[8][4];
70 extern uint8 PaletteMasks[8][4];
71 extern uint8 Depths[8][4];
72 extern uint8 BGSizes [2];
74 extern NormalTileRenderer DrawTilePtr;
75 extern ClippedTileRenderer DrawClippedTilePtr;
76 extern NormalTileRenderer DrawHiResTilePtr;
77 extern ClippedTileRenderer DrawHiResClippedTilePtr;
78 extern LargePixelRenderer DrawLargePixelPtr;
82 extern struct SLineData LineData[240];
83 extern struct SLineMatrixData LineMatrixData [240];
85 extern uint8 Mode7Depths [2];
88 (GFX.r212c & (1 << (N)) && \
89 !(PPU.BG_Forced & (1 << (N))))
91 #define SUB_OR_ADD(N) \
92 (GFX.r2131 & (1 << (N)))
95 ((GFX.r2130 & 0x30) != 0x30 && \
97 (GFX.r212d & (1 << N)) && \
98 !(PPU.BG_Forced & (1 << (N))))
100 #define ANYTHING_ON_SUB \
101 ((GFX.r2130 & 0x30) != 0x30 && \
105 #define ADD_OR_SUB_ON_ANYTHING \
108 #define BLACK BUILD_PIXEL(0,0,0)
110 bool8_32 S9xGraphicsInit ()
112 register uint32 PixelOdd = 1;
113 register uint32 PixelEven = 2;
115 #ifdef GFX_MULTI_FORMAT
116 if (GFX.BuildPixel == NULL)
117 S9xSetRenderPixelFormat (RGB565);
120 for (uint8 bitshift = 0; bitshift < 4; bitshift++)
122 for (register int i = 0; i < 16; i++)
124 register uint32 h = 0;
125 register uint32 l = 0;
127 #if defined(LSB_FIRST)
146 h |= (PixelOdd << 24);
148 h |= (PixelOdd << 16);
150 h |= (PixelOdd << 8);
154 l |= (PixelOdd << 24);
156 l |= (PixelOdd << 16);
158 l |= (PixelOdd << 8);
163 odd_high[bitshift][i] = h;
164 odd_low[bitshift][i] = l;
167 #if defined(LSB_FIRST)
173 h |= PixelEven << 16;
175 h |= PixelEven << 24;
181 l |= PixelEven << 16;
183 l |= PixelEven << 24;
186 h |= (PixelEven << 24);
188 h |= (PixelEven << 16);
190 h |= (PixelEven << 8);
194 l |= (PixelEven << 24);
196 l |= (PixelEven << 16);
198 l |= (PixelEven << 8);
203 even_high[bitshift][i] = h;
204 even_low[bitshift][i] = l;
210 GFX.InfoStringTimeout = 0;
211 GFX.InfoString = NULL;
214 IPPU.OBJChanged = TRUE;
215 if (Settings.Transparency)
216 Settings.SixteenBit = TRUE;
218 IPPU.DirectColourMapsNeedRebuild = TRUE;
219 if (Settings.SixteenBit) {
220 DrawTilePtr = DrawTile16;
221 DrawClippedTilePtr = DrawClippedTile16;
222 DrawLargePixelPtr = DrawLargePixel16;
223 DrawHiResTilePtr= DrawHiResTile16;
224 DrawHiResClippedTilePtr = DrawHiResClippedTile16;
226 DrawTilePtr = DrawTile;
227 DrawClippedTilePtr = DrawClippedTile;
228 DrawLargePixelPtr = DrawLargePixel;
229 DrawHiResTilePtr = DrawTile;
230 DrawHiResClippedTilePtr = DrawClippedTile;
232 S9xFixColourBrightness();
234 if (Settings.SixteenBit)
236 if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
239 if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
240 !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
244 free ((char *) GFX.ZERO_OR_X2);
245 GFX.ZERO_OR_X2 = NULL;
249 free ((char *) GFX.X2);
256 // Build a lookup table that multiplies a packed RGB value by 2 with
258 for (r = 0; r <= MAX_RED; r++)
263 for (g = 0; g <= MAX_GREEN; g++)
268 for (b = 0; b <= MAX_BLUE; b++)
273 GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
274 GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
278 ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
279 ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
280 // Build a lookup table that if the top bit of the color value is zero
281 // then the value is zero, otherwise multiply the value by 2. Used by
282 // the color subtraction code.
284 #if defined(OLD_COLOUR_BLENDING)
285 for (r = 0; r <= MAX_RED; r++)
288 if ((r2 & 0x10) == 0)
291 r2 = (r2 << 1) & MAX_RED;
293 for (g = 0; g <= MAX_GREEN; g++)
296 if ((g2 & GREEN_HI_BIT) == 0)
299 g2 = (g2 << 1) & MAX_GREEN;
301 for (b = 0; b <= MAX_BLUE; b++)
304 if ((b2 & 0x10) == 0)
307 b2 = (b2 << 1) & MAX_BLUE;
309 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
310 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
315 for (r = 0; r <= MAX_RED; r++)
318 if ((r2 & 0x10) == 0)
321 r2 = (r2 << 1) & MAX_RED;
325 for (g = 0; g <= MAX_GREEN; g++)
328 if ((g2 & GREEN_HI_BIT) == 0)
331 g2 = (g2 << 1) & MAX_GREEN;
335 for (b = 0; b <= MAX_BLUE; b++)
338 if ((b2 & 0x10) == 0)
341 b2 = (b2 << 1) & MAX_BLUE;
345 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
346 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
352 // Build a lookup table that if the top bit of the color value is zero
353 // then the value is zero, otherwise its just the value.
354 for (r = 0; r <= MAX_RED; r++)
357 if ((r2 & 0x10) == 0)
362 for (g = 0; g <= MAX_GREEN; g++)
365 if ((g2 & GREEN_HI_BIT) == 0)
369 for (b = 0; b <= MAX_BLUE; b++)
372 if ((b2 & 0x10) == 0)
377 GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
378 GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
386 GFX.ZERO_OR_X2 = NULL;
393 void S9xGraphicsDeinit (void)
395 // Free any memory allocated in S9xGraphicsInit
398 free ((char *) GFX.X2);
403 free ((char *) GFX.ZERO_OR_X2);
404 GFX.ZERO_OR_X2 = NULL;
408 free ((char *) GFX.ZERO);
413 void S9xBuildDirectColourMaps ()
415 for (uint32 p = 0; p < 8; p++)
417 for (uint32 c = 0; c < 256; c++)
420 DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
421 ((c & 0x38) >> 1) | (p & 2),
422 ((c & 0xc0) >> 3) | (p & 4));
425 IPPU.DirectColourMapsNeedRebuild = FALSE;
428 void S9xStartScreenRefresh()
430 if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0) {
431 free(GFX.InfoString);
432 GFX.InfoString = NULL;
437 if (IPPU.RenderThisFrame) {
438 if (!S9xInitUpdate()) {
439 IPPU.RenderThisFrame = FALSE;
443 IPPU.PreviousLine = IPPU.CurrentLine = 0;
444 IPPU.MaxBrightness = PPU.Brightness;
445 IPPU.LatchedBlanking = PPU.ForcedBlanking;
446 IPPU.LatchedInterlace = (Memory.FillRAM[0x2133] & 1);
447 IPPU.RenderedScreenWidth = 256;
448 IPPU.RenderedScreenHeight = PPU.ScreenHeight;
449 IPPU.DoubleWidthPixels = FALSE;
451 PPU.RecomputeClipWindows = TRUE;
455 void RenderLine (uint8 C)
457 if (IPPU.RenderThisFrame)
460 LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
461 LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
462 LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
463 LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
467 struct SLineMatrixData *p = &LineMatrixData [C];
468 p->MatrixA = PPU.MatrixA;
469 p->MatrixB = PPU.MatrixB;
470 p->MatrixC = PPU.MatrixC;
471 p->MatrixD = PPU.MatrixD;
472 p->CentreX = PPU.CentreX;
473 p->CentreY = PPU.CentreY;
478 if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
479 PPU.BG[2].HOffset == 0xe000)
481 LineData[C].BG[2].VOffset = 0xe1;
482 LineData[C].BG[2].HOffset = 0;
488 LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
489 LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
490 LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
491 LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
495 IPPU.CurrentLine = C + 1;
500 void S9xEndScreenRefresh()
502 IPPU.HDMAStarted = FALSE;
504 if (IPPU.RenderThisFrame) {
507 IPPU.RenderedFramesCount++;
509 if (IPPU.ColorsChanged) {
510 uint32 saved = PPU.CGDATA[0];
512 if (!Settings.SixteenBit) {
513 // Hack for Super Mario World - to get its sky blue
514 // (It uses Fixed colour addition on the backdrop colour)
515 if (!(Memory.FillRAM [0x2131] & 0x80) &&
516 (Memory.FillRAM[0x2131] & 0x20) &&
517 (PPU.FixedColourRed || PPU.FixedColourGreen ||
518 PPU.FixedColourBlue)) {
519 PPU.CGDATA[0] = PPU.FixedColourRed |
520 (PPU.FixedColourGreen << 5) |
521 (PPU.FixedColourBlue << 10);
525 IPPU.ColorsChanged = FALSE;
527 PPU.CGDATA[0] = saved;
530 if (Settings.DisplayFrameRate) {
531 S9xDisplayFrameRate();
534 if (GFX.InfoString) {
535 S9xDisplayString(GFX.InfoString);
539 IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
540 Settings.SixteenBit);
548 if (CPU.Flags & FRAME_ADVANCE_FLAG)
550 if (ICPU.FrameAdvanceCount)
552 ICPU.FrameAdvanceCount--;
553 IPPU.RenderThisFrame = TRUE;
558 CPU.Flags &= ~FRAME_ADVANCE_FLAG;
559 CPU.Flags |= DEBUG_MODE_FLAG;
564 if (CPU.SRAMModified)
566 if (!CPU.AutoSaveTimer)
568 if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
569 CPU.SRAMModified = FALSE;
573 if (!--CPU.AutoSaveTimer)
576 CPU.SRAMModified = FALSE;
582 void S9xSetInfoString (const char * fmt, ...)
587 if (vasprintf(&GFX.InfoString, fmt, ap) > 0) {
588 GFX.InfoStringTimeout = 120;
591 GFX.InfoStringTimeout = 0;
597 INLINE void SelectTileRenderer (bool8_32 normal)
601 DrawTilePtr = DrawTile16;
602 DrawClippedTilePtr = DrawClippedTile16;
603 DrawLargePixelPtr = DrawLargePixel16;
607 if (GFX.r2131 & 0x80)
609 if (GFX.r2131 & 0x40)
613 DrawTilePtr = DrawTile16Sub1_2;
614 DrawClippedTilePtr = DrawClippedTile16Sub1_2;
618 // Fixed colour substraction
619 DrawTilePtr = DrawTile16FixedSub1_2;
620 DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
622 DrawLargePixelPtr = DrawLargePixel16Sub1_2;
626 DrawTilePtr = DrawTile16Sub;
627 DrawClippedTilePtr = DrawClippedTile16Sub;
628 DrawLargePixelPtr = DrawLargePixel16Sub;
633 if (GFX.r2131 & 0x40)
637 DrawTilePtr = DrawTile16Add1_2;
638 DrawClippedTilePtr = DrawClippedTile16Add1_2;
642 // Fixed colour addition
643 DrawTilePtr = DrawTile16FixedAdd1_2;
644 DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
646 DrawLargePixelPtr = DrawLargePixel16Add1_2;
650 DrawTilePtr = DrawTile16Add;
651 DrawClippedTilePtr = DrawClippedTile16Add;
652 DrawLargePixelPtr = DrawLargePixel16Add;
663 switch (PPU.OBJSizeSelect)
694 int FirstSprite = PPU.FirstSprite & 0x7f;
699 if (PPU.OBJ [S].Size)
704 long VPos = PPU.OBJ [S].VPos;
706 if (VPos >= PPU.ScreenHeight)
708 if (PPU.OBJ [S].HPos < 256 && PPU.OBJ [S].HPos > -Size &&
709 VPos < PPU.ScreenHeight && VPos > -Size)
711 GFX.OBJList [C++] = S;
713 GFX.VPositions[S] = VPos;
716 } while (S != FirstSprite);
718 // Terminate the list
719 GFX.OBJList [C] = -1;
720 IPPU.OBJChanged = FALSE;
723 void DrawOBJS (bool8_32 OnMain = FALSE, uint8 D = 0)
726 uint32 BaseTile, Tile;
732 BG.TileAddress = PPU.OBJNameBase;
733 BG.StartPalette = 128;
736 BG.Buffer = IPPU.TileCache [TILE_4BIT];
737 BG.Buffered = IPPU.TileCached [TILE_4BIT];
738 BG.NameSelect = PPU.OBJNameSelect;
739 BG.DirectColourMode = FALSE;
744 for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
746 int VPos = GFX.VPositions [S];
747 int Size = GFX.Sizes[S];
751 if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
754 if (OnMain && SUB_OR_ADD(4))
756 SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
759 BaseTile = PPU.OBJ[S].Name | (PPU.OBJ[S].Palette << 10);
761 if (PPU.OBJ[S].HFlip)
763 BaseTile += ((Size >> 3) - 1) | H_FLIP;
766 if (PPU.OBJ[S].VFlip)
769 int clipcount = GFX.pCurrentClip->Count [4];
773 GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
775 for (int clip = 0; clip < clipcount; clip++)
779 if (!GFX.pCurrentClip->Count [4])
786 Left = GFX.pCurrentClip->Left [clip][4];
787 Right = GFX.pCurrentClip->Right [clip][4];
790 if (Right <= Left || PPU.OBJ[S].HPos + Size <= Left ||
791 PPU.OBJ[S].HPos >= Right)
794 for (int Y = 0; Y < Size; Y += 8)
796 if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
803 if ((StartLine = VPos + Y) < (int) GFX.StartY)
805 StartLine = GFX.StartY - StartLine;
806 LineCount = 8 - StartLine;
813 if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
814 if ((LineCount -= Last) <= 0)
817 TileLine = StartLine << 3;
818 O = (VPos + Y + StartLine) * GFX.PPL;
819 if (!PPU.OBJ[S].VFlip)
820 Tile = BaseTile + (Y << 1);
822 Tile = BaseTile + ((Size - Y - 8) << 1);
824 int Middle = Size >> 3;
825 if (PPU.OBJ[S].HPos < Left)
827 Tile += ((Left - PPU.OBJ[S].HPos) >> 3) * TileInc;
828 Middle -= (Left - PPU.OBJ[S].HPos) >> 3;
829 O += Left * GFX_PIX_SIZE;
830 if ((Offset = (Left - PPU.OBJ[S].HPos) & 7))
832 O -= Offset * GFX_PIX_SIZE;
834 int Width = Right - Left;
837 (*DrawClippedTilePtr) (Tile, O, Offset, W,
838 TileLine, LineCount);
844 O += 8 * GFX_PIX_SIZE;
848 O += PPU.OBJ[S].HPos * GFX_PIX_SIZE;
850 if (PPU.OBJ[S].HPos + Size >= Right)
852 Middle -= ((PPU.OBJ[S].HPos + Size + 7) -
854 Offset = (Right - (PPU.OBJ[S].HPos + Size)) & 7;
859 for (int X = 0; X < Middle; X++, O += 8 * GFX_PIX_SIZE,
862 (*DrawTilePtr) (Tile, O, TileLine, LineCount);
866 (*DrawClippedTilePtr) (Tile, O, 0, Offset,
867 TileLine, LineCount);
875 void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
884 uint8 depths [2] = {Z1, Z2};
887 BG.StartPalette = bg << 5;
891 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
893 if (PPU.BG[bg].SCSize & 1)
898 if (PPU.BG[bg].SCSize & 2)
903 if (PPU.BG[bg].SCSize & 1)
912 if (BG.TileSize == 16)
923 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
925 uint32 VOffset = LineData [Y].BG[bg].VOffset;
926 uint32 HOffset = LineData [Y].BG[bg].HOffset;
927 uint32 MosaicOffset = Y % PPU.Mosaic;
929 for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
930 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
931 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
934 uint32 MosaicLine = VOffset + Y - MosaicOffset;
936 if (Y + Lines > GFX.EndY)
937 Lines = GFX.EndY + 1 - Y;
938 uint32 VirtAlign = (MosaicLine & 7) << 3;
943 uint32 ScreenLine = MosaicLine >> OffsetShift;
944 uint32 Rem16 = MosaicLine & 15;
946 if (ScreenLine & 0x20)
951 b1 += (ScreenLine & 0x1f) << 5;
952 b2 += (ScreenLine & 0x1f) << 5;
957 uint32 ClipCount = GFX.pCurrentClip->Count [bg];
958 uint32 HPos = HOffset;
959 uint32 PixWidth = PPU.Mosaic;
964 for (uint32 clip = 0; clip < ClipCount; clip++)
966 if (GFX.pCurrentClip->Count [bg])
968 Left = GFX.pCurrentClip->Left [clip][bg];
969 Right = GFX.pCurrentClip->Right [clip][bg];
970 uint32 r = Left % PPU.Mosaic;
971 HPos = HOffset + Left;
972 PixWidth = PPU.Mosaic - r;
974 uint32 s = Y * GFX.PPL + Left * GFX_PIX_SIZE;
975 for (uint32 x = Left; x < Right; x += PixWidth,
976 s += PixWidth * GFX_PIX_SIZE,
977 HPos += PixWidth, PixWidth = PPU.Mosaic)
979 uint32 Quot = (HPos & OffsetMask) >> 3;
981 if (x + PixWidth >= Right)
982 PixWidth = Right - x;
984 if (BG.TileSize == 8)
987 t = b2 + (Quot & 0x1f);
994 t = b2 + ((Quot >> 1) & 0x1f);
996 t = b1 + (Quot >> 1);
999 Tile = READ_2BYTES (t);
1000 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1003 if (BG.TileSize != 8)
1007 // Horizontal flip, but what about vertical flip ?
1010 // Both horzontal & vertical flip
1013 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1019 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1026 // Horizontal flip only
1029 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1035 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1043 // No horizontal flip, but is there a vertical flip ?
1046 // Vertical flip only
1049 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1055 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1065 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1071 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1079 (*DrawLargePixelPtr) (Tile, s, HPos & 7, PixWidth,
1086 void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1100 int VOffsetOffset = BGMode == 4 ? 0 : 32;
1101 uint8 depths [2] = {Z1, Z2};
1103 BG.StartPalette = 0;
1105 BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
1107 if (PPU.BG[2].SCSize & 1)
1112 if (PPU.BG[2].SCSize & 2)
1117 if (PPU.BG[2].SCSize & 1)
1122 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1124 if (PPU.BG[bg].SCSize & 1)
1129 if (PPU.BG[bg].SCSize & 2)
1133 if (PPU.BG[bg].SCSize & 1)
1138 static const int Lines = 1;
1141 int OffsetEnableMask = 1 << (bg + 13);
1143 if (BG.TileSize == 16)
1154 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
1156 uint32 VOff = LineData [Y].BG[2].VOffset;
1157 uint32 HOff = LineData [Y].BG[2].HOffset;
1159 int ScreenLine = VOff >> 3;
1166 if (ScreenLine & 0x20)
1167 s1 = BPS2, s2 = BPS3;
1169 s1 = BPS0, s2 = BPS1;
1171 s1 += (ScreenLine & 0x1f) << 5;
1172 s2 += (ScreenLine & 0x1f) << 5;
1174 int clipcount = GFX.pCurrentClip->Count [bg];
1178 for (int clip = 0; clip < clipcount; clip++)
1183 if (!GFX.pCurrentClip->Count [bg])
1190 Left = GFX.pCurrentClip->Left [clip][bg];
1191 Right = GFX.pCurrentClip->Right [clip][bg];
1199 uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
1210 uint32 TotalCount = 0;
1211 uint32 MaxCount = 8;
1213 uint32 s = Left * GFX_PIX_SIZE + Y * GFX.PPL;
1214 bool8_32 left_hand_edge = (Left == 0);
1215 Width = Right - Left;
1218 MaxCount = 8 - (Left & 7);
1220 while (Left < Right)
1224 // The SNES offset-per-tile background mode has a
1225 // hardware limitation that the offsets cannot be set
1226 // for the tile at the left-hand edge of the screen.
1227 VOffset = LineData [Y].BG[bg].VOffset;
1228 HOffset = LineHOffset;
1229 left_hand_edge = FALSE;
1233 // All subsequent offset tile data is shifted left by one,
1234 // hence the - 1 below.
1235 Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
1238 s0 = s2 + (Quot2 & 0x1f);
1242 HCellOffset = READ_2BYTES (s0);
1246 VOffset = LineData [Y].BG[bg].VOffset;
1247 HOffset=LineHOffset;
1248 if ((HCellOffset & OffsetEnableMask))
1250 if (HCellOffset & 0x8000)
1251 VOffset = HCellOffset + 1;
1253 HOffset = HCellOffset;
1258 VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
1259 if ((VCellOffset & OffsetEnableMask))
1260 VOffset = VCellOffset + 1;
1262 VOffset = LineData [Y].BG[bg].VOffset;
1264 if ((HCellOffset & OffsetEnableMask))
1265 HOffset = (HCellOffset & ~7)|(LineHOffset&7);
1267 HOffset=LineHOffset;
1270 VirtAlign = ((Y + VOffset) & 7) << 3;
1271 ScreenLine = (VOffset + Y) >> OffsetShift;
1273 if (((VOffset + Y) & 15) > 7)
1284 if (ScreenLine & 0x20)
1289 b1 += (ScreenLine & 0x1f) << 5;
1290 b2 += (ScreenLine & 0x1f) << 5;
1292 HPos = (HOffset + Left) & OffsetMask;
1296 if (BG.TileSize == 8)
1299 t = b2 + (Quot & 0x1f);
1306 t = b2 + ((Quot >> 1) & 0x1f);
1308 t = b1 + (Quot >> 1);
1311 if (MaxCount + TotalCount > Width)
1312 MaxCount = Width - TotalCount;
1317 if (Count > MaxCount)
1320 s -= Offset * GFX_PIX_SIZE;
1321 Tile = READ_2BYTES(t);
1322 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1324 if (BG.TileSize == 8)
1325 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines);
1328 if (!(Tile & (V_FLIP | H_FLIP)))
1330 // Normal, unflipped
1331 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1332 s, Offset, Count, VirtAlign, Lines);
1340 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1341 s, Offset, Count, VirtAlign, Lines);
1346 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1347 s, Offset, Count, VirtAlign, Lines);
1353 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1354 s, Offset, Count, VirtAlign, Lines);
1359 TotalCount += Count;
1360 s += (Offset + Count) * GFX_PIX_SIZE;
1367 void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
1371 uint8 depths [2] = {Z1, Z2};
1380 BG.StartPalette = 0;
1382 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1384 if ((PPU.BG[bg].SCSize & 1))
1389 if ((PPU.BG[bg].SCSize & 2))
1394 if ((PPU.BG[bg].SCSize & 1))
1403 if (BG.TileSize == 16)
1405 VOffsetMask = 0x3ff;
1410 VOffsetMask = 0x1ff;
1413 int endy = GFX.EndY;
1415 for (int Y = GFX.StartY; Y <= endy; Y += Lines)
1418 uint32 VOffset = LineData [y].BG[bg].VOffset;
1419 uint32 HOffset = LineData [y].BG[bg].HOffset;
1420 int VirtAlign = (Y + VOffset) & 7;
1422 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1423 if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
1424 (HOffset != LineData [y + Lines].BG[bg].HOffset))
1428 if (Y + Lines > endy)
1429 Lines = endy + 1 - Y;
1431 int ScreenLine = (VOffset + Y) >> VOffsetShift;
1434 if (((VOffset + Y) & 15) > 7)
1447 if (ScreenLine & 0x20)
1452 b1 += (ScreenLine & 0x1f) << 5;
1453 b2 += (ScreenLine & 0x1f) << 5;
1455 int clipcount = GFX.pCurrentClip->Count [bg];
1458 for (int clip = 0; clip < clipcount; clip++)
1463 if (!GFX.pCurrentClip->Count [bg])
1470 Left = GFX.pCurrentClip->Left [clip][bg] * 2;
1471 Right = GFX.pCurrentClip->Right [clip][bg] * 2;
1477 uint32 s = (Left>>1) * GFX_PIX_SIZE + Y * GFX.PPL;
1478 uint32 HPos = (HOffset + Left * GFX_PIX_SIZE) & 0x3ff;
1480 uint32 Quot = HPos >> 3;
1485 t = b2 + ((Quot >> 1) & 0x1f);
1487 t = b1 + (Quot >> 1);
1489 Width = Right - Left;
1490 // Left hand edge clipped tile
1493 int Offset = (HPos & 7);
1497 if (s) // XXX: Workaround for underflow (Secret of MANA)
1499 Tile = READ_2BYTES (t);
1500 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1502 if (BG.TileSize == 8)
1504 if (!(Tile & H_FLIP))
1506 // Normal, unflipped
1507 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1508 s, Offset, Count, VirtAlign, Lines);
1513 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1514 s, Offset, Count, VirtAlign, Lines);
1519 if (!(Tile & (V_FLIP | H_FLIP)))
1521 // Normal, unflipped
1522 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1523 s, Offset, Count, VirtAlign, Lines);
1531 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1532 s, Offset, Count, VirtAlign, Lines);
1537 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1538 s, Offset, Count, VirtAlign, Lines);
1544 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1545 s, Offset, Count, VirtAlign, Lines);
1552 else if (Quot == 127)
1558 // Middle, unclipped tiles
1559 Count = Width - Count;
1560 int Middle = Count >> 3;
1562 for (int C = Middle; C > 0; s += 4, Quot++, C--)
1564 Tile = READ_2BYTES(t);
1565 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1566 if (BG.TileSize == 8)
1568 if (!(Tile & H_FLIP))
1570 // Normal, unflipped
1571 (*DrawHiResTilePtr) (Tile + (Quot & 1),
1572 s, VirtAlign, Lines);
1577 (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1578 s, VirtAlign, Lines);
1583 if (!(Tile & (V_FLIP | H_FLIP)))
1585 // Normal, unflipped
1586 (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1587 s, VirtAlign, Lines);
1595 (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1596 s, VirtAlign, Lines);
1601 (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1602 s, VirtAlign, Lines);
1608 (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1609 s, VirtAlign, Lines);
1621 // Right-hand edge clipped tiles
1624 Tile = READ_2BYTES(t);
1625 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1626 if (BG.TileSize == 8)
1628 if (!(Tile & H_FLIP))
1630 // Normal, unflipped
1631 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1632 s, 0, Count, VirtAlign, Lines);
1637 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1638 s, 0, Count, VirtAlign, Lines);
1643 if (!(Tile & (V_FLIP | H_FLIP)))
1645 // Normal, unflipped
1646 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1647 s, 0, Count, VirtAlign, Lines);
1655 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1656 s, 0, Count, VirtAlign, Lines);
1661 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1662 s, 0, Count, VirtAlign, Lines);
1668 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1669 s, 0, Count, VirtAlign, Lines);
1677 void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1679 BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1680 BG.BitShift = BitShifts[BGMode][bg];
1681 BG.TileShift = TileShifts[BGMode][bg];
1682 BG.TileAddress = PPU.BG[bg].NameBase << 1;
1684 BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1685 BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1686 BG.PaletteShift = PaletteShifts[BGMode][bg];
1687 BG.PaletteMask = PaletteMasks[BGMode][bg];
1688 BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1691 if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1693 DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1700 if (Settings.WrestlemaniaArcade)
1702 case 4: // Used by Puzzle Bobble
1703 DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1707 case 6: // XXX: is also offset per tile.
1708 DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1724 uint8 depths [2] = {Z1, Z2};
1727 BG.StartPalette = bg << 5;
1729 BG.StartPalette = 0;
1731 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1733 if (PPU.BG[bg].SCSize & 1)
1738 if (PPU.BG[bg].SCSize & 2)
1743 if (PPU.BG[bg].SCSize & 1)
1752 if (BG.TileSize == 16)
1763 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1765 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1766 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1767 int VirtAlign = (Y + VOffset) & 7;
1769 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1770 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1771 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1774 if (Y + Lines > GFX.EndY)
1775 Lines = GFX.EndY + 1 - Y;
1779 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1782 if (((VOffset + Y) & 15) > 7)
1795 if (ScreenLine & 0x20)
1800 b1 += (ScreenLine & 0x1f) << 5;
1801 b2 += (ScreenLine & 0x1f) << 5;
1803 int clipcount = GFX.pCurrentClip->Count [bg];
1806 for (int clip = 0; clip < clipcount; clip++)
1811 if (!GFX.pCurrentClip->Count [bg])
1818 Left = GFX.pCurrentClip->Left [clip][bg];
1819 Right = GFX.pCurrentClip->Right [clip][bg];
1825 uint32 s = Left * GFX_PIX_SIZE + Y * GFX.PPL;
1826 uint32 HPos = (HOffset + Left) & OffsetMask;
1828 uint32 Quot = HPos >> 3;
1832 if (BG.TileSize == 8)
1835 t = b2 + (Quot & 0x1f);
1842 t = b2 + ((Quot >> 1) & 0x1f);
1844 t = b1 + (Quot >> 1);
1847 Width = Right - Left;
1848 // Left hand edge clipped tile
1851 uint32 Offset = (HPos & 7);
1855 s -= Offset * GFX_PIX_SIZE;
1856 Tile = READ_2BYTES(t);
1857 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1859 if (BG.TileSize == 8)
1861 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1866 if (!(Tile & (V_FLIP | H_FLIP)))
1868 // Normal, unflipped
1869 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1870 s, Offset, Count, VirtAlign, Lines);
1878 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1879 s, Offset, Count, VirtAlign, Lines);
1884 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1885 s, Offset, Count, VirtAlign, Lines);
1891 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
1892 Offset, Count, VirtAlign, Lines);
1896 if (BG.TileSize == 8)
1901 else if (Quot == 63)
1909 else if (Quot == 127)
1913 s += 8 * GFX_PIX_SIZE;
1916 // Middle, unclipped tiles
1917 Count = Width - Count;
1918 int Middle = Count >> 3;
1920 for (int C = Middle; C > 0; s += 8 * GFX_PIX_SIZE, Quot++, C--)
1922 Tile = READ_2BYTES(t);
1923 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1925 if (BG.TileSize != 8)
1929 // Horizontal flip, but what about vertical flip ?
1932 // Both horzontal & vertical flip
1933 (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
1938 // Horizontal flip only
1939 (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
1945 // No horizontal flip, but is there a vertical flip ?
1948 // Vertical flip only
1949 (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
1955 (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
1962 (*DrawTilePtr) (Tile, s, VirtAlign, Lines);
1965 if (BG.TileSize == 8)
1984 // Right-hand edge clipped tiles
1987 Tile = READ_2BYTES(t);
1988 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1990 if (BG.TileSize == 8)
1991 (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
1995 if (!(Tile & (V_FLIP | H_FLIP)))
1997 // Normal, unflipped
1998 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
1999 Count, VirtAlign, Lines);
2007 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2008 s, 0, Count, VirtAlign,
2014 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2015 s, 0, Count, VirtAlign,
2022 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
2023 s, 0, Count, VirtAlign,
2032 #define RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2033 const uint8 bmask = MASK; \
2034 for (int x = startx; x != endx; \
2035 x += (HFLIP ? -1 : 1), AA += aa, CC += cc, p++, d++) \
2037 int X = ((AA + BB) >> 8) & 0x3ff; \
2038 int Y = ((CC + DD) >> 8) & 0x3ff; \
2039 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2040 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2041 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2049 #define RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,CFILT) \
2050 register int AABB = AA + BB; \
2051 register int CCDD = CC + DD; \
2052 const uint8 bmask = MASK; \
2053 for (int x = startx; x != endx; \
2054 x += (HFLIP ? -1 : 1), AABB += aa, CCDD += cc, p++, d++) \
2056 register uint16 X = ((AABB) >> 8) CFILT; \
2057 register uint16 Y = ((CCDD) >> 8) CFILT; \
2059 if (((X | Y) & ~0x3ff) == 0) { \
2060 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2061 uint8 b = TileData[((Y & 7) << 4) + ((X & 7) << 1)]; \
2062 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2063 if (z > *d && b) { \
2067 } else if (REPEAT == 3) { \
2068 X = (x + HOffset) & 7; \
2069 Y = (yy + CentreY) & 7; \
2070 uint8 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2071 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2072 if (z > *d && b) { \
2079 #define RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,MASK,PRIOMASK) \
2080 for (uint32 clip = 0; clip < ClipCount; clip++) \
2082 if (GFX.pCurrentClip->Count [bg]) \
2084 Left = GFX.pCurrentClip->Left [clip][bg]; \
2085 Right = GFX.pCurrentClip->Right [clip][bg]; \
2086 if (Right <= Left) \
2089 register TYPE *p = (TYPE *) Screen + Left; \
2090 register uint8 *d = Depth + Left; \
2094 startx = Right - 1; \
2108 xx = startx + (HOffset - CentreX) % 1023; \
2110 xx = startx + HOffset - CentreX; \
2111 int AA = l->MatrixA * xx; \
2112 int CC = l->MatrixC * xx; \
2116 RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2117 } else if (DEZAEMON) { \
2118 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,& 0x7ff) \
2120 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,) \
2124 #ifdef USE_CRAZY_OPTS
2126 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON) \
2127 if (GFX.Mode7PriorityMask) { \
2128 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0x7f,0x80) \
2130 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0xff,0x00) \
2133 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,HFLIP) \
2134 if (Settings.Dezaemon && PPU.Mode7Repeat) { \
2135 switch (PPU.Mode7Repeat) { \
2136 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,1); break; \
2137 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,1); break; \
2138 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,1); break; \
2141 switch (PPU.Mode7Repeat) { \
2142 case 0: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,0,0); break; \
2143 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,0); break; \
2144 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,0); break; \
2145 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,0); break; \
2149 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC) \
2150 if (PPU.Mode7HFlip) { \
2151 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,1); \
2153 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,0); \
2156 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2157 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC)
2161 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2162 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,PPU.Mode7HFlip,PPU.Mode7Repeat,Settings.Dezaemon,GFX.Mode7Mask,GFX.Mode7PriorityMask)
2166 #define RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2167 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2171 int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2172 int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2174 int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2175 int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2177 if (PPU.Mode7VFlip) \
2178 yy = 261 - (int) Line; \
2182 if (PPU.Mode7Repeat == 0) \
2183 yy += (VOffset - CentreY) % 1023; \
2185 yy += VOffset - CentreY; \
2186 int BB = l->MatrixB * yy + (CentreX << 8); \
2187 int DD = l->MatrixD * yy + (CentreY << 8); \
2189 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2192 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2195 uint8 * const VRAM1 = Memory.VRAM + 1; \
2196 if (GFX.r2130 & 1) \
2198 if (IPPU.DirectColourMapsNeedRebuild) \
2199 S9xBuildDirectColourMaps (); \
2200 GFX.ScreenColors = DirectColourMaps [0]; \
2203 GFX.ScreenColors = IPPU.ScreenColors; \
2208 uint32 Right = 256; \
2209 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2214 Screen += GFX.StartY * GFX.Pitch; \
2215 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2216 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2217 RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2221 void DrawBGMode7Background (uint8 *Screen, int bg)
2223 RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & bmask))
2226 void DrawBGMode7Background16 (uint8 *Screen, int bg)
2228 RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2231 void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2233 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2234 (*(d + GFX.DepthDelta) != 1 ?
2235 COLOR_ADD (GFX.ScreenColors [b & bmask],
2237 COLOR_ADD (GFX.ScreenColors [b & bmask],
2239 GFX.ScreenColors [b & bmask]);
2242 void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2244 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2245 (*(d + GFX.DepthDelta) != 1 ?
2246 COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2248 COLOR_ADD (GFX.ScreenColors [b & bmask],
2250 GFX.ScreenColors [b & bmask]);
2253 void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2255 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2256 (*(d + GFX.DepthDelta) != 1 ?
2257 COLOR_SUB (GFX.ScreenColors [b & bmask],
2259 COLOR_SUB (GFX.ScreenColors [b & bmask],
2261 GFX.ScreenColors [b & bmask]);
2264 void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2266 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2267 (*(d + GFX.DepthDelta) != 1 ?
2268 COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2270 COLOR_SUB (GFX.ScreenColors [b & bmask],
2272 GFX.ScreenColors [b & bmask]);
2275 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2278 uint8 *VRAM1 = Memory.VRAM + 1; \
2279 if (GFX.r2130 & 1) \
2281 if (IPPU.DirectColourMapsNeedRebuild) \
2282 S9xBuildDirectColourMaps (); \
2283 GFX.ScreenColors = DirectColourMaps [0]; \
2286 GFX.ScreenColors = IPPU.ScreenColors; \
2292 uint32 Right = 256; \
2293 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2298 Screen += GFX.StartY * GFX.Pitch; \
2299 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2300 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2301 bool8_32 allowSimpleCase = FALSE; \
2302 if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2303 && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2304 && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2306 allowSimpleCase = TRUE; \
2308 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2312 int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2313 int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2315 int CentreX = ((int) l->CentreX << M7) >> M7; \
2316 int CentreY = ((int) l->CentreY << M7) >> M7; \
2318 if (PPU.Mode7VFlip) \
2319 yy = 261 - (int) Line; \
2323 if (PPU.Mode7Repeat == 0) \
2324 yy += (VOffset - CentreY) % 1023; \
2326 yy += VOffset - CentreY; \
2327 bool8_32 simpleCase = FALSE; \
2330 /* Make a special case for the identity matrix, since it's a common case and */ \
2331 /* can be done much more quickly without special effects */ \
2332 if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2334 BB = CentreX << 8; \
2335 DD = (yy + CentreY) << 8; \
2336 simpleCase = TRUE; \
2340 BB = l->MatrixB * yy + (CentreX << 8); \
2341 DD = l->MatrixD * yy + (CentreY << 8); \
2344 for (uint32 clip = 0; clip < ClipCount; clip++) \
2346 if (GFX.pCurrentClip->Count [bg]) \
2348 Left = GFX.pCurrentClip->Left [clip][bg]; \
2349 Right = GFX.pCurrentClip->Right [clip][bg]; \
2350 if (Right <= Left) \
2353 TYPE *p = (TYPE *) Screen + Left; \
2354 uint8 *d = Depth + Left; \
2356 if (PPU.Mode7HFlip) \
2358 startx = Right - 1; \
2373 if (PPU.Mode7Repeat == 0) \
2374 xx = startx + (HOffset - CentreX) % 1023; \
2376 xx = startx + HOffset - CentreX; \
2384 AA = l->MatrixA * xx; \
2385 CC = l->MatrixC * xx; \
2389 if (!PPU.Mode7Repeat) \
2394 int X = ((AA + BB) >> 8) & 0x3ff; \
2395 int Y = (DD >> 8) & 0x3ff; \
2396 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2397 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2398 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2399 if (GFX.Z1 > *d && b) \
2401 TYPE theColor = COLORFUNC; \
2402 *p = (FUNC) | ALPHA_BITS_MASK; \
2405 AA += aa, p++, d++; \
2407 } while (x != endx); \
2413 int X = (AA + BB) >> 8; \
2416 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2422 if (((X | Y) & ~0x3ff) == 0) \
2424 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2425 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2426 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2427 if (GFX.Z1 > *d && b) \
2429 TYPE theColor = COLORFUNC; \
2430 *p = (FUNC) | ALPHA_BITS_MASK; \
2434 else if (PPU.Mode7Repeat == 3) \
2436 X = (x + HOffset) & 7; \
2437 Y = (yy + CentreY) & 7; \
2438 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2439 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2440 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2441 if (GFX.Z1 > *d && b) \
2443 TYPE theColor = COLORFUNC; \
2444 *p = (FUNC) | ALPHA_BITS_MASK; \
2448 AA += aa; p++; d++; \
2450 } while (x != endx); \
2453 else if (!PPU.Mode7Repeat) \
2455 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2456 /* the location of one point in the _sampled_ image, and weight them according */ \
2457 /* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
2460 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2461 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2462 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2463 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2464 /* You can think of this as a kind of mipmapping. */ \
2465 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2467 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2469 uint32 xPos = AA + BB; \
2470 uint32 xPix = xPos >> 8; \
2471 uint32 yPos = CC + DD; \
2472 uint32 yPix = yPos >> 8; \
2473 uint32 X = xPix & 0x3ff; \
2474 uint32 Y = yPix & 0x3ff; \
2475 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2476 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2477 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2478 if (GFX.Z1 > *d && b) \
2480 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2481 uint32 X10 = (xPix + dir) & 0x3ff; \
2482 uint32 Y01 = (yPix + dir) & 0x3ff; \
2483 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2484 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2485 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2486 uint32 p1 = COLORFUNC; \
2487 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2488 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2489 uint32 p2 = COLORFUNC; \
2490 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2491 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2492 uint32 p4 = COLORFUNC; \
2493 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2494 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2495 uint32 p3 = COLORFUNC; \
2496 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2497 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2498 uint32 Xdel = (xPos >> 3) & 0x1F; \
2499 uint32 Ydel = (yPos >> 3) & 0x1F; \
2500 uint32 XY = (Xdel*Ydel) >> 5; \
2501 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2502 uint32 area2 = Xdel - XY; \
2503 uint32 area3 = Ydel - XY; \
2504 uint32 area4 = XY; \
2505 uint32 tempColor = ((area1 * p1) + \
2508 (area4 * p4)) >> 5; \
2509 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2510 *p = (FUNC) | ALPHA_BITS_MASK; \
2516 /* The oversampling method: get the colors at four corners of a square */ \
2517 /* in the _displayed_ image, and average them. It's sharp and clean, but */ \
2518 /* gives the usual huge pixels when the source image gets "close." */ \
2520 /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2521 uint32 aaDelX = aa >> 1; \
2522 uint32 ccDelX = cc >> 1; \
2523 uint32 bbDelY = l->MatrixB >> 1; \
2524 uint32 ddDelY = l->MatrixD >> 1; \
2525 /* Offset the location within the source image so that the four sampled points */ \
2526 /* center around where the single point would otherwise have been drawn. */ \
2527 BB -= (bbDelY >> 1); \
2528 DD -= (ddDelY >> 1); \
2529 AA -= (aaDelX >> 1); \
2530 CC -= (ccDelX >> 1); \
2531 uint32 BB10 = BB + aaDelX; \
2532 uint32 BB01 = BB + bbDelY; \
2533 uint32 BB11 = BB + aaDelX + bbDelY; \
2534 uint32 DD10 = DD + ccDelX; \
2535 uint32 DD01 = DD + ddDelY; \
2536 uint32 DD11 = DD + ccDelX + ddDelY; \
2537 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2539 uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2540 uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2541 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2542 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2543 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2544 if (GFX.Z1 > *d && b) \
2546 /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2547 /* source image that we're going to examine. */ \
2548 uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2549 uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2550 uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2551 uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2552 uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2553 uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2554 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2555 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2556 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2557 TYPE p1 = COLORFUNC; \
2558 b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2559 TYPE p2 = COLORFUNC; \
2560 b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2561 TYPE p3 = COLORFUNC; \
2562 b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2563 TYPE p4 = COLORFUNC; \
2564 TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2565 *p = (FUNC) | ALPHA_BITS_MASK; \
2573 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2575 uint32 xPos = AA + BB; \
2576 uint32 xPix = xPos >> 8; \
2577 uint32 yPos = CC + DD; \
2578 uint32 yPix = yPos >> 8; \
2583 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2589 if (((X | Y) & ~0x3ff) == 0) \
2591 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2592 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2593 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2594 if (GFX.Z1 > *d && b) \
2596 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2597 uint32 X10 = (xPix + dir) & 0x3ff; \
2598 uint32 Y01 = (yPix + dir) & 0x3ff; \
2599 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2600 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2601 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2602 uint32 p1 = COLORFUNC; \
2603 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2604 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2605 uint32 p2 = COLORFUNC; \
2606 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2607 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2608 uint32 p4 = COLORFUNC; \
2609 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2610 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2611 uint32 p3 = COLORFUNC; \
2612 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2613 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2614 uint32 Xdel = (xPos >> 3) & 0x1F; \
2615 uint32 Ydel = (yPos >> 3) & 0x1F; \
2616 uint32 XY = (Xdel*Ydel) >> 5; \
2617 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2618 uint32 area2 = Xdel - XY; \
2619 uint32 area3 = Ydel - XY; \
2620 uint32 area4 = XY; \
2621 uint32 tempColor = ((area1 * p1) + \
2624 (area4 * p4)) >> 5; \
2625 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2626 *p = (FUNC) | ALPHA_BITS_MASK; \
2632 if (PPU.Mode7Repeat == 3) \
2634 X = (x + HOffset) & 7; \
2635 Y = (yy + CentreY) & 7; \
2636 uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2637 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2638 if (GFX.Z1 > *d && b) \
2640 TYPE theColor = COLORFUNC; \
2641 *p = (FUNC) | ALPHA_BITS_MASK; \
2651 STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2653 register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2654 ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2655 ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2656 ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2657 register uint32 y = (A & TWO_LOW_BITS_MASK) +
2658 (B & TWO_LOW_BITS_MASK) +
2659 (C & TWO_LOW_BITS_MASK) +
2660 (D & TWO_LOW_BITS_MASK);
2661 y = (y>>2) & TWO_LOW_BITS_MASK;
2665 void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2667 RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2670 void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2672 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2673 (*(d + GFX.DepthDelta) != 1 ?
2674 (COLOR_ADD (theColor,
2676 (COLOR_ADD (theColor,
2677 GFX.FixedColour))) :
2678 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2681 void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2683 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2684 (*(d + GFX.DepthDelta) != 1 ?
2685 COLOR_ADD1_2 (theColor,
2687 COLOR_ADD (theColor,
2689 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2692 void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2694 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2695 (*(d + GFX.DepthDelta) != 1 ?
2696 COLOR_SUB (theColor,
2698 COLOR_SUB (theColor,
2700 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2703 void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2705 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2706 (*(d + GFX.DepthDelta) != 1 ?
2707 COLOR_SUB1_2 (theColor,
2709 COLOR_SUB (theColor,
2711 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2714 #define _BUILD_SETUP(F) \
2715 GFX.BuildPixel = BuildPixel##F; \
2716 GFX.BuildPixel2 = BuildPixel2##F; \
2717 GFX.DecomposePixel = DecomposePixel##F; \
2718 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2719 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2720 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2721 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2722 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2723 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2724 MAX_RED = MAX_RED_##F; \
2725 MAX_GREEN = MAX_GREEN_##F; \
2726 MAX_BLUE = MAX_BLUE_##F; \
2727 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2728 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2729 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2730 GREEN_LOW_BIT_MASK_##F | \
2731 BLUE_LOW_BIT_MASK_##F); \
2732 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2733 GREEN_HI_BIT_MASK_##F | \
2734 BLUE_HI_BIT_MASK_##F); \
2735 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2736 GREEN_HI_BIT_MASK_##F | \
2737 BLUE_HI_BIT_MASK_##F) << 1); \
2738 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2739 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2740 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2741 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2742 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2743 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2744 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2745 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2746 ~TWO_LOW_BITS_MASK ) >> 2);
2748 void RenderScreen (uint8 *Screen, bool8_32 sub, bool8_32 force_no_add, uint8 D)
2760 GFX.pCurrentClip = &IPPU.Clip [0];
2761 BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2762 BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2763 BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2764 BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2765 OB = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2769 GFX.pCurrentClip = &IPPU.Clip [1];
2770 BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2771 BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2772 BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2773 BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2774 OB = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2777 sub |= force_no_add;
2779 if (PPU.BGMode <= 1)
2783 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2788 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2789 DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2793 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2794 DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2798 SelectTileRenderer (sub || !SUB_OR_ADD(2));
2799 DrawBackground (PPU.BGMode, 2, D + 3,
2800 (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2802 if (BG3 && PPU.BGMode == 0)
2804 SelectTileRenderer (sub || !SUB_OR_ADD(3));
2805 DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2808 else if (PPU.BGMode != 7)
2812 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2817 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2818 DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2820 if (PPU.BGMode != 6 && BG1)
2822 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2823 DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2830 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2833 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2837 if (Memory.FillRAM [0x2133] & 0x40)
2839 GFX.Mode7Mask = 0x7f;
2840 GFX.Mode7PriorityMask = 0x80;
2841 Mode7Depths [0] = 5 + D;
2842 Mode7Depths [1] = 9 + D;
2847 GFX.Mode7Mask = 0xff;
2848 GFX.Mode7PriorityMask = 0;
2849 Mode7Depths [0] = 5 + D;
2850 Mode7Depths [1] = 5 + D;
2853 if (sub || !SUB_OR_ADD(0))
2855 if (!Settings.Mode7Interpolate)
2856 DrawBGMode7Background16 (Screen, bg);
2858 DrawBGMode7Background16_i (Screen, bg);
2862 if (GFX.r2131 & 0x80)
2864 if (GFX.r2131 & 0x40)
2866 if (!Settings.Mode7Interpolate)
2867 DrawBGMode7Background16Sub1_2 (Screen, bg);
2869 DrawBGMode7Background16Sub1_2_i (Screen, bg);
2873 if (!Settings.Mode7Interpolate)
2874 DrawBGMode7Background16Sub (Screen, bg);
2876 DrawBGMode7Background16Sub_i (Screen, bg);
2881 if (GFX.r2131 & 0x40)
2883 if (!Settings.Mode7Interpolate)
2884 DrawBGMode7Background16Add1_2 (Screen, bg);
2886 DrawBGMode7Background16Add1_2_i (Screen, bg);
2890 if (!Settings.Mode7Interpolate)
2891 DrawBGMode7Background16Add (Screen, bg);
2893 DrawBGMode7Background16Add_i (Screen, bg);
2903 static void DisplayChar(uint8 *Screen, uint8 c)
2905 int line = (((c & 0x7f) - 32) >> 4) * font_height;
2906 int offset = (((c & 0x7f) - 32) & 15) * font_width;
2908 if (Settings.SixteenBit)
2912 uint16 *s = (uint16 *) Screen;
2913 for (h = 0; h < font_height; h++, line++,
2914 s += GFX.PPL - font_width)
2916 for (w = 0; w < font_width; w++, s++)
2918 uint8 p = font [line][offset + w];
2933 for (h = 0; h < font_height; h++, line++,
2934 s += GFX.PPL - font_width)
2936 for (w = 0; w < font_width; w++, s++)
2938 uint8 p = font [line][offset + w];
2951 static void S9xDisplayFrameRate()
2953 uint8 *Screen = GFX.Screen + 2 +
2954 (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch;
2957 const unsigned int char_width = Settings.SixteenBit ?
2958 (font_width - 1) * sizeof (uint16) :
2961 if (Settings.TurboMode) {
2962 len = sprintf(string, "%u",
2963 IPPU.DisplayedRenderedFrameCount);
2965 len = sprintf(string, "%2u/%02u",
2966 IPPU.DisplayedRenderedFrameCount,
2967 (unsigned int) Memory.ROMFramesPerSecond);
2970 for (int i = 0; i < len; i++) {
2971 DisplayChar(Screen, string[i]);
2972 Screen += char_width;
2976 static void S9xDisplayString(const char *string)
2978 uint8 *Screen = GFX.Screen + 2 +
2979 (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch;
2980 int len = strlen (string);
2981 int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
2985 for (i = 0; i < len; i++, char_count++)
2987 if (char_count >= max_chars || string [i] < 32)
2989 Screen -= Settings.SixteenBit ?
2990 (font_width - 1) * sizeof (uint16) * max_chars :
2991 (font_width - 1) * max_chars;
2992 Screen += font_height * GFX.Pitch;
2993 if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
2995 char_count -= max_chars;
2997 if (string [i] < 32)
2999 DisplayChar (Screen, string [i]);
3000 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
3005 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
3011 unsigned char *memoryfillram = Memory.FillRAM;
3013 // get local copies of vid registers to be used later
3014 GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN
3015 GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
3016 GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
3017 GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
3019 // If external sync is off and
3020 // main screens have not been configured the same as the sub screen and
3021 // color addition and subtraction has been diabled then
3023 // anything else it is 0
3024 GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
3025 (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
3026 (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
3028 // If sprite data has been changed then go through and
3029 // refresh the sprites.
3030 if (IPPU.OBJChanged)
3035 if (PPU.RecomputeClipWindows)
3037 ComputeClipWindows ();
3038 PPU.RecomputeClipWindows = FALSE;
3041 GFX.StartY = IPPU.PreviousLine;
3042 if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
3043 GFX.EndY = PPU.ScreenHeight - 1;
3045 uint32 starty = GFX.StartY;
3046 uint32 endy = GFX.EndY;
3048 #ifndef RC_OPTIMIZED
3049 if (Settings.SupportHiRes &&
3050 (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace)) {
3051 if (PPU.BGMode == 5 || PPU.BGMode == 6) {
3052 IPPU.RenderedScreenWidth = 512;
3056 if (IPPU.LatchedInterlace) {
3057 starty = GFX.StartY * 2;
3058 endy = GFX.EndY * 2 + 1;
3061 if (!IPPU.DoubleWidthPixels) {
3062 // The game has switched from lo-res to hi-res mode part way down
3063 // the screen. Scale any existing lo-res pixels on screen
3064 if (Settings.SixteenBit) {
3065 for (register uint32 y = 0; y < GFX.StartY; y++) {
3066 register uint16 *p =
3067 (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3068 register uint16 *q =
3069 (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3070 for (register int x = 255; x >= 0; x--, p--, q -= 2) {
3075 for (register uint32 y = 0; y < GFX.StartY; y++) {
3077 GFX.Screen + y * GFX.Pitch + 255;
3079 GFX.Screen + y * GFX.Pitch + 510;
3080 for (register int x = 255; x >= 0; x--, p--, q -= 2) {
3086 IPPU.DoubleWidthPixels = TRUE;
3089 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3091 uint32 black = BLACK | (BLACK << 16);
3093 // Are we worrying about transparencies?
3094 if (Settings.Transparency && Settings.SixteenBit)
3098 GFX.r2131 = 0x5f; //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3099 GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3100 Memory.FillRAM [0x212d]) & 15;
3101 GFX.r212c &= ~GFX.r212d; // make sure the main BG reg is the reverse of the sub BG reg
3102 GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3105 // Check to see if any transparency effects are currently in use
3106 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3107 (GFX.r2130 & 0x30) != 0x30 &&
3108 !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3110 // transparency effects in use, so lets get busy!
3111 struct ClipData *pClip;
3113 GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3114 IPPU.XB [PPU.FixedColourGreen],
3115 IPPU.XB [PPU.FixedColourBlue]);
3116 fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3117 // Clear the z-buffer, marking areas 'covered' by the fixed
3118 // colour as depth 1.
3119 pClip = &IPPU.Clip [1];
3121 // Clear the z-buffer
3123 if (pClip->Count [5])
3126 // Colour window enabled.
3128 for (uint32 y = starty; y <= endy; y++)
3130 ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3131 IPPU.RenderedScreenWidth);
3132 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3133 IPPU.RenderedScreenWidth);
3135 if (IPPU.Clip [0].Count [5])
3137 memset ((GFX.SubScreen + y * GFX.Pitch), black, IPPU.RenderedScreenWidth);
3139 for (uint32 c = 0; c < pClip->Count [5]; c++)
3141 if (pClip->Right [c][5] > pClip->Left [c][5])
3143 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3144 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3145 if (IPPU.Clip [0].Count [5])
3147 // Blast, have to clear the sub-screen to the fixed-colour
3148 // because there is a colour window in effect clipping
3149 // the main screen that will allow the sub-screen
3150 // 'underneath' to show through.
3151 memset ((GFX.SubScreen + y * GFX.Pitch) + pClip->Left [c][5] * x2,
3153 pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3159 #else // NOT RC_OPTIMIZED
3160 // loop around all of the lines being updated
3161 for (uint32 y = starty; y <= endy; y++)
3163 // Clear the subZbuffer
3164 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3165 IPPU.RenderedScreenWidth>>2);
3166 // Clear the Zbuffer
3167 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3168 IPPU.RenderedScreenWidth>>2);
3170 // if there is clipping then clear subscreen to a black color
3171 if (IPPU.Clip [0].Count [5])
3173 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch), black, IPPU.RenderedScreenWidth>>1);
3176 // loop through all window clippings
3177 for (uint32 c = 0; c < pClip->Count [5]; c++)
3179 if (pClip->Right [c][5] > pClip->Left [c][5])
3181 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3182 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3183 if (IPPU.Clip [0].Count [5])
3185 // Blast, have to clear the sub-screen to the fixed-colour
3186 // because there is a colour window in effect clipping
3187 // the main screen that will allow the sub-screen
3188 // 'underneath' to show through.
3190 register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch);
3191 register uint16 *q = p + pClip->Right [c][5] * x2;
3192 p += pClip->Left [c][5] * x2;
3195 *p++ = (uint16) GFX.FixedColour;
3205 // No windows are clipping the main screen
3206 // this simplifies the screen clearing process
3209 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3212 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3213 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3217 for (uint32 y = starty; y <= endy; y++)
3219 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3220 IPPU.RenderedScreenWidth);
3221 memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3222 IPPU.RenderedScreenWidth);
3226 if (IPPU.Clip [0].Count [5])
3228 // Blast, have to clear the sub-screen to the fixed-colour
3229 // because there is a colour window in effect clipping
3230 // the main screen that will allow the sub-screen
3231 // 'underneath' to show through.
3232 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3234 memset ((GFX.SubScreen + starty * GFX.Pitch),
3235 GFX.FixedColour | (GFX.FixedColour << 16),
3236 GFX.Pitch * (endy - starty - 1));
3240 for (uint32 y = starty; y <= endy; y++)
3242 memset ((GFX.SubScreen + y * GFX.Pitch),
3243 GFX.FixedColour | (GFX.FixedColour << 16),
3244 IPPU.RenderedScreenWidth);
3249 #else // NOT RC_OPTIMIZED
3250 // loop through all of the lines to be updated
3251 for (uint32 y = starty; y <= endy; y++)
3253 // Clear the Zbuffer
3254 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3255 IPPU.RenderedScreenWidth>>2);
3256 // clear the sub Zbuffer to 1
3257 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3258 IPPU.RenderedScreenWidth>>2);
3259 if (IPPU.Clip [0].Count [5])
3261 // Blast, have to clear the sub-screen to the fixed-colour
3262 // because there is a colour window in effect clipping
3263 // the main screen that will allow the sub-screen
3264 // 'underneath' to show through.
3267 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch), fixedColour,
3268 IPPU.RenderedScreenWidth>>1);
3275 if (ANYTHING_ON_SUB)
3277 GFX.DB = GFX.SubZBuffer;
3278 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3281 if (IPPU.Clip [0].Count [5])
3283 for (uint32 y = starty; y <= endy; y++)
3285 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch);
3286 register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3287 register uint8 *e = d + SNES_WIDTH;
3292 *p = *(p + GFX.Delta);
3301 GFX.DB = GFX.ZBuffer;
3302 RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3305 uint32 back = IPPU.ScreenColors [0];
3310 pClip = &IPPU.Clip [0];
3312 for (uint32 y = starty; y <= endy; y++)
3314 if (!(Count = pClip->Count [5]))
3321 for (uint32 b = 0; b < Count; b++)
3323 if (pClip->Count [5])
3325 Left = pClip->Left [b][5] * x2;
3326 Right = pClip->Right [b][5] * x2;
3331 if (GFX.r2131 & 0x80)
3333 if (GFX.r2131 & 0x40)
3335 // Subtract, halving the result.
3336 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3337 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3338 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3339 register uint8 *e = d + Right;
3340 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3350 *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3365 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3366 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3367 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3368 register uint8 *e = d + Right;
3369 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3379 *p = COLOR_SUB (back, *(p + GFX.Delta));
3393 if (GFX.r2131 & 0x40)
3395 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3396 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3397 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3398 register uint8 *e = d + Right;
3399 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3408 *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3423 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3424 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3425 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3426 register uint8 *e = d + Right;
3427 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3436 *p = COLOR_ADD (back, *(p + GFX.Delta));
3450 if (!pClip->Count [5])
3452 // The backdrop has not been cleared yet - so
3453 // copy the sub-screen to the main screen
3454 // or fill it with the back-drop colour if the
3455 // sub-screen is clear.
3456 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3457 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3458 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3459 register uint8 *e = d + Right;
3468 *p = *(p + GFX.Delta);
3470 *p = GFX.FixedColour;
3487 // Subscreen not being added to back
3488 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3489 pClip = &IPPU.Clip [0];
3491 if (pClip->Count [5])
3493 for (uint32 y = starty; y <= endy; y++)
3495 for (uint32 b = 0; b < pClip->Count [5]; b++)
3497 uint32 Left = pClip->Left [b][5] * x2;
3498 uint32 Right = pClip->Right [b][5] * x2;
3499 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3500 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3501 register uint8 *e = d + Right;
3515 for (uint32 y = starty; y <= endy; y++)
3517 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch);
3518 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3519 register uint8 *e = d + 256 * x2;
3539 // 16bit and transparency but currently no transparency effects in
3542 // get the back colour of the current screen
3543 uint32 back = IPPU.ScreenColors [0] |
3544 (IPPU.ScreenColors [0] << 16);
3546 // if forceblanking in use then use black instead of the back color
3547 if (PPU.ForcedBlanking)
3550 // not sure what Clip is used for yet
3551 // could be a check to see if there is any clipping present?
3552 if (IPPU.Clip [0].Count[5])
3556 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3558 memset (GFX.Screen + starty * GFX.Pitch, black,
3559 GFX.Pitch * (endy - starty - 1));
3563 for (uint32 y = starty; y <= endy; y++)
3565 memset (GFX.Screen + y * GFX.Pitch, black,
3569 for (uint32 y = starty; y <= endy; y++)
3571 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3573 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3576 memset ((GFX.Screen + y * GFX.Pitch) + IPPU.Clip [0].Left [c][5] * x2,
3578 IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3583 // loop through all of the lines that are going to be updated as part of this screen update
3584 for (uint32 y = starty; y <= endy; y++)
3586 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), black,
3587 IPPU.RenderedScreenWidth>>1);
3591 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3593 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3595 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch); // get pointer to current line in screen buffer
3596 register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3597 p += IPPU.Clip [0].Left [c][5] * x2;
3600 *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3610 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3612 memset (GFX.Screen + starty * GFX.Pitch, back,
3613 GFX.Pitch * (endy - starty - 1));
3617 for (uint32 y = starty; y <= endy; y++)
3619 memset (GFX.Screen + y * GFX.Pitch, back,
3624 // there is no clipping to worry about so just fill with the back colour
3625 for (uint32 y = starty; y <= endy; y++)
3627 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), back,
3628 IPPU.RenderedScreenWidth>>1);
3633 // If Forced blanking is not in effect
3634 if (!PPU.ForcedBlanking)
3637 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3639 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3640 GFX.ZPitch * (endy - starty - 1));
3644 for (uint32 y = starty; y <= endy; y++)
3646 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3651 // Clear the Zbuffer for each of the lines which are going to be updated
3652 for (uint32 y = starty; y <= endy; y++)
3654 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3658 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3659 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3663 else // Transparencys are disabled, ahh lovely ... nice and easy.
3666 if (Settings.SixteenBit)
3669 // get back colour to be used in clearing the screen
3670 register uint32 back;
3671 if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3672 (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3674 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3675 (IPPU.XB[PPU.FixedColourGreen] << 6) |
3676 (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3677 back = (back << 16) | back;
3681 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3684 // if Forcedblanking in use then back colour becomes black
3685 if (PPU.ForcedBlanking)
3689 SelectTileRenderer (TRUE); //selects the tile renderers to be used
3690 // TRUE means to use the default
3691 // FALSE means use best renderer based on current
3692 // graphics register settings
3695 // now clear all graphics lines which are being updated using the back colour
3696 for (register uint32 y = starty; y <= endy; y++)
3698 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), back,
3699 IPPU.RenderedScreenWidth>>1);
3703 else // Settings.SixteenBit == false
3705 // because we are in 8 bit we can just use 0 to clear the screen
3706 // this means we can use the Zero Memory function
3708 // Loop through all lines being updated and clear the pixels to 0
3709 for (uint32 y = starty; y <= endy; y++)
3711 ZeroMemory (GFX.Screen + y * GFX.Pitch,
3712 IPPU.RenderedScreenWidth);
3716 if (!PPU.ForcedBlanking)
3718 // Loop through all lines being updated and clear the
3719 // zbuffer for each of the lines
3720 for (uint32 y = starty; y <= endy; y++)
3722 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3723 IPPU.RenderedScreenWidth>>2);
3725 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3726 GFX.pCurrentClip = &IPPU.Clip [0];
3728 // Define an inline function to handle clipping
3729 #define FIXCLIP(n) \
3730 if (GFX.r212c & (1 << (n))) \
3731 GFX.pCurrentClip = &IPPU.Clip [0]; \
3733 GFX.pCurrentClip = &IPPU.Clip [1]
3735 // Define an inline function to handle which BGs are being displayed
3736 #define DISPLAY(n) \
3738 (!(PPU.BG_Forced & n) && (GFX.r212c & n)) || \
3739 (((GFX.r212d & n) && subadd)) \
3742 uint8 subadd = GFX.r2131 & 0x3f;
3744 // go through all BGS are check if they need to be displayed
3745 bool BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3746 bool BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3747 bool BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3748 bool BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3749 bool OB = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3751 if (PPU.BGMode <= 1)
3753 // screen modes 0 and 1
3762 DrawBackground (PPU.BGMode, 0, 10, 14);
3767 DrawBackground (PPU.BGMode, 1, 9, 13);
3772 DrawBackground (PPU.BGMode, 2, 3,
3773 (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3775 if (BG3 && PPU.BGMode == 0)
3778 DrawBackground (PPU.BGMode, 3, 2, 5);
3781 else if (PPU.BGMode != 7)
3783 // screen modes 2 and up but not mode 7
3792 DrawBackground (PPU.BGMode, 0, 5, 13);
3794 if (BG1 && PPU.BGMode != 6)
3797 DrawBackground (PPU.BGMode, 1, 2, 9);
3808 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3812 if (Memory.FillRAM [0x2133] & 0x40)
3814 GFX.Mode7Mask = 0x7f;
3815 GFX.Mode7PriorityMask = 0x80;
3816 Mode7Depths [0] = 5;
3817 Mode7Depths [1] = 9;
3822 GFX.Mode7Mask = 0xff;
3823 GFX.Mode7PriorityMask = 0;
3824 Mode7Depths [0] = 5;
3825 Mode7Depths [1] = 5;
3830 if (!Settings.SixteenBit)
3831 DrawBGMode7Background (GFX.Screen, bg);
3835 if (!Settings.Mode7Interpolate)
3837 DrawBGMode7Background16 (GFX.Screen, bg);
3841 DrawBGMode7Background16_i (GFX.Screen, bg);
3848 #ifndef RC_OPTIMIZE // no hi res
3849 if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3851 if (IPPU.DoubleWidthPixels)
3853 // Mixure of background modes used on screen - scale width
3854 // of all non-mode 5 and 6 pixels.
3856 if (Settings.SixteenBit)
3859 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3861 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3862 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3863 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3870 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3872 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3873 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3874 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3881 if (IPPU.LatchedInterlace)
3883 // Interlace is enabled - double the height of all non-mode 5 and 6
3885 for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3887 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch),
3888 (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch),
3894 IPPU.PreviousLine = IPPU.CurrentLine;
3897 #ifdef GFX_MULTI_FORMAT
3899 #define _BUILD_PIXEL(F) \
3900 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
3902 return (BUILD_PIXEL_##F(R,G,B)); \
3904 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
3906 return (BUILD_PIXEL2_##F(R,G,B)); \
3908 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
3910 DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
3913 _BUILD_PIXEL(RGB565)
3914 _BUILD_PIXEL(RGB555)
3915 _BUILD_PIXEL(BGR565)
3916 _BUILD_PIXEL(BGR555)
3917 _BUILD_PIXEL(GBR565)
3918 _BUILD_PIXEL(GBR555)
3919 _BUILD_PIXEL(RGB5551)
3921 bool8_32 S9xSetRenderPixelFormat (int format)
3923 extern uint32 current_graphic_format;
3925 current_graphic_format = format;
3930 _BUILD_SETUP(RGB565)
3933 _BUILD_SETUP(RGB555)
3936 _BUILD_SETUP(BGR565)
3939 _BUILD_SETUP(BGR555)
3942 _BUILD_SETUP(GBR565)
3945 _BUILD_SETUP(GBR555)
3948 _BUILD_SETUP(RGB5551)