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.
53 #define USE_CRAZY_OPTS
58 void ComputeClipWindows ();
59 static void S9xDisplayFrameRate ();
60 static void S9xDisplayString (const char *string);
62 extern uint8 BitShifts[8][4];
63 extern uint8 TileShifts[8][4];
64 extern uint8 PaletteShifts[8][4];
65 extern uint8 PaletteMasks[8][4];
66 extern uint8 Depths[8][4];
67 extern uint8 BGSizes [2];
69 extern NormalTileRenderer DrawTilePtr;
70 extern ClippedTileRenderer DrawClippedTilePtr;
71 extern NormalTileRenderer DrawHiResTilePtr;
72 extern ClippedTileRenderer DrawHiResClippedTilePtr;
73 extern LargePixelRenderer DrawLargePixelPtr;
77 extern struct SLineData LineData[240];
78 extern struct SLineMatrixData LineMatrixData [240];
80 extern uint8 Mode7Depths [2];
83 (GFX.r212c & (1 << (N)) && \
84 !(PPU.BG_Forced & (1 << (N))))
86 #define SUB_OR_ADD(N) \
87 (GFX.r2131 & (1 << (N)))
90 ((GFX.r2130 & 0x30) != 0x30 && \
92 (GFX.r212d & (1 << N)) && \
93 !(PPU.BG_Forced & (1 << (N))))
95 #define ANYTHING_ON_SUB \
96 ((GFX.r2130 & 0x30) != 0x30 && \
100 #define ADD_OR_SUB_ON_ANYTHING \
103 #define BLACK BUILD_PIXEL(0,0,0)
105 bool8_32 S9xGraphicsInit ()
107 register uint32 PixelOdd = 1;
108 register uint32 PixelEven = 2;
110 #ifdef GFX_MULTI_FORMAT
111 if (GFX.BuildPixel == NULL)
112 S9xSetRenderPixelFormat (RGB565);
115 for (uint8 bitshift = 0; bitshift < 4; bitshift++)
117 for (register int i = 0; i < 16; i++)
119 register uint32 h = 0;
120 register uint32 l = 0;
122 #if defined(LSB_FIRST)
141 h |= (PixelOdd << 24);
143 h |= (PixelOdd << 16);
145 h |= (PixelOdd << 8);
149 l |= (PixelOdd << 24);
151 l |= (PixelOdd << 16);
153 l |= (PixelOdd << 8);
158 odd_high[bitshift][i] = h;
159 odd_low[bitshift][i] = l;
162 #if defined(LSB_FIRST)
168 h |= PixelEven << 16;
170 h |= PixelEven << 24;
176 l |= PixelEven << 16;
178 l |= PixelEven << 24;
181 h |= (PixelEven << 24);
183 h |= (PixelEven << 16);
185 h |= (PixelEven << 8);
189 l |= (PixelEven << 24);
191 l |= (PixelEven << 16);
193 l |= (PixelEven << 8);
198 even_high[bitshift][i] = h;
199 even_low[bitshift][i] = l;
205 GFX.InfoStringTimeout = 0;
206 GFX.InfoString = NULL;
209 IPPU.OBJChanged = TRUE;
210 if (Settings.Transparency)
211 Settings.SixteenBit = TRUE;
213 IPPU.DirectColourMapsNeedRebuild = TRUE;
215 if (Settings.SixteenBit)
217 DrawTilePtr = DrawTile16;
218 DrawClippedTilePtr = DrawClippedTile16;
219 DrawLargePixelPtr = DrawLargePixel16;
220 DrawHiResTilePtr= DrawHiResTile16;
221 DrawHiResClippedTilePtr = DrawHiResClippedTile16;
222 GFX.PPL = GFX.Pitch >> 1;
223 GFX.PPLx2 = GFX.Pitch;
227 DrawTilePtr = DrawTile;
228 DrawClippedTilePtr = DrawClippedTile;
229 DrawLargePixelPtr = DrawLargePixel;
230 DrawHiResTilePtr = DrawTile;
231 DrawHiResClippedTilePtr = DrawClippedTile;
233 GFX.PPLx2 = GFX.Pitch * 2;
235 S9xFixColourBrightness ();
237 if (Settings.SixteenBit)
239 if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
242 if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
243 !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
247 free ((char *) GFX.ZERO_OR_X2);
248 GFX.ZERO_OR_X2 = NULL;
252 free ((char *) GFX.X2);
259 // Build a lookup table that multiplies a packed RGB value by 2 with
261 for (r = 0; r <= MAX_RED; r++)
266 for (g = 0; g <= MAX_GREEN; g++)
271 for (b = 0; b <= MAX_BLUE; b++)
276 GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
277 GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
281 ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
282 ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
283 // Build a lookup table that if the top bit of the color value is zero
284 // then the value is zero, otherwise multiply the value by 2. Used by
285 // the color subtraction code.
287 #if defined(OLD_COLOUR_BLENDING)
288 for (r = 0; r <= MAX_RED; r++)
291 if ((r2 & 0x10) == 0)
294 r2 = (r2 << 1) & MAX_RED;
296 for (g = 0; g <= MAX_GREEN; g++)
299 if ((g2 & GREEN_HI_BIT) == 0)
302 g2 = (g2 << 1) & MAX_GREEN;
304 for (b = 0; b <= MAX_BLUE; b++)
307 if ((b2 & 0x10) == 0)
310 b2 = (b2 << 1) & MAX_BLUE;
312 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
313 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
318 for (r = 0; r <= MAX_RED; r++)
321 if ((r2 & 0x10) == 0)
324 r2 = (r2 << 1) & MAX_RED;
328 for (g = 0; g <= MAX_GREEN; g++)
331 if ((g2 & GREEN_HI_BIT) == 0)
334 g2 = (g2 << 1) & MAX_GREEN;
338 for (b = 0; b <= MAX_BLUE; b++)
341 if ((b2 & 0x10) == 0)
344 b2 = (b2 << 1) & MAX_BLUE;
348 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
349 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
355 // Build a lookup table that if the top bit of the color value is zero
356 // then the value is zero, otherwise its just the value.
357 for (r = 0; r <= MAX_RED; r++)
360 if ((r2 & 0x10) == 0)
365 for (g = 0; g <= MAX_GREEN; g++)
368 if ((g2 & GREEN_HI_BIT) == 0)
372 for (b = 0; b <= MAX_BLUE; b++)
375 if ((b2 & 0x10) == 0)
380 GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
381 GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
389 GFX.ZERO_OR_X2 = NULL;
396 void S9xGraphicsDeinit (void)
398 // Free any memory allocated in S9xGraphicsInit
401 free ((char *) GFX.X2);
406 free ((char *) GFX.ZERO_OR_X2);
407 GFX.ZERO_OR_X2 = NULL;
411 free ((char *) GFX.ZERO);
416 void S9xBuildDirectColourMaps ()
418 for (uint32 p = 0; p < 8; p++)
420 for (uint32 c = 0; c < 256; c++)
423 DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
424 ((c & 0x38) >> 1) | (p & 2),
425 ((c & 0xc0) >> 3) | (p & 4));
428 IPPU.DirectColourMapsNeedRebuild = FALSE;
431 void S9xStartScreenRefresh ()
433 if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0)
434 GFX.InfoString = NULL;
436 if (IPPU.RenderThisFrame)
439 if (!S9xInitUpdate ())
441 IPPU.RenderThisFrame = FALSE;
445 IPPU.RenderedFramesCount++;
446 IPPU.PreviousLine = IPPU.CurrentLine = 0;
447 IPPU.MaxBrightness = PPU.Brightness;
448 IPPU.LatchedBlanking = PPU.ForcedBlanking;
449 IPPU.LatchedInterlace = (Memory.FillRAM[0x2133] & 1);
450 IPPU.RenderedScreenWidth = 256;
451 IPPU.RenderedScreenHeight = PPU.ScreenHeight;
452 IPPU.DoubleWidthPixels = FALSE;
453 GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
454 GFX.PPL = GFX.PPLx2 >> 1;
455 PPU.RecomputeClipWindows = TRUE;
456 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
457 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
459 if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0)
461 IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount;
462 IPPU.RenderedFramesCount = 0;
467 void RenderLine (uint8 C)
469 if (IPPU.RenderThisFrame)
472 LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
473 LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
474 LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
475 LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
479 struct SLineMatrixData *p = &LineMatrixData [C];
480 p->MatrixA = PPU.MatrixA;
481 p->MatrixB = PPU.MatrixB;
482 p->MatrixC = PPU.MatrixC;
483 p->MatrixD = PPU.MatrixD;
484 p->CentreX = PPU.CentreX;
485 p->CentreY = PPU.CentreY;
490 if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
491 PPU.BG[2].HOffset == 0xe000)
493 LineData[C].BG[2].VOffset = 0xe1;
494 LineData[C].BG[2].HOffset = 0;
500 LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
501 LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
502 LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
503 LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
507 IPPU.CurrentLine = C + 1;
512 void S9xEndScreenRefresh()
514 IPPU.HDMAStarted = FALSE;
517 if (IPPU.RenderThisFrame)
520 if (IPPU.ColorsChanged)
522 uint32 saved = PPU.CGDATA[0];
523 if (!Settings.SixteenBit)
525 // Hack for Super Mario World - to get its sky blue
526 // (It uses Fixed colour addition on the backdrop colour)
527 if (!(Memory.FillRAM [0x2131] & 0x80) &&
528 (Memory.FillRAM[0x2131] & 0x20) &&
529 (PPU.FixedColourRed || PPU.FixedColourGreen ||
530 PPU.FixedColourBlue))
532 PPU.CGDATA[0] = PPU.FixedColourRed |
533 (PPU.FixedColourGreen << 5) |
534 (PPU.FixedColourBlue << 10);
537 IPPU.ColorsChanged = FALSE;
541 PPU.CGDATA[0] = saved;
543 GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
544 GFX.PPL = GFX.PPLx2 >> 1;
546 if (Settings.DisplayFrameRate)
547 S9xDisplayFrameRate ();
549 S9xDisplayString (GFX.InfoString);
551 S9xDeinitUpdate (IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
552 Settings.SixteenBit);
560 if (CPU.Flags & FRAME_ADVANCE_FLAG)
562 if (ICPU.FrameAdvanceCount)
564 ICPU.FrameAdvanceCount--;
565 IPPU.RenderThisFrame = TRUE;
570 CPU.Flags &= ~FRAME_ADVANCE_FLAG;
571 CPU.Flags |= DEBUG_MODE_FLAG;
576 if (CPU.SRAMModified)
578 if (!CPU.AutoSaveTimer)
580 if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
581 CPU.SRAMModified = FALSE;
585 if (!--CPU.AutoSaveTimer)
588 CPU.SRAMModified = FALSE;
594 void S9xSetInfoString (const char *string)
596 GFX.InfoString = string;
597 GFX.InfoStringTimeout = 120;
600 INLINE void SelectTileRenderer (bool8_32 normal)
604 DrawTilePtr = DrawTile16;
605 DrawClippedTilePtr = DrawClippedTile16;
606 DrawLargePixelPtr = DrawLargePixel16;
610 if (GFX.r2131 & 0x80)
612 if (GFX.r2131 & 0x40)
616 DrawTilePtr = DrawTile16Sub1_2;
617 DrawClippedTilePtr = DrawClippedTile16Sub1_2;
621 // Fixed colour substraction
622 DrawTilePtr = DrawTile16FixedSub1_2;
623 DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
625 DrawLargePixelPtr = DrawLargePixel16Sub1_2;
629 DrawTilePtr = DrawTile16Sub;
630 DrawClippedTilePtr = DrawClippedTile16Sub;
631 DrawLargePixelPtr = DrawLargePixel16Sub;
636 if (GFX.r2131 & 0x40)
640 DrawTilePtr = DrawTile16Add1_2;
641 DrawClippedTilePtr = DrawClippedTile16Add1_2;
645 // Fixed colour addition
646 DrawTilePtr = DrawTile16FixedAdd1_2;
647 DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
649 DrawLargePixelPtr = DrawLargePixel16Add1_2;
653 DrawTilePtr = DrawTile16Add;
654 DrawClippedTilePtr = DrawClippedTile16Add;
655 DrawLargePixelPtr = DrawLargePixel16Add;
666 switch (PPU.OBJSizeSelect)
697 int FirstSprite = PPU.FirstSprite & 0x7f;
702 if (PPU.OBJ [S].Size)
707 long VPos = PPU.OBJ [S].VPos;
709 if (VPos >= PPU.ScreenHeight)
711 if (PPU.OBJ [S].HPos < 256 && PPU.OBJ [S].HPos > -Size &&
712 VPos < PPU.ScreenHeight && VPos > -Size)
714 GFX.OBJList [C++] = S;
716 GFX.VPositions[S] = VPos;
719 } while (S != FirstSprite);
721 // Terminate the list
722 GFX.OBJList [C] = -1;
723 IPPU.OBJChanged = FALSE;
726 void DrawOBJS (bool8_32 OnMain = FALSE, uint8 D = 0)
729 uint32 BaseTile, Tile;
735 BG.TileAddress = PPU.OBJNameBase;
736 BG.StartPalette = 128;
739 BG.Buffer = IPPU.TileCache [TILE_4BIT];
740 BG.Buffered = IPPU.TileCached [TILE_4BIT];
741 BG.NameSelect = PPU.OBJNameSelect;
742 BG.DirectColourMode = FALSE;
749 for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
751 int VPos = GFX.VPositions [S];
752 int Size = GFX.Sizes[S];
756 if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
759 if (OnMain && SUB_OR_ADD(4))
761 SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
764 BaseTile = PPU.OBJ[S].Name | (PPU.OBJ[S].Palette << 10);
766 if (PPU.OBJ[S].HFlip)
768 BaseTile += ((Size >> 3) - 1) | H_FLIP;
771 if (PPU.OBJ[S].VFlip)
774 int clipcount = GFX.pCurrentClip->Count [4];
778 GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
780 for (int clip = 0; clip < clipcount; clip++)
784 if (!GFX.pCurrentClip->Count [4])
791 Left = GFX.pCurrentClip->Left [clip][4];
792 Right = GFX.pCurrentClip->Right [clip][4];
795 if (Right <= Left || PPU.OBJ[S].HPos + Size <= Left ||
796 PPU.OBJ[S].HPos >= Right)
799 for (int Y = 0; Y < Size; Y += 8)
801 if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
808 if ((StartLine = VPos + Y) < (int) GFX.StartY)
810 StartLine = GFX.StartY - StartLine;
811 LineCount = 8 - StartLine;
818 if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
819 if ((LineCount -= Last) <= 0)
822 TileLine = StartLine << 3;
823 O = (VPos + Y + StartLine) * GFX.PPL;
824 if (!PPU.OBJ[S].VFlip)
825 Tile = BaseTile + (Y << 1);
827 Tile = BaseTile + ((Size - Y - 8) << 1);
829 int Middle = Size >> 3;
830 if (PPU.OBJ[S].HPos < Left)
832 Tile += ((Left - PPU.OBJ[S].HPos) >> 3) * TileInc;
833 Middle -= (Left - PPU.OBJ[S].HPos) >> 3;
834 O += Left * GFX.PixSize;
835 if ((Offset = (Left - PPU.OBJ[S].HPos) & 7))
837 O -= Offset * GFX.PixSize;
839 int Width = Right - Left;
842 (*DrawClippedTilePtr) (Tile, O, Offset, W,
843 TileLine, LineCount);
849 O += 8 * GFX.PixSize;
853 O += PPU.OBJ[S].HPos * GFX.PixSize;
855 if (PPU.OBJ[S].HPos + Size >= Right)
857 Middle -= ((PPU.OBJ[S].HPos + Size + 7) -
859 Offset = (Right - (PPU.OBJ[S].HPos + Size)) & 7;
864 for (int X = 0; X < Middle; X++, O += 8 * GFX.PixSize,
867 (*DrawTilePtr) (Tile, O, TileLine, LineCount);
871 (*DrawClippedTilePtr) (Tile, O, 0, Offset,
872 TileLine, LineCount);
880 void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
889 uint8 depths [2] = {Z1, Z2};
892 BG.StartPalette = bg << 5;
896 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
898 if (PPU.BG[bg].SCSize & 1)
903 if (PPU.BG[bg].SCSize & 2)
908 if (PPU.BG[bg].SCSize & 1)
917 if (BG.TileSize == 16)
928 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
930 uint32 VOffset = LineData [Y].BG[bg].VOffset;
931 uint32 HOffset = LineData [Y].BG[bg].HOffset;
932 uint32 MosaicOffset = Y % PPU.Mosaic;
934 for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
935 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
936 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
939 uint32 MosaicLine = VOffset + Y - MosaicOffset;
941 if (Y + Lines > GFX.EndY)
942 Lines = GFX.EndY + 1 - Y;
943 uint32 VirtAlign = (MosaicLine & 7) << 3;
948 uint32 ScreenLine = MosaicLine >> OffsetShift;
949 uint32 Rem16 = MosaicLine & 15;
951 if (ScreenLine & 0x20)
956 b1 += (ScreenLine & 0x1f) << 5;
957 b2 += (ScreenLine & 0x1f) << 5;
962 uint32 ClipCount = GFX.pCurrentClip->Count [bg];
963 uint32 HPos = HOffset;
964 uint32 PixWidth = PPU.Mosaic;
969 for (uint32 clip = 0; clip < ClipCount; clip++)
971 if (GFX.pCurrentClip->Count [bg])
973 Left = GFX.pCurrentClip->Left [clip][bg];
974 Right = GFX.pCurrentClip->Right [clip][bg];
975 uint32 r = Left % PPU.Mosaic;
976 HPos = HOffset + Left;
977 PixWidth = PPU.Mosaic - r;
979 uint32 s = Y * GFX.PPL + Left * GFX.PixSize;
980 for (uint32 x = Left; x < Right; x += PixWidth,
981 s += PixWidth * GFX.PixSize,
982 HPos += PixWidth, PixWidth = PPU.Mosaic)
984 uint32 Quot = (HPos & OffsetMask) >> 3;
986 if (x + PixWidth >= Right)
987 PixWidth = Right - x;
989 if (BG.TileSize == 8)
992 t = b2 + (Quot & 0x1f);
999 t = b2 + ((Quot >> 1) & 0x1f);
1001 t = b1 + (Quot >> 1);
1004 Tile = READ_2BYTES (t);
1005 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1008 if (BG.TileSize != 8)
1012 // Horizontal flip, but what about vertical flip ?
1015 // Both horzontal & vertical flip
1018 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1024 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1031 // Horizontal flip only
1034 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1040 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1048 // No horizontal flip, but is there a vertical flip ?
1051 // Vertical flip only
1054 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1060 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1070 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1076 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1084 (*DrawLargePixelPtr) (Tile, s, HPos & 7, PixWidth,
1091 void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1105 int VOffsetOffset = BGMode == 4 ? 0 : 32;
1106 uint8 depths [2] = {Z1, Z2};
1108 BG.StartPalette = 0;
1110 BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
1112 if (PPU.BG[2].SCSize & 1)
1117 if (PPU.BG[2].SCSize & 2)
1122 if (PPU.BG[2].SCSize & 1)
1127 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1129 if (PPU.BG[bg].SCSize & 1)
1134 if (PPU.BG[bg].SCSize & 2)
1138 if (PPU.BG[bg].SCSize & 1)
1143 static const int Lines = 1;
1146 int OffsetEnableMask = 1 << (bg + 13);
1148 if (BG.TileSize == 16)
1159 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
1161 uint32 VOff = LineData [Y].BG[2].VOffset;
1162 uint32 HOff = LineData [Y].BG[2].HOffset;
1164 int ScreenLine = VOff >> 3;
1171 if (ScreenLine & 0x20)
1172 s1 = BPS2, s2 = BPS3;
1174 s1 = BPS0, s2 = BPS1;
1176 s1 += (ScreenLine & 0x1f) << 5;
1177 s2 += (ScreenLine & 0x1f) << 5;
1179 int clipcount = GFX.pCurrentClip->Count [bg];
1183 for (int clip = 0; clip < clipcount; clip++)
1188 if (!GFX.pCurrentClip->Count [bg])
1195 Left = GFX.pCurrentClip->Left [clip][bg];
1196 Right = GFX.pCurrentClip->Right [clip][bg];
1204 uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
1215 uint32 TotalCount = 0;
1216 uint32 MaxCount = 8;
1218 uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1219 bool8_32 left_hand_edge = (Left == 0);
1220 Width = Right - Left;
1223 MaxCount = 8 - (Left & 7);
1225 while (Left < Right)
1229 // The SNES offset-per-tile background mode has a
1230 // hardware limitation that the offsets cannot be set
1231 // for the tile at the left-hand edge of the screen.
1232 VOffset = LineData [Y].BG[bg].VOffset;
1233 HOffset = LineHOffset;
1234 left_hand_edge = FALSE;
1238 // All subsequent offset tile data is shifted left by one,
1239 // hence the - 1 below.
1240 Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
1243 s0 = s2 + (Quot2 & 0x1f);
1247 HCellOffset = READ_2BYTES (s0);
1251 VOffset = LineData [Y].BG[bg].VOffset;
1252 HOffset=LineHOffset;
1253 if ((HCellOffset & OffsetEnableMask))
1255 if (HCellOffset & 0x8000)
1256 VOffset = HCellOffset + 1;
1258 HOffset = HCellOffset;
1263 VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
1264 if ((VCellOffset & OffsetEnableMask))
1265 VOffset = VCellOffset + 1;
1267 VOffset = LineData [Y].BG[bg].VOffset;
1269 if ((HCellOffset & OffsetEnableMask))
1270 HOffset = (HCellOffset & ~7)|(LineHOffset&7);
1272 HOffset=LineHOffset;
1275 VirtAlign = ((Y + VOffset) & 7) << 3;
1276 ScreenLine = (VOffset + Y) >> OffsetShift;
1278 if (((VOffset + Y) & 15) > 7)
1289 if (ScreenLine & 0x20)
1294 b1 += (ScreenLine & 0x1f) << 5;
1295 b2 += (ScreenLine & 0x1f) << 5;
1297 HPos = (HOffset + Left) & OffsetMask;
1301 if (BG.TileSize == 8)
1304 t = b2 + (Quot & 0x1f);
1311 t = b2 + ((Quot >> 1) & 0x1f);
1313 t = b1 + (Quot >> 1);
1316 if (MaxCount + TotalCount > Width)
1317 MaxCount = Width - TotalCount;
1322 if (Count > MaxCount)
1325 s -= Offset * GFX.PixSize;
1326 Tile = READ_2BYTES(t);
1327 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1329 if (BG.TileSize == 8)
1330 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines);
1333 if (!(Tile & (V_FLIP | H_FLIP)))
1335 // Normal, unflipped
1336 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1337 s, Offset, Count, VirtAlign, Lines);
1345 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1346 s, Offset, Count, VirtAlign, Lines);
1351 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1352 s, Offset, Count, VirtAlign, Lines);
1358 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1359 s, Offset, Count, VirtAlign, Lines);
1364 TotalCount += Count;
1365 s += (Offset + Count) * GFX.PixSize;
1372 void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
1376 GFX.Pitch = GFX.RealPitch;
1377 GFX.PPL = GFX.PPLx2 >> 1;
1379 uint8 depths [2] = {Z1, Z2};
1388 BG.StartPalette = 0;
1390 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1392 if ((PPU.BG[bg].SCSize & 1))
1397 if ((PPU.BG[bg].SCSize & 2))
1402 if ((PPU.BG[bg].SCSize & 1))
1411 if (BG.TileSize == 16)
1413 VOffsetMask = 0x3ff;
1418 VOffsetMask = 0x1ff;
1421 int endy = GFX.EndY;
1423 for (int Y = GFX.StartY; Y <= endy; Y += Lines)
1426 uint32 VOffset = LineData [y].BG[bg].VOffset;
1427 uint32 HOffset = LineData [y].BG[bg].HOffset;
1428 int VirtAlign = (Y + VOffset) & 7;
1430 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1431 if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
1432 (HOffset != LineData [y + Lines].BG[bg].HOffset))
1436 if (Y + Lines > endy)
1437 Lines = endy + 1 - Y;
1439 int ScreenLine = (VOffset + Y) >> VOffsetShift;
1442 if (((VOffset + Y) & 15) > 7)
1455 if (ScreenLine & 0x20)
1460 b1 += (ScreenLine & 0x1f) << 5;
1461 b2 += (ScreenLine & 0x1f) << 5;
1463 int clipcount = GFX.pCurrentClip->Count [bg];
1466 for (int clip = 0; clip < clipcount; clip++)
1471 if (!GFX.pCurrentClip->Count [bg])
1478 Left = GFX.pCurrentClip->Left [clip][bg] * 2;
1479 Right = GFX.pCurrentClip->Right [clip][bg] * 2;
1485 uint32 s = (Left>>1) * GFX.PixSize + Y * GFX.PPL;
1486 uint32 HPos = (HOffset + Left * GFX.PixSize) & 0x3ff;
1488 uint32 Quot = HPos >> 3;
1493 t = b2 + ((Quot >> 1) & 0x1f);
1495 t = b1 + (Quot >> 1);
1497 Width = Right - Left;
1498 // Left hand edge clipped tile
1501 int Offset = (HPos & 7);
1505 if (s) // XXX: Workaround for underflow (Secret of MANA)
1507 Tile = READ_2BYTES (t);
1508 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1510 if (BG.TileSize == 8)
1512 if (!(Tile & H_FLIP))
1514 // Normal, unflipped
1515 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1516 s, Offset, Count, VirtAlign, Lines);
1521 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1522 s, Offset, Count, VirtAlign, Lines);
1527 if (!(Tile & (V_FLIP | H_FLIP)))
1529 // Normal, unflipped
1530 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1531 s, Offset, Count, VirtAlign, Lines);
1539 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1540 s, Offset, Count, VirtAlign, Lines);
1545 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1546 s, Offset, Count, VirtAlign, Lines);
1552 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1553 s, Offset, Count, VirtAlign, Lines);
1560 else if (Quot == 127)
1566 // Middle, unclipped tiles
1567 Count = Width - Count;
1568 int Middle = Count >> 3;
1570 for (int C = Middle; C > 0; s += 4, Quot++, C--)
1572 Tile = READ_2BYTES(t);
1573 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1574 if (BG.TileSize == 8)
1576 if (!(Tile & H_FLIP))
1578 // Normal, unflipped
1579 (*DrawHiResTilePtr) (Tile + (Quot & 1),
1580 s, VirtAlign, Lines);
1585 (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1586 s, VirtAlign, Lines);
1591 if (!(Tile & (V_FLIP | H_FLIP)))
1593 // Normal, unflipped
1594 (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1595 s, VirtAlign, Lines);
1603 (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1604 s, VirtAlign, Lines);
1609 (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1610 s, VirtAlign, Lines);
1616 (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1617 s, VirtAlign, Lines);
1629 // Right-hand edge clipped tiles
1632 Tile = READ_2BYTES(t);
1633 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1634 if (BG.TileSize == 8)
1636 if (!(Tile & H_FLIP))
1638 // Normal, unflipped
1639 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1640 s, 0, Count, VirtAlign, Lines);
1645 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1646 s, 0, Count, VirtAlign, Lines);
1651 if (!(Tile & (V_FLIP | H_FLIP)))
1653 // Normal, unflipped
1654 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1655 s, 0, Count, VirtAlign, Lines);
1663 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1664 s, 0, Count, VirtAlign, Lines);
1669 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1670 s, 0, Count, VirtAlign, Lines);
1676 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1677 s, 0, Count, VirtAlign, Lines);
1685 void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1689 BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1690 BG.BitShift = BitShifts[BGMode][bg];
1691 BG.TileShift = TileShifts[BGMode][bg];
1692 BG.TileAddress = PPU.BG[bg].NameBase << 1;
1694 BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1695 BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1696 BG.PaletteShift = PaletteShifts[BGMode][bg];
1697 BG.PaletteMask = PaletteMasks[BGMode][bg];
1698 BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1701 if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1703 DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1710 if (Settings.WrestlemaniaArcade)
1712 case 4: // Used by Puzzle Bobble
1713 DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1717 case 6: // XXX: is also offset per tile.
1718 DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1734 uint8 depths [2] = {Z1, Z2};
1737 BG.StartPalette = bg << 5;
1739 BG.StartPalette = 0;
1741 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1743 if (PPU.BG[bg].SCSize & 1)
1748 if (PPU.BG[bg].SCSize & 2)
1753 if (PPU.BG[bg].SCSize & 1)
1762 if (BG.TileSize == 16)
1773 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1775 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1776 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1777 int VirtAlign = (Y + VOffset) & 7;
1779 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1780 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1781 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1784 if (Y + Lines > GFX.EndY)
1785 Lines = GFX.EndY + 1 - Y;
1789 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1792 if (((VOffset + Y) & 15) > 7)
1805 if (ScreenLine & 0x20)
1810 b1 += (ScreenLine & 0x1f) << 5;
1811 b2 += (ScreenLine & 0x1f) << 5;
1813 int clipcount = GFX.pCurrentClip->Count [bg];
1816 for (int clip = 0; clip < clipcount; clip++)
1821 if (!GFX.pCurrentClip->Count [bg])
1828 Left = GFX.pCurrentClip->Left [clip][bg];
1829 Right = GFX.pCurrentClip->Right [clip][bg];
1835 uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1836 uint32 HPos = (HOffset + Left) & OffsetMask;
1838 uint32 Quot = HPos >> 3;
1842 if (BG.TileSize == 8)
1845 t = b2 + (Quot & 0x1f);
1852 t = b2 + ((Quot >> 1) & 0x1f);
1854 t = b1 + (Quot >> 1);
1857 Width = Right - Left;
1858 // Left hand edge clipped tile
1861 uint32 Offset = (HPos & 7);
1865 s -= Offset * GFX.PixSize;
1866 Tile = READ_2BYTES(t);
1867 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1869 if (BG.TileSize == 8)
1871 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1876 if (!(Tile & (V_FLIP | H_FLIP)))
1878 // Normal, unflipped
1879 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1880 s, Offset, Count, VirtAlign, Lines);
1888 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1889 s, Offset, Count, VirtAlign, Lines);
1894 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1895 s, Offset, Count, VirtAlign, Lines);
1901 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
1902 Offset, Count, VirtAlign, Lines);
1906 if (BG.TileSize == 8)
1911 else if (Quot == 63)
1919 else if (Quot == 127)
1923 s += 8 * GFX.PixSize;
1926 // Middle, unclipped tiles
1927 Count = Width - Count;
1928 int Middle = Count >> 3;
1930 for (int C = Middle; C > 0; s += 8 * GFX.PixSize, Quot++, C--)
1932 Tile = READ_2BYTES(t);
1933 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1935 if (BG.TileSize != 8)
1939 // Horizontal flip, but what about vertical flip ?
1942 // Both horzontal & vertical flip
1943 (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
1948 // Horizontal flip only
1949 (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
1955 // No horizontal flip, but is there a vertical flip ?
1958 // Vertical flip only
1959 (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
1965 (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
1972 (*DrawTilePtr) (Tile, s, VirtAlign, Lines);
1975 if (BG.TileSize == 8)
1994 // Right-hand edge clipped tiles
1997 Tile = READ_2BYTES(t);
1998 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
2000 if (BG.TileSize == 8)
2001 (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
2005 if (!(Tile & (V_FLIP | H_FLIP)))
2007 // Normal, unflipped
2008 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
2009 Count, VirtAlign, Lines);
2017 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2018 s, 0, Count, VirtAlign,
2024 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2025 s, 0, Count, VirtAlign,
2032 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
2033 s, 0, Count, VirtAlign,
2042 #define RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2043 const uint8 bmask = MASK; \
2044 for (int x = startx; x != endx; \
2045 x += (HFLIP ? -1 : 1), AA += aa, CC += cc, p++, d++) \
2047 int X = ((AA + BB) >> 8) & 0x3ff; \
2048 int Y = ((CC + DD) >> 8) & 0x3ff; \
2049 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2050 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2051 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2059 #define RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,CFILT) \
2060 register int AABB = AA + BB; \
2061 register int CCDD = CC + DD; \
2062 const uint8 bmask = MASK; \
2063 for (int x = startx; x != endx; \
2064 x += (HFLIP ? -1 : 1), AABB += aa, CCDD += cc, p++, d++) \
2066 register uint16 X = ((AABB) >> 8) CFILT; \
2067 register uint16 Y = ((CCDD) >> 8) CFILT; \
2069 if (((X | Y) & ~0x3ff) == 0) { \
2070 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2071 uint8 b = TileData[((Y & 7) << 4) + ((X & 7) << 1)]; \
2072 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2073 if (z > *d && b) { \
2077 } else if (REPEAT == 3) { \
2078 X = (x + HOffset) & 7; \
2079 Y = (yy + CentreY) & 7; \
2080 uint8 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2081 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2082 if (z > *d && b) { \
2089 #define RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,MASK,PRIOMASK) \
2090 for (uint32 clip = 0; clip < ClipCount; clip++) \
2092 if (GFX.pCurrentClip->Count [bg]) \
2094 Left = GFX.pCurrentClip->Left [clip][bg]; \
2095 Right = GFX.pCurrentClip->Right [clip][bg]; \
2096 if (Right <= Left) \
2099 register TYPE *p = (TYPE *) Screen + Left; \
2100 register uint8 *d = Depth + Left; \
2104 startx = Right - 1; \
2118 xx = startx + (HOffset - CentreX) % 1023; \
2120 xx = startx + HOffset - CentreX; \
2121 int AA = l->MatrixA * xx; \
2122 int CC = l->MatrixC * xx; \
2126 RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2127 } else if (DEZAEMON) { \
2128 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,& 0x7ff) \
2130 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,) \
2134 #ifdef USE_CRAZY_OPTS
2136 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON) \
2137 if (GFX.Mode7PriorityMask) { \
2138 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0x7f,0x80) \
2140 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0xff,0x00) \
2143 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,HFLIP) \
2144 if (Settings.Dezaemon && PPU.Mode7Repeat) { \
2145 switch (PPU.Mode7Repeat) { \
2146 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,1); break; \
2147 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,1); break; \
2148 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,1); break; \
2151 switch (PPU.Mode7Repeat) { \
2152 case 0: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,0,0); break; \
2153 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,0); break; \
2154 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,0); break; \
2155 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,0); break; \
2159 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC) \
2160 if (PPU.Mode7HFlip) { \
2161 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,1); \
2163 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,0); \
2166 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2167 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC)
2171 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2172 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,PPU.Mode7HFlip,PPU.Mode7Repeat,Settings.Dezaemon,GFX.Mode7Mask,GFX.Mode7PriorityMask)
2176 #define RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2177 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2181 int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2182 int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2184 int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2185 int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2187 if (PPU.Mode7VFlip) \
2188 yy = 261 - (int) Line; \
2192 if (PPU.Mode7Repeat == 0) \
2193 yy += (VOffset - CentreY) % 1023; \
2195 yy += VOffset - CentreY; \
2196 int BB = l->MatrixB * yy + (CentreX << 8); \
2197 int DD = l->MatrixD * yy + (CentreY << 8); \
2199 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2202 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2205 uint8 * const VRAM1 = Memory.VRAM + 1; \
2206 if (GFX.r2130 & 1) \
2208 if (IPPU.DirectColourMapsNeedRebuild) \
2209 S9xBuildDirectColourMaps (); \
2210 GFX.ScreenColors = DirectColourMaps [0]; \
2213 GFX.ScreenColors = IPPU.ScreenColors; \
2218 uint32 Right = 256; \
2219 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2224 Screen += GFX.StartY * GFX.Pitch; \
2225 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2226 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2227 RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2231 void DrawBGMode7Background (uint8 *Screen, int bg)
2233 RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & bmask))
2236 void DrawBGMode7Background16 (uint8 *Screen, int bg)
2238 RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2241 void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2243 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2244 (*(d + GFX.DepthDelta) != 1 ?
2245 COLOR_ADD (GFX.ScreenColors [b & bmask],
2247 COLOR_ADD (GFX.ScreenColors [b & bmask],
2249 GFX.ScreenColors [b & bmask]);
2252 void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2254 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2255 (*(d + GFX.DepthDelta) != 1 ?
2256 COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2258 COLOR_ADD (GFX.ScreenColors [b & bmask],
2260 GFX.ScreenColors [b & bmask]);
2263 void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2265 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2266 (*(d + GFX.DepthDelta) != 1 ?
2267 COLOR_SUB (GFX.ScreenColors [b & bmask],
2269 COLOR_SUB (GFX.ScreenColors [b & bmask],
2271 GFX.ScreenColors [b & bmask]);
2274 void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2276 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2277 (*(d + GFX.DepthDelta) != 1 ?
2278 COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2280 COLOR_SUB (GFX.ScreenColors [b & bmask],
2282 GFX.ScreenColors [b & bmask]);
2285 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2288 uint8 *VRAM1 = Memory.VRAM + 1; \
2289 if (GFX.r2130 & 1) \
2291 if (IPPU.DirectColourMapsNeedRebuild) \
2292 S9xBuildDirectColourMaps (); \
2293 GFX.ScreenColors = DirectColourMaps [0]; \
2296 GFX.ScreenColors = IPPU.ScreenColors; \
2302 uint32 Right = 256; \
2303 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2308 Screen += GFX.StartY * GFX.Pitch; \
2309 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2310 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2311 bool8_32 allowSimpleCase = FALSE; \
2312 if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2313 && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2314 && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2316 allowSimpleCase = TRUE; \
2318 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2322 int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2323 int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2325 int CentreX = ((int) l->CentreX << M7) >> M7; \
2326 int CentreY = ((int) l->CentreY << M7) >> M7; \
2328 if (PPU.Mode7VFlip) \
2329 yy = 261 - (int) Line; \
2333 if (PPU.Mode7Repeat == 0) \
2334 yy += (VOffset - CentreY) % 1023; \
2336 yy += VOffset - CentreY; \
2337 bool8_32 simpleCase = FALSE; \
2340 /* Make a special case for the identity matrix, since it's a common case and */ \
2341 /* can be done much more quickly without special effects */ \
2342 if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2344 BB = CentreX << 8; \
2345 DD = (yy + CentreY) << 8; \
2346 simpleCase = TRUE; \
2350 BB = l->MatrixB * yy + (CentreX << 8); \
2351 DD = l->MatrixD * yy + (CentreY << 8); \
2354 for (uint32 clip = 0; clip < ClipCount; clip++) \
2356 if (GFX.pCurrentClip->Count [bg]) \
2358 Left = GFX.pCurrentClip->Left [clip][bg]; \
2359 Right = GFX.pCurrentClip->Right [clip][bg]; \
2360 if (Right <= Left) \
2363 TYPE *p = (TYPE *) Screen + Left; \
2364 uint8 *d = Depth + Left; \
2366 if (PPU.Mode7HFlip) \
2368 startx = Right - 1; \
2383 if (PPU.Mode7Repeat == 0) \
2384 xx = startx + (HOffset - CentreX) % 1023; \
2386 xx = startx + HOffset - CentreX; \
2394 AA = l->MatrixA * xx; \
2395 CC = l->MatrixC * xx; \
2399 if (!PPU.Mode7Repeat) \
2404 int X = ((AA + BB) >> 8) & 0x3ff; \
2405 int Y = (DD >> 8) & 0x3ff; \
2406 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2407 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2408 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2409 if (GFX.Z1 > *d && b) \
2411 TYPE theColor = COLORFUNC; \
2412 *p = (FUNC) | ALPHA_BITS_MASK; \
2415 AA += aa, p++, d++; \
2417 } while (x != endx); \
2423 int X = (AA + BB) >> 8; \
2426 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2432 if (((X | Y) & ~0x3ff) == 0) \
2434 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2435 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2436 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2437 if (GFX.Z1 > *d && b) \
2439 TYPE theColor = COLORFUNC; \
2440 *p = (FUNC) | ALPHA_BITS_MASK; \
2444 else if (PPU.Mode7Repeat == 3) \
2446 X = (x + HOffset) & 7; \
2447 Y = (yy + CentreY) & 7; \
2448 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2449 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2450 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2451 if (GFX.Z1 > *d && b) \
2453 TYPE theColor = COLORFUNC; \
2454 *p = (FUNC) | ALPHA_BITS_MASK; \
2458 AA += aa; p++; d++; \
2460 } while (x != endx); \
2463 else if (!PPU.Mode7Repeat) \
2465 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2466 /* the location of one point in the _sampled_ image, and weight them according */ \
2467 /* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
2470 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2471 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2472 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2473 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2474 /* You can think of this as a kind of mipmapping. */ \
2475 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2477 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2479 uint32 xPos = AA + BB; \
2480 uint32 xPix = xPos >> 8; \
2481 uint32 yPos = CC + DD; \
2482 uint32 yPix = yPos >> 8; \
2483 uint32 X = xPix & 0x3ff; \
2484 uint32 Y = yPix & 0x3ff; \
2485 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2486 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2487 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2488 if (GFX.Z1 > *d && b) \
2490 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2491 uint32 X10 = (xPix + dir) & 0x3ff; \
2492 uint32 Y01 = (yPix + dir) & 0x3ff; \
2493 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2494 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2495 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2496 uint32 p1 = COLORFUNC; \
2497 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2498 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2499 uint32 p2 = COLORFUNC; \
2500 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2501 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2502 uint32 p4 = COLORFUNC; \
2503 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2504 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2505 uint32 p3 = COLORFUNC; \
2506 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2507 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2508 uint32 Xdel = (xPos >> 3) & 0x1F; \
2509 uint32 Ydel = (yPos >> 3) & 0x1F; \
2510 uint32 XY = (Xdel*Ydel) >> 5; \
2511 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2512 uint32 area2 = Xdel - XY; \
2513 uint32 area3 = Ydel - XY; \
2514 uint32 area4 = XY; \
2515 uint32 tempColor = ((area1 * p1) + \
2518 (area4 * p4)) >> 5; \
2519 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2520 *p = (FUNC) | ALPHA_BITS_MASK; \
2526 /* The oversampling method: get the colors at four corners of a square */ \
2527 /* in the _displayed_ image, and average them. It's sharp and clean, but */ \
2528 /* gives the usual huge pixels when the source image gets "close." */ \
2530 /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2531 uint32 aaDelX = aa >> 1; \
2532 uint32 ccDelX = cc >> 1; \
2533 uint32 bbDelY = l->MatrixB >> 1; \
2534 uint32 ddDelY = l->MatrixD >> 1; \
2535 /* Offset the location within the source image so that the four sampled points */ \
2536 /* center around where the single point would otherwise have been drawn. */ \
2537 BB -= (bbDelY >> 1); \
2538 DD -= (ddDelY >> 1); \
2539 AA -= (aaDelX >> 1); \
2540 CC -= (ccDelX >> 1); \
2541 uint32 BB10 = BB + aaDelX; \
2542 uint32 BB01 = BB + bbDelY; \
2543 uint32 BB11 = BB + aaDelX + bbDelY; \
2544 uint32 DD10 = DD + ccDelX; \
2545 uint32 DD01 = DD + ddDelY; \
2546 uint32 DD11 = DD + ccDelX + ddDelY; \
2547 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2549 uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2550 uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2551 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2552 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2553 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2554 if (GFX.Z1 > *d && b) \
2556 /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2557 /* source image that we're going to examine. */ \
2558 uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2559 uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2560 uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2561 uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2562 uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2563 uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2564 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2565 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2566 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2567 TYPE p1 = COLORFUNC; \
2568 b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2569 TYPE p2 = COLORFUNC; \
2570 b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2571 TYPE p3 = COLORFUNC; \
2572 b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2573 TYPE p4 = COLORFUNC; \
2574 TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2575 *p = (FUNC) | ALPHA_BITS_MASK; \
2583 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2585 uint32 xPos = AA + BB; \
2586 uint32 xPix = xPos >> 8; \
2587 uint32 yPos = CC + DD; \
2588 uint32 yPix = yPos >> 8; \
2593 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2599 if (((X | Y) & ~0x3ff) == 0) \
2601 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2602 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2603 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2604 if (GFX.Z1 > *d && b) \
2606 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2607 uint32 X10 = (xPix + dir) & 0x3ff; \
2608 uint32 Y01 = (yPix + dir) & 0x3ff; \
2609 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2610 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2611 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2612 uint32 p1 = COLORFUNC; \
2613 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2614 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2615 uint32 p2 = COLORFUNC; \
2616 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2617 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2618 uint32 p4 = COLORFUNC; \
2619 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2620 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2621 uint32 p3 = COLORFUNC; \
2622 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2623 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2624 uint32 Xdel = (xPos >> 3) & 0x1F; \
2625 uint32 Ydel = (yPos >> 3) & 0x1F; \
2626 uint32 XY = (Xdel*Ydel) >> 5; \
2627 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2628 uint32 area2 = Xdel - XY; \
2629 uint32 area3 = Ydel - XY; \
2630 uint32 area4 = XY; \
2631 uint32 tempColor = ((area1 * p1) + \
2634 (area4 * p4)) >> 5; \
2635 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2636 *p = (FUNC) | ALPHA_BITS_MASK; \
2642 if (PPU.Mode7Repeat == 3) \
2644 X = (x + HOffset) & 7; \
2645 Y = (yy + CentreY) & 7; \
2646 uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2647 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2648 if (GFX.Z1 > *d && b) \
2650 TYPE theColor = COLORFUNC; \
2651 *p = (FUNC) | ALPHA_BITS_MASK; \
2661 STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2663 register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2664 ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2665 ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2666 ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2667 register uint32 y = (A & TWO_LOW_BITS_MASK) +
2668 (B & TWO_LOW_BITS_MASK) +
2669 (C & TWO_LOW_BITS_MASK) +
2670 (D & TWO_LOW_BITS_MASK);
2671 y = (y>>2) & TWO_LOW_BITS_MASK;
2675 void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2677 RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2680 void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2682 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2683 (*(d + GFX.DepthDelta) != 1 ?
2684 (COLOR_ADD (theColor,
2686 (COLOR_ADD (theColor,
2687 GFX.FixedColour))) :
2688 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2691 void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2693 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2694 (*(d + GFX.DepthDelta) != 1 ?
2695 COLOR_ADD1_2 (theColor,
2697 COLOR_ADD (theColor,
2699 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2702 void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2704 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2705 (*(d + GFX.DepthDelta) != 1 ?
2706 COLOR_SUB (theColor,
2708 COLOR_SUB (theColor,
2710 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2713 void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2715 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2716 (*(d + GFX.DepthDelta) != 1 ?
2717 COLOR_SUB1_2 (theColor,
2719 COLOR_SUB (theColor,
2721 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2724 #define _BUILD_SETUP(F) \
2725 GFX.BuildPixel = BuildPixel##F; \
2726 GFX.BuildPixel2 = BuildPixel2##F; \
2727 GFX.DecomposePixel = DecomposePixel##F; \
2728 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2729 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2730 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2731 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2732 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2733 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2734 MAX_RED = MAX_RED_##F; \
2735 MAX_GREEN = MAX_GREEN_##F; \
2736 MAX_BLUE = MAX_BLUE_##F; \
2737 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2738 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2739 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2740 GREEN_LOW_BIT_MASK_##F | \
2741 BLUE_LOW_BIT_MASK_##F); \
2742 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2743 GREEN_HI_BIT_MASK_##F | \
2744 BLUE_HI_BIT_MASK_##F); \
2745 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2746 GREEN_HI_BIT_MASK_##F | \
2747 BLUE_HI_BIT_MASK_##F) << 1); \
2748 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2749 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2750 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2751 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2752 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2753 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2754 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2755 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2756 ~TWO_LOW_BITS_MASK ) >> 2);
2758 void RenderScreen (uint8 *Screen, bool8_32 sub, bool8_32 force_no_add, uint8 D)
2770 GFX.pCurrentClip = &IPPU.Clip [0];
2771 BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2772 BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2773 BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2774 BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2775 OB = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2779 GFX.pCurrentClip = &IPPU.Clip [1];
2780 BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2781 BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2782 BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2783 BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2784 OB = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2787 sub |= force_no_add;
2789 if (PPU.BGMode <= 1)
2793 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2798 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2799 DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2803 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2804 DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2808 SelectTileRenderer (sub || !SUB_OR_ADD(2));
2809 DrawBackground (PPU.BGMode, 2, D + 3,
2810 (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2812 if (BG3 && PPU.BGMode == 0)
2814 SelectTileRenderer (sub || !SUB_OR_ADD(3));
2815 DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2818 else if (PPU.BGMode != 7)
2822 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2827 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2828 DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2830 if (PPU.BGMode != 6 && BG1)
2832 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2833 DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2840 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2843 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2847 if (Memory.FillRAM [0x2133] & 0x40)
2849 GFX.Mode7Mask = 0x7f;
2850 GFX.Mode7PriorityMask = 0x80;
2851 Mode7Depths [0] = 5 + D;
2852 Mode7Depths [1] = 9 + D;
2857 GFX.Mode7Mask = 0xff;
2858 GFX.Mode7PriorityMask = 0;
2859 Mode7Depths [0] = 5 + D;
2860 Mode7Depths [1] = 5 + D;
2863 if (sub || !SUB_OR_ADD(0))
2865 if (!Settings.Mode7Interpolate)
2866 DrawBGMode7Background16 (Screen, bg);
2868 DrawBGMode7Background16_i (Screen, bg);
2872 if (GFX.r2131 & 0x80)
2874 if (GFX.r2131 & 0x40)
2876 if (!Settings.Mode7Interpolate)
2877 DrawBGMode7Background16Sub1_2 (Screen, bg);
2879 DrawBGMode7Background16Sub1_2_i (Screen, bg);
2883 if (!Settings.Mode7Interpolate)
2884 DrawBGMode7Background16Sub (Screen, bg);
2886 DrawBGMode7Background16Sub_i (Screen, bg);
2891 if (GFX.r2131 & 0x40)
2893 if (!Settings.Mode7Interpolate)
2894 DrawBGMode7Background16Add1_2 (Screen, bg);
2896 DrawBGMode7Background16Add1_2_i (Screen, bg);
2900 if (!Settings.Mode7Interpolate)
2901 DrawBGMode7Background16Add (Screen, bg);
2903 DrawBGMode7Background16Add_i (Screen, bg);
2913 void DisplayChar (uint8 *Screen, uint8 c)
2915 int line = (((c & 0x7f) - 32) >> 4) * font_height;
2916 int offset = (((c & 0x7f) - 32) & 15) * font_width;
2918 if (Settings.SixteenBit)
2922 uint16 *s = (uint16 *) Screen;
2923 for (h = 0; h < font_height; h++, line++,
2924 s += GFX.PPL - font_width)
2926 for (w = 0; w < font_width; w++, s++)
2928 uint8 p = font [line][offset + w];
2943 for (h = 0; h < font_height; h++, line++,
2944 s += GFX.PPL - font_width)
2946 for (w = 0; w < font_width; w++, s++)
2948 uint8 p = font [line][offset + w];
2961 static void S9xDisplayFrameRate ()
2963 uint8 *Screen = GFX.Screen + 2 +
2964 (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch2;
2968 sprintf (string, "%02d/%02d", IPPU.DisplayedRenderedFrameCount,
2969 (int) Memory.ROMFramesPerSecond);
2973 Screen += (font_width - 1) * sizeof(uint16);
2975 for (i = 0; i < len; i++)
2977 DisplayChar (Screen, string [i]);
2978 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
2983 static void S9xDisplayString (const char *string)
2985 uint8 *Screen = GFX.Screen + 2 +
2986 (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch2;
2987 int len = strlen (string);
2988 int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
2992 for (i = 0; i < len; i++, char_count++)
2994 if (char_count >= max_chars || string [i] < 32)
2996 Screen -= Settings.SixteenBit ?
2997 (font_width - 1) * sizeof (uint16) * max_chars :
2998 (font_width - 1) * max_chars;
2999 Screen += font_height * GFX.Pitch;
3000 if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
3002 char_count -= max_chars;
3004 if (string [i] < 32)
3006 DisplayChar (Screen, string [i]);
3007 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
3012 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
3018 unsigned char *memoryfillram = Memory.FillRAM;
3020 // get local copies of vid registers to be used later
3021 GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN
3022 GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
3023 GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
3024 GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
3026 // If external sync is off and
3027 // main screens have not been configured the same as the sub screen and
3028 // color addition and subtraction has been diabled then
3030 // anything else it is 0
3031 GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
3032 (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
3033 (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
3035 // If sprite data has been changed then go through and
3036 // refresh the sprites.
3037 if (IPPU.OBJChanged)
3042 if (PPU.RecomputeClipWindows)
3044 ComputeClipWindows ();
3045 PPU.RecomputeClipWindows = FALSE;
3048 GFX.StartY = IPPU.PreviousLine;
3049 if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
3050 GFX.EndY = PPU.ScreenHeight - 1;
3052 uint32 starty = GFX.StartY;
3053 uint32 endy = GFX.EndY;
3055 #ifndef RC_OPTIMIZED
3056 if (Settings.SupportHiRes &&
3057 (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace))
3059 if (PPU.BGMode == 5 || PPU.BGMode == 6)
3061 IPPU.RenderedScreenWidth = 512;
3064 if (IPPU.LatchedInterlace)
3066 starty = GFX.StartY * 2;
3067 endy = GFX.EndY * 2 + 1;
3069 if (!IPPU.DoubleWidthPixels)
3071 // The game has switched from lo-res to hi-res mode part way down
3072 // the screen. Scale any existing lo-res pixels on screen
3074 if (Settings.SixteenBit)
3077 #if defined (USE_GLIDE) || defined (USE_OPENGL)
3080 (Settings.GlideEnable && GFX.Pitch == 512) ||
3083 (Settings.OpenGLEnable && GFX.Pitch == 512) ||
3087 // Have to back out of the speed up hack where the low res.
3088 // SNES image was rendered into a 256x239 sized buffer,
3089 // ignoring the true, larger size of the buffer.
3091 for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
3093 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3094 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.RealPitch) + 510;
3095 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3101 for (register uint32 y = 0; y < GFX.StartY; y++)
3103 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3104 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3105 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3112 for (register uint32 y = 0; y < GFX.StartY; y++)
3114 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3115 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3116 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3121 IPPU.DoubleWidthPixels = TRUE;
3124 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3126 uint32 black = BLACK | (BLACK << 16);
3128 // Are we worrying about transparencies?
3129 if (Settings.Transparency && Settings.SixteenBit)
3133 GFX.r2131 = 0x5f; //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3134 GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3135 Memory.FillRAM [0x212d]) & 15;
3136 GFX.r212c &= ~GFX.r212d; // make sure the main BG reg is the reverse of the sub BG reg
3137 GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3140 // Check to see if any transparency effects are currently in use
3141 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3142 (GFX.r2130 & 0x30) != 0x30 &&
3143 !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3145 // transparency effects in use, so lets get busy!
3146 struct ClipData *pClip;
3148 GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3149 IPPU.XB [PPU.FixedColourGreen],
3150 IPPU.XB [PPU.FixedColourBlue]);
3151 fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3152 // Clear the z-buffer, marking areas 'covered' by the fixed
3153 // colour as depth 1.
3154 pClip = &IPPU.Clip [1];
3156 // Clear the z-buffer
3158 if (pClip->Count [5])
3161 // Colour window enabled.
3164 for (uint32 y = starty; y <= endy; y++)
3167 ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3168 IPPU.RenderedScreenWidth);
3169 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3170 IPPU.RenderedScreenWidth);
3172 if (IPPU.Clip [0].Count [5])
3174 memset ((GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth);
3176 for (uint32 c = 0; c < pClip->Count [5]; c++)
3178 if (pClip->Right [c][5] > pClip->Left [c][5])
3180 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3181 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3182 if (IPPU.Clip [0].Count [5])
3184 // Blast, have to clear the sub-screen to the fixed-colour
3185 // because there is a colour window in effect clipping
3186 // the main screen that will allow the sub-screen
3187 // 'underneath' to show through.
3188 memset ((GFX.SubScreen + y * GFX.Pitch2) + pClip->Left [c][5] * x2,
3190 pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3196 #else // NOT RC_OPTIMIZED
3197 // loop around all of the lines being updated
3198 for (uint32 y = starty; y <= endy; y++)
3200 // Clear the subZbuffer
3201 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3202 IPPU.RenderedScreenWidth>>2);
3203 // Clear the Zbuffer
3204 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3205 IPPU.RenderedScreenWidth>>2);
3207 // if there is clipping then clear subscreen to a black color
3208 if (IPPU.Clip [0].Count [5])
3210 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth>>1);
3213 // loop through all window clippings
3214 for (uint32 c = 0; c < pClip->Count [5]; c++)
3216 if (pClip->Right [c][5] > pClip->Left [c][5])
3218 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3219 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3220 if (IPPU.Clip [0].Count [5])
3222 // Blast, have to clear the sub-screen to the fixed-colour
3223 // because there is a colour window in effect clipping
3224 // the main screen that will allow the sub-screen
3225 // 'underneath' to show through.
3227 register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch2);
3228 register uint16 *q = p + pClip->Right [c][5] * x2;
3229 p += pClip->Left [c][5] * x2;
3232 *p++ = (uint16) GFX.FixedColour;
3238 //#undef RC_OPTIMIZED
3243 // No windows are clipping the main screen
3244 // this simplifies the screen clearing process
3247 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3250 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3251 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3255 for (uint32 y = starty; y <= endy; y++)
3257 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3258 IPPU.RenderedScreenWidth);
3259 memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3260 IPPU.RenderedScreenWidth);
3264 if (IPPU.Clip [0].Count [5])
3266 // Blast, have to clear the sub-screen to the fixed-colour
3267 // because there is a colour window in effect clipping
3268 // the main screen that will allow the sub-screen
3269 // 'underneath' to show through.
3270 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3272 memset ((GFX.SubScreen + starty * GFX.Pitch2),
3273 GFX.FixedColour | (GFX.FixedColour << 16),
3274 GFX.Pitch2 * (endy - starty - 1));
3278 for (uint32 y = starty; y <= endy; y++)
3280 memset ((GFX.SubScreen + y * GFX.Pitch2),
3281 GFX.FixedColour | (GFX.FixedColour << 16),
3282 IPPU.RenderedScreenWidth);
3287 #else // NOT RC_OPTIMIZED
3288 // loop through all of the lines to be updated
3289 for (uint32 y = starty; y <= endy; y++)
3291 // Clear the Zbuffer
3292 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3293 IPPU.RenderedScreenWidth>>2);
3294 // clear the sub Zbuffer to 1
3295 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3296 IPPU.RenderedScreenWidth>>2);
3297 if (IPPU.Clip [0].Count [5])
3299 // Blast, have to clear the sub-screen to the fixed-colour
3300 // because there is a colour window in effect clipping
3301 // the main screen that will allow the sub-screen
3302 // 'underneath' to show through.
3305 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), fixedColour,
3306 IPPU.RenderedScreenWidth>>1);
3313 if (ANYTHING_ON_SUB)
3315 GFX.DB = GFX.SubZBuffer;
3316 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3319 if (IPPU.Clip [0].Count [5])
3321 for (uint32 y = starty; y <= endy; y++)
3323 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3324 register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3325 register uint8 *e = d + SNES_WIDTH;
3330 *p = *(p + GFX.Delta);
3339 GFX.DB = GFX.ZBuffer;
3340 RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3343 uint32 back = IPPU.ScreenColors [0];
3348 pClip = &IPPU.Clip [0];
3350 for (uint32 y = starty; y <= endy; y++)
3352 if (!(Count = pClip->Count [5]))
3359 for (uint32 b = 0; b < Count; b++)
3361 if (pClip->Count [5])
3363 Left = pClip->Left [b][5] * x2;
3364 Right = pClip->Right [b][5] * x2;
3369 if (GFX.r2131 & 0x80)
3371 if (GFX.r2131 & 0x40)
3373 // Subtract, halving the result.
3374 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3375 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3376 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3377 register uint8 *e = d + Right;
3378 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3388 *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3403 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3404 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3405 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3406 register uint8 *e = d + Right;
3407 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3417 *p = COLOR_SUB (back, *(p + GFX.Delta));
3431 if (GFX.r2131 & 0x40)
3433 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3434 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3435 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3436 register uint8 *e = d + Right;
3437 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3446 *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3461 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3462 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3463 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3464 register uint8 *e = d + Right;
3465 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3474 *p = COLOR_ADD (back, *(p + GFX.Delta));
3488 if (!pClip->Count [5])
3490 // The backdrop has not been cleared yet - so
3491 // copy the sub-screen to the main screen
3492 // or fill it with the back-drop colour if the
3493 // sub-screen is clear.
3494 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3495 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3496 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3497 register uint8 *e = d + Right;
3506 *p = *(p + GFX.Delta);
3508 *p = GFX.FixedColour;
3525 // Subscreen not being added to back
3526 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3527 pClip = &IPPU.Clip [0];
3529 if (pClip->Count [5])
3531 for (uint32 y = starty; y <= endy; y++)
3533 for (uint32 b = 0; b < pClip->Count [5]; b++)
3535 uint32 Left = pClip->Left [b][5] * x2;
3536 uint32 Right = pClip->Right [b][5] * x2;
3537 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3538 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3539 register uint8 *e = d + Right;
3553 for (uint32 y = starty; y <= endy; y++)
3555 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3556 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3557 register uint8 *e = d + 256 * x2;
3577 // 16bit and transparency but currently no transparency effects in
3580 // get the back colour of the current screen
3581 uint32 back = IPPU.ScreenColors [0] |
3582 (IPPU.ScreenColors [0] << 16);
3584 // if forceblanking in use then use black instead of the back color
3585 if (PPU.ForcedBlanking)
3588 // not sure what Clip is used for yet
3589 // could be a check to see if there is any clipping present?
3590 if (IPPU.Clip [0].Count[5])
3594 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3596 memset (GFX.Screen + starty * GFX.Pitch2, black,
3597 GFX.Pitch2 * (endy - starty - 1));
3601 for (uint32 y = starty; y <= endy; y++)
3603 memset (GFX.Screen + y * GFX.Pitch2, black,
3607 for (uint32 y = starty; y <= endy; y++)
3609 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3611 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3614 memset ((GFX.Screen + y * GFX.Pitch2) + IPPU.Clip [0].Left [c][5] * x2,
3616 IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3621 // loop through all of the lines that are going to be updated as part of this screen update
3622 for (uint32 y = starty; y <= endy; y++)
3624 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), black,
3625 IPPU.RenderedScreenWidth>>1);
3629 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3631 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3633 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2); // get pointer to current line in screen buffer
3634 register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3635 p += IPPU.Clip [0].Left [c][5] * x2;
3638 *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3648 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3650 memset (GFX.Screen + starty * GFX.Pitch2, back,
3651 GFX.Pitch2 * (endy - starty - 1));
3655 for (uint32 y = starty; y <= endy; y++)
3657 memset (GFX.Screen + y * GFX.Pitch2, back,
3662 // there is no clipping to worry about so just fill with the back colour
3663 for (uint32 y = starty; y <= endy; y++)
3665 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3666 IPPU.RenderedScreenWidth>>1);
3671 // If Forced blanking is not in effect
3672 if (!PPU.ForcedBlanking)
3675 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3677 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3678 GFX.ZPitch * (endy - starty - 1));
3682 for (uint32 y = starty; y <= endy; y++)
3684 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3689 // Clear the Zbuffer for each of the lines which are going to be updated
3690 for (uint32 y = starty; y <= endy; y++)
3692 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3696 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3697 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3701 else // Transparencys are disabled, ahh lovely ... nice and easy.
3704 if (Settings.SixteenBit)
3707 // get back colour to be used in clearing the screen
3708 register uint32 back;
3709 if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3710 (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3712 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3713 (IPPU.XB[PPU.FixedColourGreen] << 6) |
3714 (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3715 back = (back << 16) | back;
3719 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3722 // if Forcedblanking in use then back colour becomes black
3723 if (PPU.ForcedBlanking)
3727 SelectTileRenderer (TRUE); //selects the tile renderers to be used
3728 // TRUE means to use the default
3729 // FALSE means use best renderer based on current
3730 // graphics register settings
3733 // now clear all graphics lines which are being updated using the back colour
3734 for (register uint32 y = starty; y <= endy; y++)
3736 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3737 IPPU.RenderedScreenWidth>>1);
3741 else // Settings.SixteenBit == false
3743 // because we are in 8 bit we can just use 0 to clear the screen
3744 // this means we can use the Zero Memory function
3746 // Loop through all lines being updated and clear the pixels to 0
3747 for (uint32 y = starty; y <= endy; y++)
3749 ZeroMemory (GFX.Screen + y * GFX.Pitch2,
3750 IPPU.RenderedScreenWidth);
3754 if (!PPU.ForcedBlanking)
3756 // Loop through all lines being updated and clear the
3757 // zbuffer for each of the lines
3758 for (uint32 y = starty; y <= endy; y++)
3760 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3761 IPPU.RenderedScreenWidth>>2);
3763 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3764 GFX.pCurrentClip = &IPPU.Clip [0];
3766 // Define an inline function to handle clipping
3767 #define FIXCLIP(n) \
3768 if (GFX.r212c & (1 << (n))) \
3769 GFX.pCurrentClip = &IPPU.Clip [0]; \
3771 GFX.pCurrentClip = &IPPU.Clip [1]
3773 // Define an inline function to handle which BGs are being displayed
3774 #define DISPLAY(n) \
3775 (!(PPU.BG_Forced & n) && \
3776 (GFX.r212c & n) || \
3777 ((GFX.r212d & n) && subadd))
3779 uint8 subadd = GFX.r2131 & 0x3f;
3781 // go through all BGS are check if they need to be displayed
3782 bool8_32 BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3783 bool8_32 BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3784 bool8_32 BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3785 bool8_32 BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3786 bool8_32 OB = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3788 if (PPU.BGMode <= 1)
3790 // screen modes 0 and 1
3799 DrawBackground (PPU.BGMode, 0, 10, 14);
3804 DrawBackground (PPU.BGMode, 1, 9, 13);
3809 DrawBackground (PPU.BGMode, 2, 3,
3810 (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3812 if (BG3 && PPU.BGMode == 0)
3815 DrawBackground (PPU.BGMode, 3, 2, 5);
3818 else if (PPU.BGMode != 7)
3820 // screen modes 2 and up but not mode 7
3829 DrawBackground (PPU.BGMode, 0, 5, 13);
3831 if (BG1 && PPU.BGMode != 6)
3834 DrawBackground (PPU.BGMode, 1, 2, 9);
3845 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3849 if (Memory.FillRAM [0x2133] & 0x40)
3851 GFX.Mode7Mask = 0x7f;
3852 GFX.Mode7PriorityMask = 0x80;
3853 Mode7Depths [0] = 5;
3854 Mode7Depths [1] = 9;
3859 GFX.Mode7Mask = 0xff;
3860 GFX.Mode7PriorityMask = 0;
3861 Mode7Depths [0] = 5;
3862 Mode7Depths [1] = 5;
3867 if (!Settings.SixteenBit)
3868 DrawBGMode7Background (GFX.Screen, bg);
3872 if (!Settings.Mode7Interpolate)
3874 DrawBGMode7Background16 (GFX.Screen, bg);
3878 DrawBGMode7Background16_i (GFX.Screen, bg);
3885 #ifndef RC_OPTIMIZE // no hi res
3886 if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3888 if (IPPU.DoubleWidthPixels)
3890 // Mixure of background modes used on screen - scale width
3891 // of all non-mode 5 and 6 pixels.
3893 if (Settings.SixteenBit)
3896 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3898 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3899 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3900 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3907 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3909 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3910 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3911 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3918 if (IPPU.LatchedInterlace)
3920 // Interlace is enabled - double the height of all non-mode 5 and 6
3922 for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3924 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch2),
3925 (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch2),
3931 IPPU.PreviousLine = IPPU.CurrentLine;
3934 #ifdef GFX_MULTI_FORMAT
3936 #define _BUILD_PIXEL(F) \
3937 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
3939 return (BUILD_PIXEL_##F(R,G,B)); \
3941 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
3943 return (BUILD_PIXEL2_##F(R,G,B)); \
3945 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
3947 DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
3950 _BUILD_PIXEL(RGB565)
3951 _BUILD_PIXEL(RGB555)
3952 _BUILD_PIXEL(BGR565)
3953 _BUILD_PIXEL(BGR555)
3954 _BUILD_PIXEL(GBR565)
3955 _BUILD_PIXEL(GBR555)
3956 _BUILD_PIXEL(RGB5551)
3958 bool8_32 S9xSetRenderPixelFormat (int format)
3960 extern uint32 current_graphic_format;
3962 current_graphic_format = format;
3967 _BUILD_SETUP(RGB565)
3970 _BUILD_SETUP(RGB555)
3973 _BUILD_SETUP(BGR565)
3976 _BUILD_SETUP(BGR555)
3979 _BUILD_SETUP(GBR565)
3982 _BUILD_SETUP(GBR555)
3985 _BUILD_SETUP(RGB5551)