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;
216 IPPU.DirectColourMapsNeedRebuild = TRUE;
217 DrawTilePtr = DrawTile16;
218 DrawClippedTilePtr = DrawClippedTile16;
219 DrawLargePixelPtr = DrawLargePixel16;
220 DrawHiResTilePtr= DrawHiResTile16;
221 DrawHiResClippedTilePtr = DrawHiResClippedTile16;
222 S9xFixColourBrightness();
224 if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
227 if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
228 !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
232 free ((char *) GFX.ZERO_OR_X2);
233 GFX.ZERO_OR_X2 = NULL;
237 free ((char *) GFX.X2);
244 // Build a lookup table that multiplies a packed RGB value by 2 with
246 for (r = 0; r <= MAX_RED; r++)
251 for (g = 0; g <= MAX_GREEN; g++)
256 for (b = 0; b <= MAX_BLUE; b++)
261 GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
262 GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
266 ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
267 ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
268 // Build a lookup table that if the top bit of the color value is zero
269 // then the value is zero, otherwise multiply the value by 2. Used by
270 // the color subtraction code.
272 #if defined(OLD_COLOUR_BLENDING)
273 for (r = 0; r <= MAX_RED; r++)
276 if ((r2 & 0x10) == 0)
279 r2 = (r2 << 1) & MAX_RED;
281 for (g = 0; g <= MAX_GREEN; g++)
284 if ((g2 & GREEN_HI_BIT) == 0)
287 g2 = (g2 << 1) & MAX_GREEN;
289 for (b = 0; b <= MAX_BLUE; b++)
292 if ((b2 & 0x10) == 0)
295 b2 = (b2 << 1) & MAX_BLUE;
297 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
298 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
303 for (r = 0; r <= MAX_RED; r++)
306 if ((r2 & 0x10) == 0)
309 r2 = (r2 << 1) & MAX_RED;
313 for (g = 0; g <= MAX_GREEN; g++)
316 if ((g2 & GREEN_HI_BIT) == 0)
319 g2 = (g2 << 1) & MAX_GREEN;
323 for (b = 0; b <= MAX_BLUE; b++)
326 if ((b2 & 0x10) == 0)
329 b2 = (b2 << 1) & MAX_BLUE;
333 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
334 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
340 // Build a lookup table that if the top bit of the color value is zero
341 // then the value is zero, otherwise its just the value.
342 for (r = 0; r <= MAX_RED; r++)
345 if ((r2 & 0x10) == 0)
350 for (g = 0; g <= MAX_GREEN; g++)
353 if ((g2 & GREEN_HI_BIT) == 0)
357 for (b = 0; b <= MAX_BLUE; b++)
360 if ((b2 & 0x10) == 0)
365 GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
366 GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
374 void S9xGraphicsDeinit (void)
376 // Free any memory allocated in S9xGraphicsInit
379 free ((char *) GFX.X2);
384 free ((char *) GFX.ZERO_OR_X2);
385 GFX.ZERO_OR_X2 = NULL;
389 free ((char *) GFX.ZERO);
394 void S9xBuildDirectColourMaps ()
396 for (uint32 p = 0; p < 8; p++)
398 for (uint32 c = 0; c < 256; c++)
401 DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
402 ((c & 0x38) >> 1) | (p & 2),
403 ((c & 0xc0) >> 3) | (p & 4));
406 IPPU.DirectColourMapsNeedRebuild = FALSE;
409 void S9xStartScreenRefresh()
411 if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0) {
412 free(GFX.InfoString);
413 GFX.InfoString = NULL;
418 if (IPPU.RenderThisFrame) {
419 if (!S9xInitUpdate()) {
420 IPPU.RenderThisFrame = FALSE;
424 IPPU.PreviousLine = IPPU.CurrentLine = 0;
425 IPPU.MaxBrightness = PPU.Brightness;
426 IPPU.LatchedBlanking = PPU.ForcedBlanking;
427 IPPU.LatchedInterlace = (Memory.FillRAM[0x2133] & 1);
428 IPPU.RenderedScreenWidth = 256;
429 IPPU.RenderedScreenHeight = PPU.ScreenHeight;
430 IPPU.DoubleWidthPixels = FALSE;
432 PPU.RecomputeClipWindows = TRUE;
436 void RenderLine (uint8 C)
438 if (IPPU.RenderThisFrame)
441 LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
442 LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
443 LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
444 LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
448 struct SLineMatrixData *p = &LineMatrixData [C];
449 p->MatrixA = PPU.MatrixA;
450 p->MatrixB = PPU.MatrixB;
451 p->MatrixC = PPU.MatrixC;
452 p->MatrixD = PPU.MatrixD;
453 p->CentreX = PPU.CentreX;
454 p->CentreY = PPU.CentreY;
459 if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
460 PPU.BG[2].HOffset == 0xe000)
462 LineData[C].BG[2].VOffset = 0xe1;
463 LineData[C].BG[2].HOffset = 0;
469 LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
470 LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
471 LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
472 LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
476 IPPU.CurrentLine = C + 1;
481 void S9xEndScreenRefresh()
483 IPPU.HDMAStarted = FALSE;
485 if (IPPU.RenderThisFrame) {
488 IPPU.RenderedFramesCount++;
490 if (IPPU.ColorsChanged) {
491 IPPU.ColorsChanged = FALSE;
494 if (Settings.DisplayFrameRate) {
495 S9xDisplayFrameRate();
498 if (GFX.InfoString) {
499 S9xDisplayString(GFX.InfoString);
502 S9xDeinitUpdate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight);
510 if (CPU.Flags & FRAME_ADVANCE_FLAG)
512 if (ICPU.FrameAdvanceCount)
514 ICPU.FrameAdvanceCount--;
515 IPPU.RenderThisFrame = TRUE;
520 CPU.Flags &= ~FRAME_ADVANCE_FLAG;
521 CPU.Flags |= DEBUG_MODE_FLAG;
526 if (CPU.SRAMModified)
528 if (!CPU.AutoSaveTimer)
530 if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
531 CPU.SRAMModified = FALSE;
535 if (!--CPU.AutoSaveTimer)
538 CPU.SRAMModified = FALSE;
544 void S9xSetInfoString (const char * fmt, ...)
549 if (vasprintf(&GFX.InfoString, fmt, ap) > 0) {
550 GFX.InfoStringTimeout = 120;
553 GFX.InfoStringTimeout = 0;
559 INLINE void SelectTileRenderer (bool8_32 normal)
563 DrawTilePtr = DrawTile16;
564 DrawClippedTilePtr = DrawClippedTile16;
565 DrawLargePixelPtr = DrawLargePixel16;
569 if (GFX.r2131 & 0x80)
571 if (GFX.r2131 & 0x40)
575 DrawTilePtr = DrawTile16Sub1_2;
576 DrawClippedTilePtr = DrawClippedTile16Sub1_2;
580 // Fixed colour substraction
581 DrawTilePtr = DrawTile16FixedSub1_2;
582 DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
584 DrawLargePixelPtr = DrawLargePixel16Sub1_2;
588 DrawTilePtr = DrawTile16Sub;
589 DrawClippedTilePtr = DrawClippedTile16Sub;
590 DrawLargePixelPtr = DrawLargePixel16Sub;
595 if (GFX.r2131 & 0x40)
599 DrawTilePtr = DrawTile16Add1_2;
600 DrawClippedTilePtr = DrawClippedTile16Add1_2;
604 // Fixed colour addition
605 DrawTilePtr = DrawTile16FixedAdd1_2;
606 DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
608 DrawLargePixelPtr = DrawLargePixel16Add1_2;
612 DrawTilePtr = DrawTile16Add;
613 DrawClippedTilePtr = DrawClippedTile16Add;
614 DrawLargePixelPtr = DrawLargePixel16Add;
625 switch (PPU.OBJSizeSelect)
656 int FirstSprite = PPU.FirstSprite & 0x7f;
661 if (PPU.OBJ [S].Size)
666 long VPos = PPU.OBJ [S].VPos;
668 if (VPos >= PPU.ScreenHeight)
670 if (PPU.OBJ [S].HPos < 256 && PPU.OBJ [S].HPos > -Size &&
671 VPos < PPU.ScreenHeight && VPos > -Size)
673 GFX.OBJList [C++] = S;
675 GFX.VPositions[S] = VPos;
678 } while (S != FirstSprite);
680 // Terminate the list
681 GFX.OBJList [C] = -1;
682 IPPU.OBJChanged = FALSE;
685 void DrawOBJS (bool8_32 OnMain = FALSE, uint8 D = 0)
688 uint32 BaseTile, Tile;
694 BG.TileAddress = PPU.OBJNameBase;
695 BG.StartPalette = 128;
698 BG.Buffer = IPPU.TileCache [TILE_4BIT];
699 BG.Buffered = IPPU.TileCached [TILE_4BIT];
700 BG.NameSelect = PPU.OBJNameSelect;
701 BG.DirectColourMode = FALSE;
706 for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
708 int VPos = GFX.VPositions [S];
709 int Size = GFX.Sizes[S];
713 if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
716 if (OnMain && SUB_OR_ADD(4))
718 SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
721 BaseTile = PPU.OBJ[S].Name | (PPU.OBJ[S].Palette << 10);
723 if (PPU.OBJ[S].HFlip)
725 BaseTile += ((Size >> 3) - 1) | H_FLIP;
728 if (PPU.OBJ[S].VFlip)
731 int clipcount = GFX.pCurrentClip->Count [4];
735 GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
737 for (int clip = 0; clip < clipcount; clip++)
741 if (!GFX.pCurrentClip->Count [4])
748 Left = GFX.pCurrentClip->Left [clip][4];
749 Right = GFX.pCurrentClip->Right [clip][4];
752 if (Right <= Left || PPU.OBJ[S].HPos + Size <= Left ||
753 PPU.OBJ[S].HPos >= Right)
756 for (int Y = 0; Y < Size; Y += 8)
758 if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
765 if ((StartLine = VPos + Y) < (int) GFX.StartY)
767 StartLine = GFX.StartY - StartLine;
768 LineCount = 8 - StartLine;
775 if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
776 if ((LineCount -= Last) <= 0)
779 TileLine = StartLine << 3;
780 O = (VPos + Y + StartLine) * GFX.PPL;
781 if (!PPU.OBJ[S].VFlip)
782 Tile = BaseTile + (Y << 1);
784 Tile = BaseTile + ((Size - Y - 8) << 1);
786 int Middle = Size >> 3;
787 if (PPU.OBJ[S].HPos < Left)
789 Tile += ((Left - PPU.OBJ[S].HPos) >> 3) * TileInc;
790 Middle -= (Left - PPU.OBJ[S].HPos) >> 3;
791 O += Left * GFX_PIX_SIZE;
792 if ((Offset = (Left - PPU.OBJ[S].HPos) & 7))
794 O -= Offset * GFX_PIX_SIZE;
796 int Width = Right - Left;
799 (*DrawClippedTilePtr) (Tile, O, Offset, W,
800 TileLine, LineCount);
806 O += 8 * GFX_PIX_SIZE;
810 O += PPU.OBJ[S].HPos * GFX_PIX_SIZE;
812 if (PPU.OBJ[S].HPos + Size >= Right)
814 Middle -= ((PPU.OBJ[S].HPos + Size + 7) -
816 Offset = (Right - (PPU.OBJ[S].HPos + Size)) & 7;
821 for (int X = 0; X < Middle; X++, O += 8 * GFX_PIX_SIZE,
824 (*DrawTilePtr) (Tile, O, TileLine, LineCount);
828 (*DrawClippedTilePtr) (Tile, O, 0, Offset,
829 TileLine, LineCount);
837 void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
846 uint8 depths [2] = {Z1, Z2};
849 BG.StartPalette = bg << 5;
853 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
855 if (PPU.BG[bg].SCSize & 1)
860 if (PPU.BG[bg].SCSize & 2)
865 if (PPU.BG[bg].SCSize & 1)
874 if (BG.TileSize == 16)
885 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
887 uint32 VOffset = LineData [Y].BG[bg].VOffset;
888 uint32 HOffset = LineData [Y].BG[bg].HOffset;
889 uint32 MosaicOffset = Y % PPU.Mosaic;
891 for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
892 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
893 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
896 uint32 MosaicLine = VOffset + Y - MosaicOffset;
898 if (Y + Lines > GFX.EndY)
899 Lines = GFX.EndY + 1 - Y;
900 uint32 VirtAlign = (MosaicLine & 7) << 3;
905 uint32 ScreenLine = MosaicLine >> OffsetShift;
906 uint32 Rem16 = MosaicLine & 15;
908 if (ScreenLine & 0x20)
913 b1 += (ScreenLine & 0x1f) << 5;
914 b2 += (ScreenLine & 0x1f) << 5;
919 uint32 ClipCount = GFX.pCurrentClip->Count [bg];
920 uint32 HPos = HOffset;
921 uint32 PixWidth = PPU.Mosaic;
926 for (uint32 clip = 0; clip < ClipCount; clip++)
928 if (GFX.pCurrentClip->Count [bg])
930 Left = GFX.pCurrentClip->Left [clip][bg];
931 Right = GFX.pCurrentClip->Right [clip][bg];
932 uint32 r = Left % PPU.Mosaic;
933 HPos = HOffset + Left;
934 PixWidth = PPU.Mosaic - r;
936 uint32 s = Y * GFX.PPL + Left * GFX_PIX_SIZE;
937 for (uint32 x = Left; x < Right; x += PixWidth,
938 s += PixWidth * GFX_PIX_SIZE,
939 HPos += PixWidth, PixWidth = PPU.Mosaic)
941 uint32 Quot = (HPos & OffsetMask) >> 3;
943 if (x + PixWidth >= Right)
944 PixWidth = Right - x;
946 if (BG.TileSize == 8)
949 t = b2 + (Quot & 0x1f);
956 t = b2 + ((Quot >> 1) & 0x1f);
958 t = b1 + (Quot >> 1);
961 Tile = READ_2BYTES (t);
962 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
965 if (BG.TileSize != 8)
969 // Horizontal flip, but what about vertical flip ?
972 // Both horzontal & vertical flip
975 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
981 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
988 // Horizontal flip only
991 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
997 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1005 // No horizontal flip, but is there a vertical flip ?
1008 // Vertical flip only
1011 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1017 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1027 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1033 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1041 (*DrawLargePixelPtr) (Tile, s, HPos & 7, PixWidth,
1048 void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1062 int VOffsetOffset = BGMode == 4 ? 0 : 32;
1063 uint8 depths [2] = {Z1, Z2};
1065 BG.StartPalette = 0;
1067 BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
1069 if (PPU.BG[2].SCSize & 1)
1074 if (PPU.BG[2].SCSize & 2)
1079 if (PPU.BG[2].SCSize & 1)
1084 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1086 if (PPU.BG[bg].SCSize & 1)
1091 if (PPU.BG[bg].SCSize & 2)
1095 if (PPU.BG[bg].SCSize & 1)
1100 static const int Lines = 1;
1103 int OffsetEnableMask = 1 << (bg + 13);
1105 if (BG.TileSize == 16)
1116 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
1118 uint32 VOff = LineData [Y].BG[2].VOffset;
1119 uint32 HOff = LineData [Y].BG[2].HOffset;
1121 int ScreenLine = VOff >> 3;
1128 if (ScreenLine & 0x20)
1129 s1 = BPS2, s2 = BPS3;
1131 s1 = BPS0, s2 = BPS1;
1133 s1 += (ScreenLine & 0x1f) << 5;
1134 s2 += (ScreenLine & 0x1f) << 5;
1136 int clipcount = GFX.pCurrentClip->Count [bg];
1140 for (int clip = 0; clip < clipcount; clip++)
1145 if (!GFX.pCurrentClip->Count [bg])
1152 Left = GFX.pCurrentClip->Left [clip][bg];
1153 Right = GFX.pCurrentClip->Right [clip][bg];
1161 uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
1172 uint32 TotalCount = 0;
1173 uint32 MaxCount = 8;
1175 uint32 s = Left * GFX_PIX_SIZE + Y * GFX.PPL;
1176 bool8_32 left_hand_edge = (Left == 0);
1177 Width = Right - Left;
1180 MaxCount = 8 - (Left & 7);
1182 while (Left < Right)
1186 // The SNES offset-per-tile background mode has a
1187 // hardware limitation that the offsets cannot be set
1188 // for the tile at the left-hand edge of the screen.
1189 VOffset = LineData [Y].BG[bg].VOffset;
1190 HOffset = LineHOffset;
1191 left_hand_edge = FALSE;
1195 // All subsequent offset tile data is shifted left by one,
1196 // hence the - 1 below.
1197 Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
1200 s0 = s2 + (Quot2 & 0x1f);
1204 HCellOffset = READ_2BYTES (s0);
1208 VOffset = LineData [Y].BG[bg].VOffset;
1209 HOffset=LineHOffset;
1210 if ((HCellOffset & OffsetEnableMask))
1212 if (HCellOffset & 0x8000)
1213 VOffset = HCellOffset + 1;
1215 HOffset = HCellOffset;
1220 VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
1221 if ((VCellOffset & OffsetEnableMask))
1222 VOffset = VCellOffset + 1;
1224 VOffset = LineData [Y].BG[bg].VOffset;
1226 if ((HCellOffset & OffsetEnableMask))
1227 HOffset = (HCellOffset & ~7)|(LineHOffset&7);
1229 HOffset=LineHOffset;
1232 VirtAlign = ((Y + VOffset) & 7) << 3;
1233 ScreenLine = (VOffset + Y) >> OffsetShift;
1235 if (((VOffset + Y) & 15) > 7)
1246 if (ScreenLine & 0x20)
1251 b1 += (ScreenLine & 0x1f) << 5;
1252 b2 += (ScreenLine & 0x1f) << 5;
1254 HPos = (HOffset + Left) & OffsetMask;
1258 if (BG.TileSize == 8)
1261 t = b2 + (Quot & 0x1f);
1268 t = b2 + ((Quot >> 1) & 0x1f);
1270 t = b1 + (Quot >> 1);
1273 if (MaxCount + TotalCount > Width)
1274 MaxCount = Width - TotalCount;
1279 if (Count > MaxCount)
1282 s -= Offset * GFX_PIX_SIZE;
1283 Tile = READ_2BYTES(t);
1284 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1286 if (BG.TileSize == 8)
1287 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines);
1290 if (!(Tile & (V_FLIP | H_FLIP)))
1292 // Normal, unflipped
1293 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1294 s, Offset, Count, VirtAlign, Lines);
1302 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1303 s, Offset, Count, VirtAlign, Lines);
1308 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1309 s, Offset, Count, VirtAlign, Lines);
1315 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1316 s, Offset, Count, VirtAlign, Lines);
1321 TotalCount += Count;
1322 s += (Offset + Count) * GFX_PIX_SIZE;
1329 void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
1333 uint8 depths [2] = {Z1, Z2};
1342 BG.StartPalette = 0;
1344 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1346 if ((PPU.BG[bg].SCSize & 1))
1351 if ((PPU.BG[bg].SCSize & 2))
1356 if ((PPU.BG[bg].SCSize & 1))
1365 if (BG.TileSize == 16)
1367 VOffsetMask = 0x3ff;
1372 VOffsetMask = 0x1ff;
1375 int endy = GFX.EndY;
1377 for (int Y = GFX.StartY; Y <= endy; Y += Lines)
1380 uint32 VOffset = LineData [y].BG[bg].VOffset;
1381 uint32 HOffset = LineData [y].BG[bg].HOffset;
1382 int VirtAlign = (Y + VOffset) & 7;
1384 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1385 if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
1386 (HOffset != LineData [y + Lines].BG[bg].HOffset))
1390 if (Y + Lines > endy)
1391 Lines = endy + 1 - Y;
1393 int ScreenLine = (VOffset + Y) >> VOffsetShift;
1396 if (((VOffset + Y) & 15) > 7)
1409 if (ScreenLine & 0x20)
1414 b1 += (ScreenLine & 0x1f) << 5;
1415 b2 += (ScreenLine & 0x1f) << 5;
1417 int clipcount = GFX.pCurrentClip->Count [bg];
1420 for (int clip = 0; clip < clipcount; clip++)
1425 if (!GFX.pCurrentClip->Count [bg])
1432 Left = GFX.pCurrentClip->Left [clip][bg] * 2;
1433 Right = GFX.pCurrentClip->Right [clip][bg] * 2;
1439 intptr_t s = (Left>>1) * GFX_PIX_SIZE + Y * GFX.PPL;
1440 uint32 HPos = (HOffset + Left * GFX_PIX_SIZE) & 0x3ff;
1442 uint32 Quot = HPos >> 3;
1447 t = b2 + ((Quot >> 1) & 0x1f);
1449 t = b1 + (Quot >> 1);
1451 Width = Right - Left;
1452 // Left hand edge clipped tile
1455 int Offset = (HPos & 7);
1460 Tile = READ_2BYTES (t);
1461 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1463 if (BG.TileSize == 8)
1465 if (!(Tile & H_FLIP))
1467 // Normal, unflipped
1468 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1469 s, Offset, Count, VirtAlign, Lines);
1474 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1475 s, Offset, Count, VirtAlign, Lines);
1480 if (!(Tile & (V_FLIP | H_FLIP)))
1482 // Normal, unflipped
1483 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1484 s, Offset, Count, VirtAlign, Lines);
1492 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1493 s, Offset, Count, VirtAlign, Lines);
1498 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1499 s, Offset, Count, VirtAlign, Lines);
1505 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1506 s, Offset, Count, VirtAlign, Lines);
1513 else if (Quot == 127)
1519 // Middle, unclipped tiles
1520 Count = Width - Count;
1521 int Middle = Count >> 3;
1523 for (int C = Middle; C > 0; s += 4, Quot++, C--)
1525 Tile = READ_2BYTES(t);
1526 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1527 if (BG.TileSize == 8)
1529 if (!(Tile & H_FLIP))
1531 // Normal, unflipped
1532 (*DrawHiResTilePtr) (Tile + (Quot & 1),
1533 s, VirtAlign, Lines);
1538 (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1539 s, VirtAlign, Lines);
1544 if (!(Tile & (V_FLIP | H_FLIP)))
1546 // Normal, unflipped
1547 (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1548 s, VirtAlign, Lines);
1556 (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1557 s, VirtAlign, Lines);
1562 (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1563 s, VirtAlign, Lines);
1569 (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1570 s, VirtAlign, Lines);
1582 // Right-hand edge clipped tiles
1585 Tile = READ_2BYTES(t);
1586 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1587 if (BG.TileSize == 8)
1589 if (!(Tile & H_FLIP))
1591 // Normal, unflipped
1592 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1593 s, 0, Count, VirtAlign, Lines);
1598 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1599 s, 0, Count, VirtAlign, Lines);
1604 if (!(Tile & (V_FLIP | H_FLIP)))
1606 // Normal, unflipped
1607 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1608 s, 0, Count, VirtAlign, Lines);
1616 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1617 s, 0, Count, VirtAlign, Lines);
1622 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1623 s, 0, Count, VirtAlign, Lines);
1629 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1630 s, 0, Count, VirtAlign, Lines);
1638 void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1640 BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1641 BG.BitShift = BitShifts[BGMode][bg];
1642 BG.TileShift = TileShifts[BGMode][bg];
1643 BG.TileAddress = PPU.BG[bg].NameBase << 1;
1645 BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1646 BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1647 BG.PaletteShift = PaletteShifts[BGMode][bg];
1648 BG.PaletteMask = PaletteMasks[BGMode][bg];
1649 BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1652 if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1654 DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1661 if (Settings.WrestlemaniaArcade)
1663 case 4: // Used by Puzzle Bobble
1664 DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1668 case 6: // XXX: is also offset per tile.
1669 DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1685 uint8 depths [2] = {Z1, Z2};
1688 BG.StartPalette = bg << 5;
1690 BG.StartPalette = 0;
1692 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1694 if (PPU.BG[bg].SCSize & 1)
1699 if (PPU.BG[bg].SCSize & 2)
1704 if (PPU.BG[bg].SCSize & 1)
1713 if (BG.TileSize == 16)
1724 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1726 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1727 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1728 int VirtAlign = (Y + VOffset) & 7;
1730 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1731 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1732 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1735 if (Y + Lines > GFX.EndY)
1736 Lines = GFX.EndY + 1 - Y;
1740 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1743 if (((VOffset + Y) & 15) > 7)
1756 if (ScreenLine & 0x20)
1761 b1 += (ScreenLine & 0x1f) << 5;
1762 b2 += (ScreenLine & 0x1f) << 5;
1764 int clipcount = GFX.pCurrentClip->Count [bg];
1767 for (int clip = 0; clip < clipcount; clip++)
1772 if (!GFX.pCurrentClip->Count [bg])
1779 Left = GFX.pCurrentClip->Left [clip][bg];
1780 Right = GFX.pCurrentClip->Right [clip][bg];
1786 intptr_t s = Left * GFX_PIX_SIZE + Y * GFX.PPL;
1787 uint32 HPos = (HOffset + Left) & OffsetMask;
1789 uint32 Quot = HPos >> 3;
1793 if (BG.TileSize == 8)
1796 t = b2 + (Quot & 0x1f);
1803 t = b2 + ((Quot >> 1) & 0x1f);
1805 t = b1 + (Quot >> 1);
1808 Width = Right - Left;
1809 // Left hand edge clipped tile
1812 uint32 Offset = (HPos & 7);
1816 s -= Offset * GFX_PIX_SIZE;
1817 Tile = READ_2BYTES(t);
1818 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1820 if (BG.TileSize == 8)
1822 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1827 if (!(Tile & (V_FLIP | H_FLIP)))
1829 // Normal, unflipped
1830 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1831 s, Offset, Count, VirtAlign, Lines);
1839 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1840 s, Offset, Count, VirtAlign, Lines);
1845 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1846 s, Offset, Count, VirtAlign, Lines);
1852 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
1853 Offset, Count, VirtAlign, Lines);
1857 if (BG.TileSize == 8)
1862 else if (Quot == 63)
1870 else if (Quot == 127)
1874 s += 8 * GFX_PIX_SIZE;
1877 // Middle, unclipped tiles
1878 Count = Width - Count;
1879 int Middle = Count >> 3;
1881 for (int C = Middle; C > 0; s += 8 * GFX_PIX_SIZE, Quot++, C--)
1883 Tile = READ_2BYTES(t);
1884 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1886 if (BG.TileSize != 8)
1890 // Horizontal flip, but what about vertical flip ?
1893 // Both horzontal & vertical flip
1894 (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
1899 // Horizontal flip only
1900 (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
1906 // No horizontal flip, but is there a vertical flip ?
1909 // Vertical flip only
1910 (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
1916 (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
1923 (*DrawTilePtr) (Tile, s, VirtAlign, Lines);
1926 if (BG.TileSize == 8)
1945 // Right-hand edge clipped tiles
1948 Tile = READ_2BYTES(t);
1949 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1951 if (BG.TileSize == 8)
1952 (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
1956 if (!(Tile & (V_FLIP | H_FLIP)))
1958 // Normal, unflipped
1959 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
1960 Count, VirtAlign, Lines);
1968 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1969 s, 0, Count, VirtAlign,
1975 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1976 s, 0, Count, VirtAlign,
1983 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1984 s, 0, Count, VirtAlign,
1993 #define RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
1994 const uint8 bmask = MASK; \
1995 for (int x = startx; x != endx; \
1996 x += (HFLIP ? -1 : 1), AA += aa, CC += cc, p++, d++) \
1998 int X = ((AA + BB) >> 8) & 0x3ff; \
1999 int Y = ((CC + DD) >> 8) & 0x3ff; \
2000 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2001 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2002 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2010 #define RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,CFILT) \
2011 register int AABB = AA + BB; \
2012 register int CCDD = CC + DD; \
2013 const uint8 bmask = MASK; \
2014 for (int x = startx; x != endx; \
2015 x += (HFLIP ? -1 : 1), AABB += aa, CCDD += cc, p++, d++) \
2017 register uint16 X = ((AABB) >> 8) CFILT; \
2018 register uint16 Y = ((CCDD) >> 8) CFILT; \
2020 if (((X | Y) & ~0x3ff) == 0) { \
2021 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2022 uint8 b = TileData[((Y & 7) << 4) + ((X & 7) << 1)]; \
2023 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2024 if (z > *d && b) { \
2028 } else if (REPEAT == 3) { \
2029 X = (x + HOffset) & 7; \
2030 Y = (yy + CentreY) & 7; \
2031 uint8 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2032 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2033 if (z > *d && b) { \
2040 #define RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,MASK,PRIOMASK) \
2041 for (uint32 clip = 0; clip < ClipCount; clip++) \
2043 if (GFX.pCurrentClip->Count [bg]) \
2045 Left = GFX.pCurrentClip->Left [clip][bg]; \
2046 Right = GFX.pCurrentClip->Right [clip][bg]; \
2047 if (Right <= Left) \
2050 register TYPE *p = (TYPE *) Screen + Left; \
2051 register uint8 *d = Depth + Left; \
2055 startx = Right - 1; \
2069 xx = startx + (HOffset - CentreX) % 1023; \
2071 xx = startx + HOffset - CentreX; \
2072 int AA = l->MatrixA * xx; \
2073 int CC = l->MatrixC * xx; \
2077 RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2078 } else if (DEZAEMON) { \
2079 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,& 0x7ff) \
2081 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,) \
2085 #ifdef USE_CRAZY_OPTS
2087 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON) \
2088 if (GFX.Mode7PriorityMask) { \
2089 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0x7f,0x80) \
2091 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0xff,0x00) \
2094 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,HFLIP) \
2095 if (Settings.Dezaemon && PPU.Mode7Repeat) { \
2096 switch (PPU.Mode7Repeat) { \
2097 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,1); break; \
2098 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,1); break; \
2099 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,1); break; \
2102 switch (PPU.Mode7Repeat) { \
2103 case 0: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,0,0); break; \
2104 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,0); break; \
2105 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,0); break; \
2106 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,0); break; \
2110 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC) \
2111 if (PPU.Mode7HFlip) { \
2112 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,1); \
2114 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,0); \
2117 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2118 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC)
2122 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2123 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,PPU.Mode7HFlip,PPU.Mode7Repeat,Settings.Dezaemon,GFX.Mode7Mask,GFX.Mode7PriorityMask)
2127 #define RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2128 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2132 int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2133 int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2135 int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2136 int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2138 if (PPU.Mode7VFlip) \
2139 yy = 261 - (int) Line; \
2143 if (PPU.Mode7Repeat == 0) \
2144 yy += (VOffset - CentreY) % 1023; \
2146 yy += VOffset - CentreY; \
2147 int BB = l->MatrixB * yy + (CentreX << 8); \
2148 int DD = l->MatrixD * yy + (CentreY << 8); \
2150 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2153 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2156 uint8 * const VRAM1 = Memory.VRAM + 1; \
2157 if (GFX.r2130 & 1) \
2159 if (IPPU.DirectColourMapsNeedRebuild) \
2160 S9xBuildDirectColourMaps (); \
2161 GFX.ScreenColors = DirectColourMaps [0]; \
2164 GFX.ScreenColors = IPPU.ScreenColors; \
2169 uint32 Right = 256; \
2170 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2175 Screen += GFX.StartY * GFX.Pitch; \
2176 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2177 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2178 RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2182 void DrawBGMode7Background (uint8 *Screen, int bg)
2184 RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & bmask))
2187 void DrawBGMode7Background16 (uint8 *Screen, int bg)
2189 RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2192 void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2194 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2195 (*(d + GFX.DepthDelta) != 1 ?
2196 COLOR_ADD (GFX.ScreenColors [b & bmask],
2198 COLOR_ADD (GFX.ScreenColors [b & bmask],
2200 GFX.ScreenColors [b & bmask]);
2203 void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2205 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2206 (*(d + GFX.DepthDelta) != 1 ?
2207 COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2209 COLOR_ADD (GFX.ScreenColors [b & bmask],
2211 GFX.ScreenColors [b & bmask]);
2214 void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2216 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2217 (*(d + GFX.DepthDelta) != 1 ?
2218 COLOR_SUB (GFX.ScreenColors [b & bmask],
2220 COLOR_SUB (GFX.ScreenColors [b & bmask],
2222 GFX.ScreenColors [b & bmask]);
2225 void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2227 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2228 (*(d + GFX.DepthDelta) != 1 ?
2229 COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2231 COLOR_SUB (GFX.ScreenColors [b & bmask],
2233 GFX.ScreenColors [b & bmask]);
2236 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2239 uint8 *VRAM1 = Memory.VRAM + 1; \
2240 if (GFX.r2130 & 1) \
2242 if (IPPU.DirectColourMapsNeedRebuild) \
2243 S9xBuildDirectColourMaps (); \
2244 GFX.ScreenColors = DirectColourMaps [0]; \
2247 GFX.ScreenColors = IPPU.ScreenColors; \
2253 uint32 Right = 256; \
2254 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2259 Screen += GFX.StartY * GFX.Pitch; \
2260 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2261 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2262 bool8_32 allowSimpleCase = FALSE; \
2263 if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2264 && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2265 && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2267 allowSimpleCase = TRUE; \
2269 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2273 int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2274 int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2276 int CentreX = ((int) l->CentreX << M7) >> M7; \
2277 int CentreY = ((int) l->CentreY << M7) >> M7; \
2279 if (PPU.Mode7VFlip) \
2280 yy = 261 - (int) Line; \
2284 if (PPU.Mode7Repeat == 0) \
2285 yy += (VOffset - CentreY) % 1023; \
2287 yy += VOffset - CentreY; \
2288 bool8_32 simpleCase = FALSE; \
2291 /* Make a special case for the identity matrix, since it's a common case and */ \
2292 /* can be done much more quickly without special effects */ \
2293 if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2295 BB = CentreX << 8; \
2296 DD = (yy + CentreY) << 8; \
2297 simpleCase = TRUE; \
2301 BB = l->MatrixB * yy + (CentreX << 8); \
2302 DD = l->MatrixD * yy + (CentreY << 8); \
2305 for (uint32 clip = 0; clip < ClipCount; clip++) \
2307 if (GFX.pCurrentClip->Count [bg]) \
2309 Left = GFX.pCurrentClip->Left [clip][bg]; \
2310 Right = GFX.pCurrentClip->Right [clip][bg]; \
2311 if (Right <= Left) \
2314 TYPE *p = (TYPE *) Screen + Left; \
2315 uint8 *d = Depth + Left; \
2317 if (PPU.Mode7HFlip) \
2319 startx = Right - 1; \
2334 if (PPU.Mode7Repeat == 0) \
2335 xx = startx + (HOffset - CentreX) % 1023; \
2337 xx = startx + HOffset - CentreX; \
2345 AA = l->MatrixA * xx; \
2346 CC = l->MatrixC * xx; \
2350 if (!PPU.Mode7Repeat) \
2355 int X = ((AA + BB) >> 8) & 0x3ff; \
2356 int Y = (DD >> 8) & 0x3ff; \
2357 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2358 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2359 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2360 if (GFX.Z1 > *d && b) \
2362 TYPE theColor = COLORFUNC; \
2363 *p = (FUNC) | ALPHA_BITS_MASK; \
2366 AA += aa, p++, d++; \
2368 } while (x != endx); \
2374 int X = (AA + BB) >> 8; \
2377 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2383 if (((X | Y) & ~0x3ff) == 0) \
2385 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2386 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2387 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2388 if (GFX.Z1 > *d && b) \
2390 TYPE theColor = COLORFUNC; \
2391 *p = (FUNC) | ALPHA_BITS_MASK; \
2395 else if (PPU.Mode7Repeat == 3) \
2397 X = (x + HOffset) & 7; \
2398 Y = (yy + CentreY) & 7; \
2399 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2400 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2401 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2402 if (GFX.Z1 > *d && b) \
2404 TYPE theColor = COLORFUNC; \
2405 *p = (FUNC) | ALPHA_BITS_MASK; \
2409 AA += aa; p++; d++; \
2411 } while (x != endx); \
2414 else if (!PPU.Mode7Repeat) \
2416 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2417 /* the location of one point in the _sampled_ image, and weight them according */ \
2418 /* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
2421 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2422 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2423 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2424 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2425 /* You can think of this as a kind of mipmapping. */ \
2426 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2428 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2430 uint32 xPos = AA + BB; \
2431 uint32 xPix = xPos >> 8; \
2432 uint32 yPos = CC + DD; \
2433 uint32 yPix = yPos >> 8; \
2434 uint32 X = xPix & 0x3ff; \
2435 uint32 Y = yPix & 0x3ff; \
2436 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2437 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2438 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2439 if (GFX.Z1 > *d && b) \
2441 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2442 uint32 X10 = (xPix + dir) & 0x3ff; \
2443 uint32 Y01 = (yPix + dir) & 0x3ff; \
2444 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2445 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2446 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2447 uint32 p1 = COLORFUNC; \
2448 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2449 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2450 uint32 p2 = COLORFUNC; \
2451 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2452 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2453 uint32 p4 = COLORFUNC; \
2454 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2455 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2456 uint32 p3 = COLORFUNC; \
2457 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2458 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2459 uint32 Xdel = (xPos >> 3) & 0x1F; \
2460 uint32 Ydel = (yPos >> 3) & 0x1F; \
2461 uint32 XY = (Xdel*Ydel) >> 5; \
2462 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2463 uint32 area2 = Xdel - XY; \
2464 uint32 area3 = Ydel - XY; \
2465 uint32 area4 = XY; \
2466 uint32 tempColor = ((area1 * p1) + \
2469 (area4 * p4)) >> 5; \
2470 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2471 *p = (FUNC) | ALPHA_BITS_MASK; \
2477 /* The oversampling method: get the colors at four corners of a square */ \
2478 /* in the _displayed_ image, and average them. It's sharp and clean, but */ \
2479 /* gives the usual huge pixels when the source image gets "close." */ \
2481 /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2482 uint32 aaDelX = aa >> 1; \
2483 uint32 ccDelX = cc >> 1; \
2484 uint32 bbDelY = l->MatrixB >> 1; \
2485 uint32 ddDelY = l->MatrixD >> 1; \
2486 /* Offset the location within the source image so that the four sampled points */ \
2487 /* center around where the single point would otherwise have been drawn. */ \
2488 BB -= (bbDelY >> 1); \
2489 DD -= (ddDelY >> 1); \
2490 AA -= (aaDelX >> 1); \
2491 CC -= (ccDelX >> 1); \
2492 uint32 BB10 = BB + aaDelX; \
2493 uint32 BB01 = BB + bbDelY; \
2494 uint32 BB11 = BB + aaDelX + bbDelY; \
2495 uint32 DD10 = DD + ccDelX; \
2496 uint32 DD01 = DD + ddDelY; \
2497 uint32 DD11 = DD + ccDelX + ddDelY; \
2498 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2500 uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2501 uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2502 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2503 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2504 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2505 if (GFX.Z1 > *d && b) \
2507 /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2508 /* source image that we're going to examine. */ \
2509 uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2510 uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2511 uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2512 uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2513 uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2514 uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2515 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2516 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2517 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2518 TYPE p1 = COLORFUNC; \
2519 b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2520 TYPE p2 = COLORFUNC; \
2521 b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2522 TYPE p3 = COLORFUNC; \
2523 b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2524 TYPE p4 = COLORFUNC; \
2525 TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2526 *p = (FUNC) | ALPHA_BITS_MASK; \
2534 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2536 uint32 xPos = AA + BB; \
2537 uint32 xPix = xPos >> 8; \
2538 uint32 yPos = CC + DD; \
2539 uint32 yPix = yPos >> 8; \
2544 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2550 if (((X | Y) & ~0x3ff) == 0) \
2552 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2553 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2554 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2555 if (GFX.Z1 > *d && b) \
2557 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2558 uint32 X10 = (xPix + dir) & 0x3ff; \
2559 uint32 Y01 = (yPix + dir) & 0x3ff; \
2560 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2561 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2562 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2563 uint32 p1 = COLORFUNC; \
2564 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2565 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2566 uint32 p2 = COLORFUNC; \
2567 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2568 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2569 uint32 p4 = COLORFUNC; \
2570 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2571 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2572 uint32 p3 = COLORFUNC; \
2573 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2574 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2575 uint32 Xdel = (xPos >> 3) & 0x1F; \
2576 uint32 Ydel = (yPos >> 3) & 0x1F; \
2577 uint32 XY = (Xdel*Ydel) >> 5; \
2578 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2579 uint32 area2 = Xdel - XY; \
2580 uint32 area3 = Ydel - XY; \
2581 uint32 area4 = XY; \
2582 uint32 tempColor = ((area1 * p1) + \
2585 (area4 * p4)) >> 5; \
2586 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2587 *p = (FUNC) | ALPHA_BITS_MASK; \
2593 if (PPU.Mode7Repeat == 3) \
2595 X = (x + HOffset) & 7; \
2596 Y = (yy + CentreY) & 7; \
2597 uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2598 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2599 if (GFX.Z1 > *d && b) \
2601 TYPE theColor = COLORFUNC; \
2602 *p = (FUNC) | ALPHA_BITS_MASK; \
2612 STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2614 register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2615 ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2616 ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2617 ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2618 register uint32 y = (A & TWO_LOW_BITS_MASK) +
2619 (B & TWO_LOW_BITS_MASK) +
2620 (C & TWO_LOW_BITS_MASK) +
2621 (D & TWO_LOW_BITS_MASK);
2622 y = (y>>2) & TWO_LOW_BITS_MASK;
2626 void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2628 RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2631 void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2633 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2634 (*(d + GFX.DepthDelta) != 1 ?
2635 (COLOR_ADD (theColor,
2637 (COLOR_ADD (theColor,
2638 GFX.FixedColour))) :
2639 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2642 void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2644 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2645 (*(d + GFX.DepthDelta) != 1 ?
2646 COLOR_ADD1_2 (theColor,
2648 COLOR_ADD (theColor,
2650 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2653 void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2655 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2656 (*(d + GFX.DepthDelta) != 1 ?
2657 COLOR_SUB (theColor,
2659 COLOR_SUB (theColor,
2661 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2664 void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2666 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2667 (*(d + GFX.DepthDelta) != 1 ?
2668 COLOR_SUB1_2 (theColor,
2670 COLOR_SUB (theColor,
2672 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2675 #define _BUILD_SETUP(F) \
2676 GFX.BuildPixel = BuildPixel##F; \
2677 GFX.BuildPixel2 = BuildPixel2##F; \
2678 GFX.DecomposePixel = DecomposePixel##F; \
2679 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2680 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2681 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2682 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2683 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2684 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2685 MAX_RED = MAX_RED_##F; \
2686 MAX_GREEN = MAX_GREEN_##F; \
2687 MAX_BLUE = MAX_BLUE_##F; \
2688 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2689 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2690 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2691 GREEN_LOW_BIT_MASK_##F | \
2692 BLUE_LOW_BIT_MASK_##F); \
2693 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2694 GREEN_HI_BIT_MASK_##F | \
2695 BLUE_HI_BIT_MASK_##F); \
2696 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2697 GREEN_HI_BIT_MASK_##F | \
2698 BLUE_HI_BIT_MASK_##F) << 1); \
2699 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2700 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2701 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2702 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2703 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2704 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2705 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2706 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2707 ~TWO_LOW_BITS_MASK ) >> 2);
2709 void RenderScreen (uint8 *Screen, bool8_32 sub, bool8_32 force_no_add, uint8 D)
2721 GFX.pCurrentClip = &IPPU.Clip [0];
2722 BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2723 BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2724 BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2725 BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2726 OB = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2730 GFX.pCurrentClip = &IPPU.Clip [1];
2731 BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2732 BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2733 BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2734 BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2735 OB = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2738 sub |= force_no_add;
2740 if (PPU.BGMode <= 1)
2744 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2749 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2750 DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2754 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2755 DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2759 SelectTileRenderer (sub || !SUB_OR_ADD(2));
2760 DrawBackground (PPU.BGMode, 2, D + 3,
2761 (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2763 if (BG3 && PPU.BGMode == 0)
2765 SelectTileRenderer (sub || !SUB_OR_ADD(3));
2766 DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2769 else if (PPU.BGMode != 7)
2773 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2778 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2779 DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2781 if (PPU.BGMode != 6 && BG1)
2783 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2784 DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2791 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2794 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2798 if (Memory.FillRAM [0x2133] & 0x40)
2800 GFX.Mode7Mask = 0x7f;
2801 GFX.Mode7PriorityMask = 0x80;
2802 Mode7Depths [0] = 5 + D;
2803 Mode7Depths [1] = 9 + D;
2808 GFX.Mode7Mask = 0xff;
2809 GFX.Mode7PriorityMask = 0;
2810 Mode7Depths [0] = 5 + D;
2811 Mode7Depths [1] = 5 + D;
2814 if (sub || !SUB_OR_ADD(0))
2816 if (!Settings.Mode7Interpolate)
2817 DrawBGMode7Background16 (Screen, bg);
2819 DrawBGMode7Background16_i (Screen, bg);
2823 if (GFX.r2131 & 0x80)
2825 if (GFX.r2131 & 0x40)
2827 if (!Settings.Mode7Interpolate)
2828 DrawBGMode7Background16Sub1_2 (Screen, bg);
2830 DrawBGMode7Background16Sub1_2_i (Screen, bg);
2834 if (!Settings.Mode7Interpolate)
2835 DrawBGMode7Background16Sub (Screen, bg);
2837 DrawBGMode7Background16Sub_i (Screen, bg);
2842 if (GFX.r2131 & 0x40)
2844 if (!Settings.Mode7Interpolate)
2845 DrawBGMode7Background16Add1_2 (Screen, bg);
2847 DrawBGMode7Background16Add1_2_i (Screen, bg);
2851 if (!Settings.Mode7Interpolate)
2852 DrawBGMode7Background16Add (Screen, bg);
2854 DrawBGMode7Background16Add_i (Screen, bg);
2864 static void DisplayChar(uint8 *Screen, uint8 c)
2866 int line = (((c & 0x7f) - 32) >> 4) * font_height;
2867 int offset = (((c & 0x7f) - 32) & 15) * font_width;
2870 uint16 *s = (uint16 *) Screen;
2871 for (h = 0; h < font_height; h++, line++,
2872 s += GFX.PPL - font_width)
2874 for (w = 0; w < font_width; w++, s++)
2876 uint8 p = font [line][offset + w];
2887 static void S9xDisplayFrameRate()
2889 const unsigned int char_width = (font_width - 1) * sizeof (uint16);
2890 uint8 *Screen = GFX.Screen + 2 +
2891 (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch;
2895 if (Settings.TurboMode) {
2896 len = sprintf(string, "%u",
2897 IPPU.DisplayedRenderedFrameCount);
2899 len = sprintf(string, "%2u/%02u",
2900 IPPU.DisplayedRenderedFrameCount,
2901 (unsigned int) Memory.ROMFramesPerSecond);
2904 for (int i = 0; i < len; i++) {
2905 DisplayChar(Screen, string[i]);
2906 Screen += char_width;
2910 static void S9xDisplayString(const char *string)
2912 const unsigned int char_width = (font_width - 1) * sizeof (uint16);
2913 uint8 *Screen = GFX.Screen + 2 +
2914 (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch;
2915 int len = strlen (string);
2916 int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
2920 for (i = 0; i < len; i++, char_count++)
2922 if (char_count >= max_chars || string [i] < 32)
2924 Screen -= char_width * max_chars;
2925 Screen += font_height * GFX.Pitch;
2926 if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
2928 char_count -= max_chars;
2930 if (string [i] < 32)
2932 DisplayChar (Screen, string [i]);
2933 Screen += char_width;
2937 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
2943 unsigned char *memoryfillram = Memory.FillRAM;
2945 // get local copies of vid registers to be used later
2946 GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN
2947 GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
2948 GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
2949 GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
2951 // If external sync is off and
2952 // main screens have not been configured the same as the sub screen and
2953 // color addition and subtraction has been diabled then
2955 // anything else it is 0
2956 GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
2957 (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
2958 (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
2960 // If sprite data has been changed then go through and
2961 // refresh the sprites.
2962 if (IPPU.OBJChanged)
2967 if (PPU.RecomputeClipWindows)
2969 ComputeClipWindows ();
2970 PPU.RecomputeClipWindows = FALSE;
2973 GFX.StartY = IPPU.PreviousLine;
2974 if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
2975 GFX.EndY = PPU.ScreenHeight - 1;
2977 uint32 starty = GFX.StartY;
2978 uint32 endy = GFX.EndY;
2980 #ifndef RC_OPTIMIZED
2981 if (Settings.SupportHiRes &&
2982 (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace)) {
2983 if (PPU.BGMode == 5 || PPU.BGMode == 6) {
2984 IPPU.RenderedScreenWidth = 512;
2988 if (IPPU.LatchedInterlace) {
2989 starty = GFX.StartY * 2;
2990 endy = GFX.EndY * 2 + 1;
2993 if (!IPPU.DoubleWidthPixels) {
2994 // The game has switched from lo-res to hi-res mode part way down
2995 // the screen. Scale any existing lo-res pixels on screen
2996 for (register uint32 y = 0; y < GFX.StartY; y++) {
2997 register uint16 *p =
2998 (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
2999 register uint16 *q =
3000 (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3001 for (register int x = 255; x >= 0; x--, p--, q -= 2) {
3006 IPPU.DoubleWidthPixels = TRUE;
3009 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3011 uint32 black = BLACK | (BLACK << 16);
3013 // Are we worrying about transparencies?
3014 if (Settings.Transparency)
3018 GFX.r2131 = 0x5f; //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3019 GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3020 Memory.FillRAM [0x212d]) & 15;
3021 GFX.r212c &= ~GFX.r212d; // make sure the main BG reg is the reverse of the sub BG reg
3022 GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3025 // Check to see if any transparency effects are currently in use
3026 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3027 (GFX.r2130 & 0x30) != 0x30 &&
3028 !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3030 // transparency effects in use, so lets get busy!
3031 struct ClipData *pClip;
3033 GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3034 IPPU.XB [PPU.FixedColourGreen],
3035 IPPU.XB [PPU.FixedColourBlue]);
3036 fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3037 // Clear the z-buffer, marking areas 'covered' by the fixed
3038 // colour as depth 1.
3039 pClip = &IPPU.Clip [1];
3041 // Clear the z-buffer
3043 if (pClip->Count [5])
3046 // Colour window enabled.
3048 for (uint32 y = starty; y <= endy; y++)
3050 ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3051 IPPU.RenderedScreenWidth);
3052 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3053 IPPU.RenderedScreenWidth);
3055 if (IPPU.Clip [0].Count [5])
3057 memset ((GFX.SubScreen + y * GFX.Pitch), black, IPPU.RenderedScreenWidth);
3059 for (uint32 c = 0; c < pClip->Count [5]; c++)
3061 if (pClip->Right [c][5] > pClip->Left [c][5])
3063 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3064 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3065 if (IPPU.Clip [0].Count [5])
3067 // Blast, have to clear the sub-screen to the fixed-colour
3068 // because there is a colour window in effect clipping
3069 // the main screen that will allow the sub-screen
3070 // 'underneath' to show through.
3071 memset ((GFX.SubScreen + y * GFX.Pitch) + pClip->Left [c][5] * x2,
3073 pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3079 #else // NOT RC_OPTIMIZED
3080 // loop around all of the lines being updated
3081 for (uint32 y = starty; y <= endy; y++)
3083 // Clear the subZbuffer
3084 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3085 IPPU.RenderedScreenWidth>>2);
3086 // Clear the Zbuffer
3087 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3088 IPPU.RenderedScreenWidth>>2);
3090 // if there is clipping then clear subscreen to a black color
3091 if (IPPU.Clip [0].Count [5])
3093 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch), black, IPPU.RenderedScreenWidth>>1);
3096 // loop through all window clippings
3097 for (uint32 c = 0; c < pClip->Count [5]; c++)
3099 if (pClip->Right [c][5] > pClip->Left [c][5])
3101 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3102 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3103 if (IPPU.Clip [0].Count [5])
3105 // Blast, have to clear the sub-screen to the fixed-colour
3106 // because there is a colour window in effect clipping
3107 // the main screen that will allow the sub-screen
3108 // 'underneath' to show through.
3110 register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch);
3111 register uint16 *q = p + pClip->Right [c][5] * x2;
3112 p += pClip->Left [c][5] * x2;
3115 *p++ = (uint16) GFX.FixedColour;
3125 // No windows are clipping the main screen
3126 // this simplifies the screen clearing process
3129 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3132 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3133 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3137 for (uint32 y = starty; y <= endy; y++)
3139 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3140 IPPU.RenderedScreenWidth);
3141 memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3142 IPPU.RenderedScreenWidth);
3146 if (IPPU.Clip [0].Count [5])
3148 // Blast, have to clear the sub-screen to the fixed-colour
3149 // because there is a colour window in effect clipping
3150 // the main screen that will allow the sub-screen
3151 // 'underneath' to show through.
3152 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3154 memset ((GFX.SubScreen + starty * GFX.Pitch),
3155 GFX.FixedColour | (GFX.FixedColour << 16),
3156 GFX.Pitch * (endy - starty - 1));
3160 for (uint32 y = starty; y <= endy; y++)
3162 memset ((GFX.SubScreen + y * GFX.Pitch),
3163 GFX.FixedColour | (GFX.FixedColour << 16),
3164 IPPU.RenderedScreenWidth);
3169 #else // NOT RC_OPTIMIZED
3170 // loop through all of the lines to be updated
3171 for (uint32 y = starty; y <= endy; y++)
3173 // Clear the Zbuffer
3174 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3175 IPPU.RenderedScreenWidth>>2);
3176 // clear the sub Zbuffer to 1
3177 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3178 IPPU.RenderedScreenWidth>>2);
3179 if (IPPU.Clip [0].Count [5])
3181 // Blast, have to clear the sub-screen to the fixed-colour
3182 // because there is a colour window in effect clipping
3183 // the main screen that will allow the sub-screen
3184 // 'underneath' to show through.
3187 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch), fixedColour,
3188 IPPU.RenderedScreenWidth>>1);
3195 if (ANYTHING_ON_SUB)
3197 GFX.DB = GFX.SubZBuffer;
3198 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3201 if (IPPU.Clip [0].Count [5])
3203 for (uint32 y = starty; y <= endy; y++)
3205 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch);
3206 register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3207 register uint8 *e = d + SNES_WIDTH;
3212 *p = *(p + GFX.Delta);
3221 GFX.DB = GFX.ZBuffer;
3222 RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3225 uint32 back = IPPU.ScreenColors [0];
3230 pClip = &IPPU.Clip [0];
3232 for (uint32 y = starty; y <= endy; y++)
3234 if (!(Count = pClip->Count [5]))
3241 for (uint32 b = 0; b < Count; b++)
3243 if (pClip->Count [5])
3245 Left = pClip->Left [b][5] * x2;
3246 Right = pClip->Right [b][5] * x2;
3251 if (GFX.r2131 & 0x80)
3253 if (GFX.r2131 & 0x40)
3255 // Subtract, halving the result.
3256 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3257 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3258 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3259 register uint8 *e = d + Right;
3260 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3270 *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3285 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3286 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3287 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3288 register uint8 *e = d + Right;
3289 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3299 *p = COLOR_SUB (back, *(p + GFX.Delta));
3313 if (GFX.r2131 & 0x40)
3315 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3316 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3317 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3318 register uint8 *e = d + Right;
3319 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3328 *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3343 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3344 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3345 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3346 register uint8 *e = d + Right;
3347 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3356 *p = COLOR_ADD (back, *(p + GFX.Delta));
3370 if (!pClip->Count [5])
3372 // The backdrop has not been cleared yet - so
3373 // copy the sub-screen to the main screen
3374 // or fill it with the back-drop colour if the
3375 // sub-screen is clear.
3376 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3377 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3378 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3379 register uint8 *e = d + Right;
3388 *p = *(p + GFX.Delta);
3390 *p = GFX.FixedColour;
3407 // Subscreen not being added to back
3408 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3409 pClip = &IPPU.Clip [0];
3411 if (pClip->Count [5])
3413 for (uint32 y = starty; y <= endy; y++)
3415 for (uint32 b = 0; b < pClip->Count [5]; b++)
3417 uint32 Left = pClip->Left [b][5] * x2;
3418 uint32 Right = pClip->Right [b][5] * x2;
3419 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3420 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3421 register uint8 *e = d + Right;
3435 for (uint32 y = starty; y <= endy; y++)
3437 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch);
3438 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3439 register uint8 *e = d + 256 * x2;
3459 // 16bit and transparency but currently no transparency effects in
3462 // get the back colour of the current screen
3463 uint32 back = IPPU.ScreenColors [0] |
3464 (IPPU.ScreenColors [0] << 16);
3466 // if forceblanking in use then use black instead of the back color
3467 if (PPU.ForcedBlanking)
3470 // not sure what Clip is used for yet
3471 // could be a check to see if there is any clipping present?
3472 if (IPPU.Clip [0].Count[5])
3476 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3478 memset (GFX.Screen + starty * GFX.Pitch, black,
3479 GFX.Pitch * (endy - starty - 1));
3483 for (uint32 y = starty; y <= endy; y++)
3485 memset (GFX.Screen + y * GFX.Pitch, black,
3489 for (uint32 y = starty; y <= endy; y++)
3491 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3493 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3496 memset ((GFX.Screen + y * GFX.Pitch) + IPPU.Clip [0].Left [c][5] * x2,
3498 IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3503 // loop through all of the lines that are going to be updated as part of this screen update
3504 for (uint32 y = starty; y <= endy; y++)
3506 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), black,
3507 IPPU.RenderedScreenWidth>>1);
3511 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3513 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3515 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch); // get pointer to current line in screen buffer
3516 register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3517 p += IPPU.Clip [0].Left [c][5] * x2;
3520 *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3530 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3532 memset (GFX.Screen + starty * GFX.Pitch, back,
3533 GFX.Pitch * (endy - starty - 1));
3537 for (uint32 y = starty; y <= endy; y++)
3539 memset (GFX.Screen + y * GFX.Pitch, back,
3544 // there is no clipping to worry about so just fill with the back colour
3545 for (uint32 y = starty; y <= endy; y++)
3547 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), back,
3548 IPPU.RenderedScreenWidth>>1);
3553 // If Forced blanking is not in effect
3554 if (!PPU.ForcedBlanking)
3557 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3559 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3560 GFX.ZPitch * (endy - starty - 1));
3564 for (uint32 y = starty; y <= endy; y++)
3566 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3571 // Clear the Zbuffer for each of the lines which are going to be updated
3572 for (uint32 y = starty; y <= endy; y++)
3574 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3578 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3579 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3583 else // Transparencys are disabled, ahh lovely ... nice and easy.
3585 // get back colour to be used in clearing the screen
3586 register uint32 back;
3587 if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3588 (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3590 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3591 (IPPU.XB[PPU.FixedColourGreen] << 6) |
3592 (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3593 back = (back << 16) | back;
3597 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3600 // if Forcedblanking in use then back colour becomes black
3601 if (PPU.ForcedBlanking)
3605 SelectTileRenderer (TRUE); //selects the tile renderers to be used
3606 // TRUE means to use the default
3607 // FALSE means use best renderer based on current
3608 // graphics register settings
3611 // now clear all graphics lines which are being updated using the back colour
3612 for (register uint32 y = starty; y <= endy; y++)
3614 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), back,
3615 IPPU.RenderedScreenWidth>>1);
3618 if (!PPU.ForcedBlanking)
3620 // Loop through all lines being updated and clear the
3621 // zbuffer for each of the lines
3622 for (uint32 y = starty; y <= endy; y++)
3624 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3625 IPPU.RenderedScreenWidth>>2);
3627 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3628 GFX.pCurrentClip = &IPPU.Clip [0];
3630 // Define an inline function to handle clipping
3631 #define FIXCLIP(n) \
3632 if (GFX.r212c & (1 << (n))) \
3633 GFX.pCurrentClip = &IPPU.Clip [0]; \
3635 GFX.pCurrentClip = &IPPU.Clip [1]
3637 // Define an inline function to handle which BGs are being displayed
3638 #define DISPLAY(n) \
3640 (!(PPU.BG_Forced & n) && (GFX.r212c & n)) || \
3641 (((GFX.r212d & n) && subadd)) \
3644 uint8 subadd = GFX.r2131 & 0x3f;
3646 // go through all BGS are check if they need to be displayed
3647 bool BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3648 bool BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3649 bool BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3650 bool BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3651 bool OB = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3653 if (PPU.BGMode <= 1)
3655 // screen modes 0 and 1
3664 DrawBackground (PPU.BGMode, 0, 10, 14);
3669 DrawBackground (PPU.BGMode, 1, 9, 13);
3674 DrawBackground (PPU.BGMode, 2, 3,
3675 (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3677 if (BG3 && PPU.BGMode == 0)
3680 DrawBackground (PPU.BGMode, 3, 2, 5);
3683 else if (PPU.BGMode != 7)
3685 // screen modes 2 and up but not mode 7
3694 DrawBackground (PPU.BGMode, 0, 5, 13);
3696 if (BG1 && PPU.BGMode != 6)
3699 DrawBackground (PPU.BGMode, 1, 2, 9);
3710 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3714 if (Memory.FillRAM [0x2133] & 0x40)
3716 GFX.Mode7Mask = 0x7f;
3717 GFX.Mode7PriorityMask = 0x80;
3718 Mode7Depths [0] = 5;
3719 Mode7Depths [1] = 9;
3724 GFX.Mode7Mask = 0xff;
3725 GFX.Mode7PriorityMask = 0;
3726 Mode7Depths [0] = 5;
3727 Mode7Depths [1] = 5;
3731 if (!Settings.Mode7Interpolate)
3733 DrawBGMode7Background16 (GFX.Screen, bg);
3737 DrawBGMode7Background16_i (GFX.Screen, bg);
3743 #ifndef RC_OPTIMIZE // no hi res
3744 if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3746 if (IPPU.DoubleWidthPixels)
3748 // Mixure of background modes used on screen - scale width
3749 // of all non-mode 5 and 6 pixels.
3750 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3752 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3753 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3754 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3759 if (IPPU.LatchedInterlace)
3761 // Interlace is enabled - double the height of all non-mode 5 and 6
3763 for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3765 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch),
3766 (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch),
3772 IPPU.PreviousLine = IPPU.CurrentLine;
3775 #ifdef GFX_MULTI_FORMAT
3777 #define _BUILD_PIXEL(F) \
3778 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
3780 return (BUILD_PIXEL_##F(R,G,B)); \
3782 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
3784 return (BUILD_PIXEL2_##F(R,G,B)); \
3786 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
3788 DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
3791 _BUILD_PIXEL(RGB565)
3792 _BUILD_PIXEL(RGB555)
3793 _BUILD_PIXEL(BGR565)
3794 _BUILD_PIXEL(BGR555)
3795 _BUILD_PIXEL(GBR565)
3796 _BUILD_PIXEL(GBR555)
3797 _BUILD_PIXEL(RGB5551)
3799 bool8_32 S9xSetRenderPixelFormat (int format)
3801 extern uint32 current_graphic_format;
3803 current_graphic_format = format;
3808 _BUILD_SETUP(RGB565)
3811 _BUILD_SETUP(RGB555)
3814 _BUILD_SETUP(BGR565)
3817 _BUILD_SETUP(BGR555)
3820 _BUILD_SETUP(GBR565)
3823 _BUILD_SETUP(GBR555)
3826 _BUILD_SETUP(RGB5551)