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 void ComputeClipWindows ();
62 static void S9xDisplayFrameRate ();
63 static void S9xDisplayString (const char *string);
65 extern uint8 BitShifts[8][4];
66 extern uint8 TileShifts[8][4];
67 extern uint8 PaletteShifts[8][4];
68 extern uint8 PaletteMasks[8][4];
69 extern uint8 Depths[8][4];
70 extern uint8 BGSizes [2];
72 extern NormalTileRenderer DrawTilePtr;
73 extern ClippedTileRenderer DrawClippedTilePtr;
74 extern NormalTileRenderer DrawHiResTilePtr;
75 extern ClippedTileRenderer DrawHiResClippedTilePtr;
76 extern LargePixelRenderer DrawLargePixelPtr;
80 extern struct SLineData LineData[240];
81 extern struct SLineMatrixData LineMatrixData [240];
83 extern uint8 Mode7Depths [2];
86 (GFX.r212c & (1 << (N)) && \
87 !(PPU.BG_Forced & (1 << (N))))
89 #define SUB_OR_ADD(N) \
90 (GFX.r2131 & (1 << (N)))
93 ((GFX.r2130 & 0x30) != 0x30 && \
95 (GFX.r212d & (1 << N)) && \
96 !(PPU.BG_Forced & (1 << (N))))
98 #define ANYTHING_ON_SUB \
99 ((GFX.r2130 & 0x30) != 0x30 && \
103 #define ADD_OR_SUB_ON_ANYTHING \
106 #define BLACK BUILD_PIXEL(0,0,0)
108 bool8_32 S9xGraphicsInit ()
110 register uint32 PixelOdd = 1;
111 register uint32 PixelEven = 2;
113 #ifdef GFX_MULTI_FORMAT
114 if (GFX.BuildPixel == NULL)
115 S9xSetRenderPixelFormat (RGB565);
118 for (uint8 bitshift = 0; bitshift < 4; bitshift++)
120 for (register int i = 0; i < 16; i++)
122 register uint32 h = 0;
123 register uint32 l = 0;
125 #if defined(LSB_FIRST)
144 h |= (PixelOdd << 24);
146 h |= (PixelOdd << 16);
148 h |= (PixelOdd << 8);
152 l |= (PixelOdd << 24);
154 l |= (PixelOdd << 16);
156 l |= (PixelOdd << 8);
161 odd_high[bitshift][i] = h;
162 odd_low[bitshift][i] = l;
165 #if defined(LSB_FIRST)
171 h |= PixelEven << 16;
173 h |= PixelEven << 24;
179 l |= PixelEven << 16;
181 l |= PixelEven << 24;
184 h |= (PixelEven << 24);
186 h |= (PixelEven << 16);
188 h |= (PixelEven << 8);
192 l |= (PixelEven << 24);
194 l |= (PixelEven << 16);
196 l |= (PixelEven << 8);
201 even_high[bitshift][i] = h;
202 even_low[bitshift][i] = l;
208 GFX.InfoStringTimeout = 0;
209 GFX.InfoString = NULL;
212 IPPU.OBJChanged = TRUE;
213 if (Settings.Transparency)
214 Settings.SixteenBit = TRUE;
216 IPPU.DirectColourMapsNeedRebuild = TRUE;
218 if (Settings.SixteenBit)
220 DrawTilePtr = DrawTile16;
221 DrawClippedTilePtr = DrawClippedTile16;
222 DrawLargePixelPtr = DrawLargePixel16;
223 DrawHiResTilePtr= DrawHiResTile16;
224 DrawHiResClippedTilePtr = DrawHiResClippedTile16;
225 GFX.PPL = GFX.Pitch >> 1;
226 GFX.PPLx2 = GFX.Pitch;
230 DrawTilePtr = DrawTile;
231 DrawClippedTilePtr = DrawClippedTile;
232 DrawLargePixelPtr = DrawLargePixel;
233 DrawHiResTilePtr = DrawTile;
234 DrawHiResClippedTilePtr = DrawClippedTile;
236 GFX.PPLx2 = GFX.Pitch * 2;
238 S9xFixColourBrightness ();
240 if (Settings.SixteenBit)
242 if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
245 if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
246 !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
250 free ((char *) GFX.ZERO_OR_X2);
251 GFX.ZERO_OR_X2 = NULL;
255 free ((char *) GFX.X2);
262 // Build a lookup table that multiplies a packed RGB value by 2 with
264 for (r = 0; r <= MAX_RED; r++)
269 for (g = 0; g <= MAX_GREEN; g++)
274 for (b = 0; b <= MAX_BLUE; b++)
279 GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
280 GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
284 ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
285 ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
286 // Build a lookup table that if the top bit of the color value is zero
287 // then the value is zero, otherwise multiply the value by 2. Used by
288 // the color subtraction code.
290 #if defined(OLD_COLOUR_BLENDING)
291 for (r = 0; r <= MAX_RED; r++)
294 if ((r2 & 0x10) == 0)
297 r2 = (r2 << 1) & MAX_RED;
299 for (g = 0; g <= MAX_GREEN; g++)
302 if ((g2 & GREEN_HI_BIT) == 0)
305 g2 = (g2 << 1) & MAX_GREEN;
307 for (b = 0; b <= MAX_BLUE; b++)
310 if ((b2 & 0x10) == 0)
313 b2 = (b2 << 1) & MAX_BLUE;
315 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
316 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
321 for (r = 0; r <= MAX_RED; r++)
324 if ((r2 & 0x10) == 0)
327 r2 = (r2 << 1) & MAX_RED;
331 for (g = 0; g <= MAX_GREEN; g++)
334 if ((g2 & GREEN_HI_BIT) == 0)
337 g2 = (g2 << 1) & MAX_GREEN;
341 for (b = 0; b <= MAX_BLUE; b++)
344 if ((b2 & 0x10) == 0)
347 b2 = (b2 << 1) & MAX_BLUE;
351 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
352 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
358 // Build a lookup table that if the top bit of the color value is zero
359 // then the value is zero, otherwise its just the value.
360 for (r = 0; r <= MAX_RED; r++)
363 if ((r2 & 0x10) == 0)
368 for (g = 0; g <= MAX_GREEN; g++)
371 if ((g2 & GREEN_HI_BIT) == 0)
375 for (b = 0; b <= MAX_BLUE; b++)
378 if ((b2 & 0x10) == 0)
383 GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
384 GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
392 GFX.ZERO_OR_X2 = NULL;
399 void S9xGraphicsDeinit (void)
401 // Free any memory allocated in S9xGraphicsInit
404 free ((char *) GFX.X2);
409 free ((char *) GFX.ZERO_OR_X2);
410 GFX.ZERO_OR_X2 = NULL;
414 free ((char *) GFX.ZERO);
419 void S9xBuildDirectColourMaps ()
421 for (uint32 p = 0; p < 8; p++)
423 for (uint32 c = 0; c < 256; c++)
426 DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
427 ((c & 0x38) >> 1) | (p & 2),
428 ((c & 0xc0) >> 3) | (p & 4));
431 IPPU.DirectColourMapsNeedRebuild = FALSE;
434 void S9xStartScreenRefresh ()
436 if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0) {
437 free(GFX.InfoString);
438 GFX.InfoString = NULL;
441 if (IPPU.RenderThisFrame)
444 if (!S9xInitUpdate ())
446 IPPU.RenderThisFrame = FALSE;
450 IPPU.RenderedFramesCount++;
451 IPPU.PreviousLine = IPPU.CurrentLine = 0;
452 IPPU.MaxBrightness = PPU.Brightness;
453 IPPU.LatchedBlanking = PPU.ForcedBlanking;
454 IPPU.LatchedInterlace = (Memory.FillRAM[0x2133] & 1);
455 IPPU.RenderedScreenWidth = 256;
456 IPPU.RenderedScreenHeight = PPU.ScreenHeight;
457 IPPU.DoubleWidthPixels = FALSE;
458 GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
459 GFX.PPL = GFX.PPLx2 >> 1;
460 PPU.RecomputeClipWindows = TRUE;
461 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
462 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
464 if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0)
466 IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount;
467 IPPU.RenderedFramesCount = 0;
472 void RenderLine (uint8 C)
474 if (IPPU.RenderThisFrame)
477 LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
478 LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
479 LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
480 LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
484 struct SLineMatrixData *p = &LineMatrixData [C];
485 p->MatrixA = PPU.MatrixA;
486 p->MatrixB = PPU.MatrixB;
487 p->MatrixC = PPU.MatrixC;
488 p->MatrixD = PPU.MatrixD;
489 p->CentreX = PPU.CentreX;
490 p->CentreY = PPU.CentreY;
495 if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
496 PPU.BG[2].HOffset == 0xe000)
498 LineData[C].BG[2].VOffset = 0xe1;
499 LineData[C].BG[2].HOffset = 0;
505 LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
506 LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
507 LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
508 LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
512 IPPU.CurrentLine = C + 1;
517 void S9xEndScreenRefresh()
519 IPPU.HDMAStarted = FALSE;
522 if (IPPU.RenderThisFrame)
525 if (IPPU.ColorsChanged)
527 uint32 saved = PPU.CGDATA[0];
528 if (!Settings.SixteenBit)
530 // Hack for Super Mario World - to get its sky blue
531 // (It uses Fixed colour addition on the backdrop colour)
532 if (!(Memory.FillRAM [0x2131] & 0x80) &&
533 (Memory.FillRAM[0x2131] & 0x20) &&
534 (PPU.FixedColourRed || PPU.FixedColourGreen ||
535 PPU.FixedColourBlue))
537 PPU.CGDATA[0] = PPU.FixedColourRed |
538 (PPU.FixedColourGreen << 5) |
539 (PPU.FixedColourBlue << 10);
542 IPPU.ColorsChanged = FALSE;
546 PPU.CGDATA[0] = saved;
548 GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
549 GFX.PPL = GFX.PPLx2 >> 1;
551 if (Settings.DisplayFrameRate)
552 S9xDisplayFrameRate ();
554 S9xDisplayString (GFX.InfoString);
556 S9xDeinitUpdate (IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
557 Settings.SixteenBit);
565 if (CPU.Flags & FRAME_ADVANCE_FLAG)
567 if (ICPU.FrameAdvanceCount)
569 ICPU.FrameAdvanceCount--;
570 IPPU.RenderThisFrame = TRUE;
575 CPU.Flags &= ~FRAME_ADVANCE_FLAG;
576 CPU.Flags |= DEBUG_MODE_FLAG;
581 if (CPU.SRAMModified)
583 if (!CPU.AutoSaveTimer)
585 if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
586 CPU.SRAMModified = FALSE;
590 if (!--CPU.AutoSaveTimer)
593 CPU.SRAMModified = FALSE;
599 void S9xSetInfoString (const char * fmt, ...)
604 if (vasprintf(&GFX.InfoString, fmt, ap) > 0) {
605 GFX.InfoStringTimeout = 120;
608 GFX.InfoStringTimeout = 0;
614 INLINE void SelectTileRenderer (bool8_32 normal)
618 DrawTilePtr = DrawTile16;
619 DrawClippedTilePtr = DrawClippedTile16;
620 DrawLargePixelPtr = DrawLargePixel16;
624 if (GFX.r2131 & 0x80)
626 if (GFX.r2131 & 0x40)
630 DrawTilePtr = DrawTile16Sub1_2;
631 DrawClippedTilePtr = DrawClippedTile16Sub1_2;
635 // Fixed colour substraction
636 DrawTilePtr = DrawTile16FixedSub1_2;
637 DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
639 DrawLargePixelPtr = DrawLargePixel16Sub1_2;
643 DrawTilePtr = DrawTile16Sub;
644 DrawClippedTilePtr = DrawClippedTile16Sub;
645 DrawLargePixelPtr = DrawLargePixel16Sub;
650 if (GFX.r2131 & 0x40)
654 DrawTilePtr = DrawTile16Add1_2;
655 DrawClippedTilePtr = DrawClippedTile16Add1_2;
659 // Fixed colour addition
660 DrawTilePtr = DrawTile16FixedAdd1_2;
661 DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
663 DrawLargePixelPtr = DrawLargePixel16Add1_2;
667 DrawTilePtr = DrawTile16Add;
668 DrawClippedTilePtr = DrawClippedTile16Add;
669 DrawLargePixelPtr = DrawLargePixel16Add;
680 switch (PPU.OBJSizeSelect)
711 int FirstSprite = PPU.FirstSprite & 0x7f;
716 if (PPU.OBJ [S].Size)
721 long VPos = PPU.OBJ [S].VPos;
723 if (VPos >= PPU.ScreenHeight)
725 if (PPU.OBJ [S].HPos < 256 && PPU.OBJ [S].HPos > -Size &&
726 VPos < PPU.ScreenHeight && VPos > -Size)
728 GFX.OBJList [C++] = S;
730 GFX.VPositions[S] = VPos;
733 } while (S != FirstSprite);
735 // Terminate the list
736 GFX.OBJList [C] = -1;
737 IPPU.OBJChanged = FALSE;
740 void DrawOBJS (bool8_32 OnMain = FALSE, uint8 D = 0)
743 uint32 BaseTile, Tile;
749 BG.TileAddress = PPU.OBJNameBase;
750 BG.StartPalette = 128;
753 BG.Buffer = IPPU.TileCache [TILE_4BIT];
754 BG.Buffered = IPPU.TileCached [TILE_4BIT];
755 BG.NameSelect = PPU.OBJNameSelect;
756 BG.DirectColourMode = FALSE;
763 for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
765 int VPos = GFX.VPositions [S];
766 int Size = GFX.Sizes[S];
770 if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
773 if (OnMain && SUB_OR_ADD(4))
775 SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
778 BaseTile = PPU.OBJ[S].Name | (PPU.OBJ[S].Palette << 10);
780 if (PPU.OBJ[S].HFlip)
782 BaseTile += ((Size >> 3) - 1) | H_FLIP;
785 if (PPU.OBJ[S].VFlip)
788 int clipcount = GFX.pCurrentClip->Count [4];
792 GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
794 for (int clip = 0; clip < clipcount; clip++)
798 if (!GFX.pCurrentClip->Count [4])
805 Left = GFX.pCurrentClip->Left [clip][4];
806 Right = GFX.pCurrentClip->Right [clip][4];
809 if (Right <= Left || PPU.OBJ[S].HPos + Size <= Left ||
810 PPU.OBJ[S].HPos >= Right)
813 for (int Y = 0; Y < Size; Y += 8)
815 if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
822 if ((StartLine = VPos + Y) < (int) GFX.StartY)
824 StartLine = GFX.StartY - StartLine;
825 LineCount = 8 - StartLine;
832 if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
833 if ((LineCount -= Last) <= 0)
836 TileLine = StartLine << 3;
837 O = (VPos + Y + StartLine) * GFX.PPL;
838 if (!PPU.OBJ[S].VFlip)
839 Tile = BaseTile + (Y << 1);
841 Tile = BaseTile + ((Size - Y - 8) << 1);
843 int Middle = Size >> 3;
844 if (PPU.OBJ[S].HPos < Left)
846 Tile += ((Left - PPU.OBJ[S].HPos) >> 3) * TileInc;
847 Middle -= (Left - PPU.OBJ[S].HPos) >> 3;
848 O += Left * GFX.PixSize;
849 if ((Offset = (Left - PPU.OBJ[S].HPos) & 7))
851 O -= Offset * GFX.PixSize;
853 int Width = Right - Left;
856 (*DrawClippedTilePtr) (Tile, O, Offset, W,
857 TileLine, LineCount);
863 O += 8 * GFX.PixSize;
867 O += PPU.OBJ[S].HPos * GFX.PixSize;
869 if (PPU.OBJ[S].HPos + Size >= Right)
871 Middle -= ((PPU.OBJ[S].HPos + Size + 7) -
873 Offset = (Right - (PPU.OBJ[S].HPos + Size)) & 7;
878 for (int X = 0; X < Middle; X++, O += 8 * GFX.PixSize,
881 (*DrawTilePtr) (Tile, O, TileLine, LineCount);
885 (*DrawClippedTilePtr) (Tile, O, 0, Offset,
886 TileLine, LineCount);
894 void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
903 uint8 depths [2] = {Z1, Z2};
906 BG.StartPalette = bg << 5;
910 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
912 if (PPU.BG[bg].SCSize & 1)
917 if (PPU.BG[bg].SCSize & 2)
922 if (PPU.BG[bg].SCSize & 1)
931 if (BG.TileSize == 16)
942 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
944 uint32 VOffset = LineData [Y].BG[bg].VOffset;
945 uint32 HOffset = LineData [Y].BG[bg].HOffset;
946 uint32 MosaicOffset = Y % PPU.Mosaic;
948 for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
949 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
950 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
953 uint32 MosaicLine = VOffset + Y - MosaicOffset;
955 if (Y + Lines > GFX.EndY)
956 Lines = GFX.EndY + 1 - Y;
957 uint32 VirtAlign = (MosaicLine & 7) << 3;
962 uint32 ScreenLine = MosaicLine >> OffsetShift;
963 uint32 Rem16 = MosaicLine & 15;
965 if (ScreenLine & 0x20)
970 b1 += (ScreenLine & 0x1f) << 5;
971 b2 += (ScreenLine & 0x1f) << 5;
976 uint32 ClipCount = GFX.pCurrentClip->Count [bg];
977 uint32 HPos = HOffset;
978 uint32 PixWidth = PPU.Mosaic;
983 for (uint32 clip = 0; clip < ClipCount; clip++)
985 if (GFX.pCurrentClip->Count [bg])
987 Left = GFX.pCurrentClip->Left [clip][bg];
988 Right = GFX.pCurrentClip->Right [clip][bg];
989 uint32 r = Left % PPU.Mosaic;
990 HPos = HOffset + Left;
991 PixWidth = PPU.Mosaic - r;
993 uint32 s = Y * GFX.PPL + Left * GFX.PixSize;
994 for (uint32 x = Left; x < Right; x += PixWidth,
995 s += PixWidth * GFX.PixSize,
996 HPos += PixWidth, PixWidth = PPU.Mosaic)
998 uint32 Quot = (HPos & OffsetMask) >> 3;
1000 if (x + PixWidth >= Right)
1001 PixWidth = Right - x;
1003 if (BG.TileSize == 8)
1006 t = b2 + (Quot & 0x1f);
1013 t = b2 + ((Quot >> 1) & 0x1f);
1015 t = b1 + (Quot >> 1);
1018 Tile = READ_2BYTES (t);
1019 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1022 if (BG.TileSize != 8)
1026 // Horizontal flip, but what about vertical flip ?
1029 // Both horzontal & vertical flip
1032 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1038 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1045 // Horizontal flip only
1048 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1054 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1062 // No horizontal flip, but is there a vertical flip ?
1065 // Vertical flip only
1068 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1074 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1084 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1090 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1098 (*DrawLargePixelPtr) (Tile, s, HPos & 7, PixWidth,
1105 void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1119 int VOffsetOffset = BGMode == 4 ? 0 : 32;
1120 uint8 depths [2] = {Z1, Z2};
1122 BG.StartPalette = 0;
1124 BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
1126 if (PPU.BG[2].SCSize & 1)
1131 if (PPU.BG[2].SCSize & 2)
1136 if (PPU.BG[2].SCSize & 1)
1141 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1143 if (PPU.BG[bg].SCSize & 1)
1148 if (PPU.BG[bg].SCSize & 2)
1152 if (PPU.BG[bg].SCSize & 1)
1157 static const int Lines = 1;
1160 int OffsetEnableMask = 1 << (bg + 13);
1162 if (BG.TileSize == 16)
1173 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
1175 uint32 VOff = LineData [Y].BG[2].VOffset;
1176 uint32 HOff = LineData [Y].BG[2].HOffset;
1178 int ScreenLine = VOff >> 3;
1185 if (ScreenLine & 0x20)
1186 s1 = BPS2, s2 = BPS3;
1188 s1 = BPS0, s2 = BPS1;
1190 s1 += (ScreenLine & 0x1f) << 5;
1191 s2 += (ScreenLine & 0x1f) << 5;
1193 int clipcount = GFX.pCurrentClip->Count [bg];
1197 for (int clip = 0; clip < clipcount; clip++)
1202 if (!GFX.pCurrentClip->Count [bg])
1209 Left = GFX.pCurrentClip->Left [clip][bg];
1210 Right = GFX.pCurrentClip->Right [clip][bg];
1218 uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
1229 uint32 TotalCount = 0;
1230 uint32 MaxCount = 8;
1232 uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1233 bool8_32 left_hand_edge = (Left == 0);
1234 Width = Right - Left;
1237 MaxCount = 8 - (Left & 7);
1239 while (Left < Right)
1243 // The SNES offset-per-tile background mode has a
1244 // hardware limitation that the offsets cannot be set
1245 // for the tile at the left-hand edge of the screen.
1246 VOffset = LineData [Y].BG[bg].VOffset;
1247 HOffset = LineHOffset;
1248 left_hand_edge = FALSE;
1252 // All subsequent offset tile data is shifted left by one,
1253 // hence the - 1 below.
1254 Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
1257 s0 = s2 + (Quot2 & 0x1f);
1261 HCellOffset = READ_2BYTES (s0);
1265 VOffset = LineData [Y].BG[bg].VOffset;
1266 HOffset=LineHOffset;
1267 if ((HCellOffset & OffsetEnableMask))
1269 if (HCellOffset & 0x8000)
1270 VOffset = HCellOffset + 1;
1272 HOffset = HCellOffset;
1277 VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
1278 if ((VCellOffset & OffsetEnableMask))
1279 VOffset = VCellOffset + 1;
1281 VOffset = LineData [Y].BG[bg].VOffset;
1283 if ((HCellOffset & OffsetEnableMask))
1284 HOffset = (HCellOffset & ~7)|(LineHOffset&7);
1286 HOffset=LineHOffset;
1289 VirtAlign = ((Y + VOffset) & 7) << 3;
1290 ScreenLine = (VOffset + Y) >> OffsetShift;
1292 if (((VOffset + Y) & 15) > 7)
1303 if (ScreenLine & 0x20)
1308 b1 += (ScreenLine & 0x1f) << 5;
1309 b2 += (ScreenLine & 0x1f) << 5;
1311 HPos = (HOffset + Left) & OffsetMask;
1315 if (BG.TileSize == 8)
1318 t = b2 + (Quot & 0x1f);
1325 t = b2 + ((Quot >> 1) & 0x1f);
1327 t = b1 + (Quot >> 1);
1330 if (MaxCount + TotalCount > Width)
1331 MaxCount = Width - TotalCount;
1336 if (Count > MaxCount)
1339 s -= Offset * GFX.PixSize;
1340 Tile = READ_2BYTES(t);
1341 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1343 if (BG.TileSize == 8)
1344 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines);
1347 if (!(Tile & (V_FLIP | H_FLIP)))
1349 // Normal, unflipped
1350 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1351 s, Offset, Count, VirtAlign, Lines);
1359 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1360 s, Offset, Count, VirtAlign, Lines);
1365 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1366 s, Offset, Count, VirtAlign, Lines);
1372 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1373 s, Offset, Count, VirtAlign, Lines);
1378 TotalCount += Count;
1379 s += (Offset + Count) * GFX.PixSize;
1386 void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
1390 GFX.Pitch = GFX.RealPitch;
1391 GFX.PPL = GFX.PPLx2 >> 1;
1393 uint8 depths [2] = {Z1, Z2};
1402 BG.StartPalette = 0;
1404 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1406 if ((PPU.BG[bg].SCSize & 1))
1411 if ((PPU.BG[bg].SCSize & 2))
1416 if ((PPU.BG[bg].SCSize & 1))
1425 if (BG.TileSize == 16)
1427 VOffsetMask = 0x3ff;
1432 VOffsetMask = 0x1ff;
1435 int endy = GFX.EndY;
1437 for (int Y = GFX.StartY; Y <= endy; Y += Lines)
1440 uint32 VOffset = LineData [y].BG[bg].VOffset;
1441 uint32 HOffset = LineData [y].BG[bg].HOffset;
1442 int VirtAlign = (Y + VOffset) & 7;
1444 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1445 if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
1446 (HOffset != LineData [y + Lines].BG[bg].HOffset))
1450 if (Y + Lines > endy)
1451 Lines = endy + 1 - Y;
1453 int ScreenLine = (VOffset + Y) >> VOffsetShift;
1456 if (((VOffset + Y) & 15) > 7)
1469 if (ScreenLine & 0x20)
1474 b1 += (ScreenLine & 0x1f) << 5;
1475 b2 += (ScreenLine & 0x1f) << 5;
1477 int clipcount = GFX.pCurrentClip->Count [bg];
1480 for (int clip = 0; clip < clipcount; clip++)
1485 if (!GFX.pCurrentClip->Count [bg])
1492 Left = GFX.pCurrentClip->Left [clip][bg] * 2;
1493 Right = GFX.pCurrentClip->Right [clip][bg] * 2;
1499 uint32 s = (Left>>1) * GFX.PixSize + Y * GFX.PPL;
1500 uint32 HPos = (HOffset + Left * GFX.PixSize) & 0x3ff;
1502 uint32 Quot = HPos >> 3;
1507 t = b2 + ((Quot >> 1) & 0x1f);
1509 t = b1 + (Quot >> 1);
1511 Width = Right - Left;
1512 // Left hand edge clipped tile
1515 int Offset = (HPos & 7);
1519 if (s) // XXX: Workaround for underflow (Secret of MANA)
1521 Tile = READ_2BYTES (t);
1522 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1524 if (BG.TileSize == 8)
1526 if (!(Tile & H_FLIP))
1528 // Normal, unflipped
1529 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1530 s, Offset, Count, VirtAlign, Lines);
1535 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1536 s, Offset, Count, VirtAlign, Lines);
1541 if (!(Tile & (V_FLIP | H_FLIP)))
1543 // Normal, unflipped
1544 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1545 s, Offset, Count, VirtAlign, Lines);
1553 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1554 s, Offset, Count, VirtAlign, Lines);
1559 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1560 s, Offset, Count, VirtAlign, Lines);
1566 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1567 s, Offset, Count, VirtAlign, Lines);
1574 else if (Quot == 127)
1580 // Middle, unclipped tiles
1581 Count = Width - Count;
1582 int Middle = Count >> 3;
1584 for (int C = Middle; C > 0; s += 4, Quot++, C--)
1586 Tile = READ_2BYTES(t);
1587 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1588 if (BG.TileSize == 8)
1590 if (!(Tile & H_FLIP))
1592 // Normal, unflipped
1593 (*DrawHiResTilePtr) (Tile + (Quot & 1),
1594 s, VirtAlign, Lines);
1599 (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1600 s, VirtAlign, Lines);
1605 if (!(Tile & (V_FLIP | H_FLIP)))
1607 // Normal, unflipped
1608 (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1609 s, VirtAlign, Lines);
1617 (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1618 s, VirtAlign, Lines);
1623 (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1624 s, VirtAlign, Lines);
1630 (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1631 s, VirtAlign, Lines);
1643 // Right-hand edge clipped tiles
1646 Tile = READ_2BYTES(t);
1647 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1648 if (BG.TileSize == 8)
1650 if (!(Tile & H_FLIP))
1652 // Normal, unflipped
1653 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1654 s, 0, Count, VirtAlign, Lines);
1659 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1660 s, 0, Count, VirtAlign, Lines);
1665 if (!(Tile & (V_FLIP | H_FLIP)))
1667 // Normal, unflipped
1668 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1669 s, 0, Count, VirtAlign, Lines);
1677 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1678 s, 0, Count, VirtAlign, Lines);
1683 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1684 s, 0, Count, VirtAlign, Lines);
1690 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1691 s, 0, Count, VirtAlign, Lines);
1699 void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1703 BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1704 BG.BitShift = BitShifts[BGMode][bg];
1705 BG.TileShift = TileShifts[BGMode][bg];
1706 BG.TileAddress = PPU.BG[bg].NameBase << 1;
1708 BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1709 BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1710 BG.PaletteShift = PaletteShifts[BGMode][bg];
1711 BG.PaletteMask = PaletteMasks[BGMode][bg];
1712 BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1715 if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1717 DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1724 if (Settings.WrestlemaniaArcade)
1726 case 4: // Used by Puzzle Bobble
1727 DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1731 case 6: // XXX: is also offset per tile.
1732 DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1748 uint8 depths [2] = {Z1, Z2};
1751 BG.StartPalette = bg << 5;
1753 BG.StartPalette = 0;
1755 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1757 if (PPU.BG[bg].SCSize & 1)
1762 if (PPU.BG[bg].SCSize & 2)
1767 if (PPU.BG[bg].SCSize & 1)
1776 if (BG.TileSize == 16)
1787 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1789 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1790 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1791 int VirtAlign = (Y + VOffset) & 7;
1793 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1794 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1795 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1798 if (Y + Lines > GFX.EndY)
1799 Lines = GFX.EndY + 1 - Y;
1803 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1806 if (((VOffset + Y) & 15) > 7)
1819 if (ScreenLine & 0x20)
1824 b1 += (ScreenLine & 0x1f) << 5;
1825 b2 += (ScreenLine & 0x1f) << 5;
1827 int clipcount = GFX.pCurrentClip->Count [bg];
1830 for (int clip = 0; clip < clipcount; clip++)
1835 if (!GFX.pCurrentClip->Count [bg])
1842 Left = GFX.pCurrentClip->Left [clip][bg];
1843 Right = GFX.pCurrentClip->Right [clip][bg];
1849 uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1850 uint32 HPos = (HOffset + Left) & OffsetMask;
1852 uint32 Quot = HPos >> 3;
1856 if (BG.TileSize == 8)
1859 t = b2 + (Quot & 0x1f);
1866 t = b2 + ((Quot >> 1) & 0x1f);
1868 t = b1 + (Quot >> 1);
1871 Width = Right - Left;
1872 // Left hand edge clipped tile
1875 uint32 Offset = (HPos & 7);
1879 s -= Offset * GFX.PixSize;
1880 Tile = READ_2BYTES(t);
1881 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1883 if (BG.TileSize == 8)
1885 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1890 if (!(Tile & (V_FLIP | H_FLIP)))
1892 // Normal, unflipped
1893 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1894 s, Offset, Count, VirtAlign, Lines);
1902 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1903 s, Offset, Count, VirtAlign, Lines);
1908 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1909 s, Offset, Count, VirtAlign, Lines);
1915 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
1916 Offset, Count, VirtAlign, Lines);
1920 if (BG.TileSize == 8)
1925 else if (Quot == 63)
1933 else if (Quot == 127)
1937 s += 8 * GFX.PixSize;
1940 // Middle, unclipped tiles
1941 Count = Width - Count;
1942 int Middle = Count >> 3;
1944 for (int C = Middle; C > 0; s += 8 * GFX.PixSize, Quot++, C--)
1946 Tile = READ_2BYTES(t);
1947 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1949 if (BG.TileSize != 8)
1953 // Horizontal flip, but what about vertical flip ?
1956 // Both horzontal & vertical flip
1957 (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
1962 // Horizontal flip only
1963 (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
1969 // No horizontal flip, but is there a vertical flip ?
1972 // Vertical flip only
1973 (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
1979 (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
1986 (*DrawTilePtr) (Tile, s, VirtAlign, Lines);
1989 if (BG.TileSize == 8)
2008 // Right-hand edge clipped tiles
2011 Tile = READ_2BYTES(t);
2012 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
2014 if (BG.TileSize == 8)
2015 (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
2019 if (!(Tile & (V_FLIP | H_FLIP)))
2021 // Normal, unflipped
2022 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
2023 Count, VirtAlign, Lines);
2031 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2032 s, 0, Count, VirtAlign,
2038 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2039 s, 0, Count, VirtAlign,
2046 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
2047 s, 0, Count, VirtAlign,
2056 #define RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2057 const uint8 bmask = MASK; \
2058 for (int x = startx; x != endx; \
2059 x += (HFLIP ? -1 : 1), AA += aa, CC += cc, p++, d++) \
2061 int X = ((AA + BB) >> 8) & 0x3ff; \
2062 int Y = ((CC + DD) >> 8) & 0x3ff; \
2063 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2064 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2065 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2073 #define RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,CFILT) \
2074 register int AABB = AA + BB; \
2075 register int CCDD = CC + DD; \
2076 const uint8 bmask = MASK; \
2077 for (int x = startx; x != endx; \
2078 x += (HFLIP ? -1 : 1), AABB += aa, CCDD += cc, p++, d++) \
2080 register uint16 X = ((AABB) >> 8) CFILT; \
2081 register uint16 Y = ((CCDD) >> 8) CFILT; \
2083 if (((X | Y) & ~0x3ff) == 0) { \
2084 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2085 uint8 b = TileData[((Y & 7) << 4) + ((X & 7) << 1)]; \
2086 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2087 if (z > *d && b) { \
2091 } else if (REPEAT == 3) { \
2092 X = (x + HOffset) & 7; \
2093 Y = (yy + CentreY) & 7; \
2094 uint8 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2095 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2096 if (z > *d && b) { \
2103 #define RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,MASK,PRIOMASK) \
2104 for (uint32 clip = 0; clip < ClipCount; clip++) \
2106 if (GFX.pCurrentClip->Count [bg]) \
2108 Left = GFX.pCurrentClip->Left [clip][bg]; \
2109 Right = GFX.pCurrentClip->Right [clip][bg]; \
2110 if (Right <= Left) \
2113 register TYPE *p = (TYPE *) Screen + Left; \
2114 register uint8 *d = Depth + Left; \
2118 startx = Right - 1; \
2132 xx = startx + (HOffset - CentreX) % 1023; \
2134 xx = startx + HOffset - CentreX; \
2135 int AA = l->MatrixA * xx; \
2136 int CC = l->MatrixC * xx; \
2140 RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2141 } else if (DEZAEMON) { \
2142 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,& 0x7ff) \
2144 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,) \
2148 #ifdef USE_CRAZY_OPTS
2150 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON) \
2151 if (GFX.Mode7PriorityMask) { \
2152 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0x7f,0x80) \
2154 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0xff,0x00) \
2157 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,HFLIP) \
2158 if (Settings.Dezaemon && PPU.Mode7Repeat) { \
2159 switch (PPU.Mode7Repeat) { \
2160 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,1); break; \
2161 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,1); break; \
2162 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,1); break; \
2165 switch (PPU.Mode7Repeat) { \
2166 case 0: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,0,0); break; \
2167 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,0); break; \
2168 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,0); break; \
2169 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,0); break; \
2173 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC) \
2174 if (PPU.Mode7HFlip) { \
2175 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,1); \
2177 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,0); \
2180 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2181 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC)
2185 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2186 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,PPU.Mode7HFlip,PPU.Mode7Repeat,Settings.Dezaemon,GFX.Mode7Mask,GFX.Mode7PriorityMask)
2190 #define RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2191 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2195 int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2196 int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2198 int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2199 int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2201 if (PPU.Mode7VFlip) \
2202 yy = 261 - (int) Line; \
2206 if (PPU.Mode7Repeat == 0) \
2207 yy += (VOffset - CentreY) % 1023; \
2209 yy += VOffset - CentreY; \
2210 int BB = l->MatrixB * yy + (CentreX << 8); \
2211 int DD = l->MatrixD * yy + (CentreY << 8); \
2213 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2216 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2219 uint8 * const VRAM1 = Memory.VRAM + 1; \
2220 if (GFX.r2130 & 1) \
2222 if (IPPU.DirectColourMapsNeedRebuild) \
2223 S9xBuildDirectColourMaps (); \
2224 GFX.ScreenColors = DirectColourMaps [0]; \
2227 GFX.ScreenColors = IPPU.ScreenColors; \
2232 uint32 Right = 256; \
2233 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2238 Screen += GFX.StartY * GFX.Pitch; \
2239 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2240 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2241 RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2245 void DrawBGMode7Background (uint8 *Screen, int bg)
2247 RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & bmask))
2250 void DrawBGMode7Background16 (uint8 *Screen, int bg)
2252 RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2255 void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2257 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2258 (*(d + GFX.DepthDelta) != 1 ?
2259 COLOR_ADD (GFX.ScreenColors [b & bmask],
2261 COLOR_ADD (GFX.ScreenColors [b & bmask],
2263 GFX.ScreenColors [b & bmask]);
2266 void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2268 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2269 (*(d + GFX.DepthDelta) != 1 ?
2270 COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2272 COLOR_ADD (GFX.ScreenColors [b & bmask],
2274 GFX.ScreenColors [b & bmask]);
2277 void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2279 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2280 (*(d + GFX.DepthDelta) != 1 ?
2281 COLOR_SUB (GFX.ScreenColors [b & bmask],
2283 COLOR_SUB (GFX.ScreenColors [b & bmask],
2285 GFX.ScreenColors [b & bmask]);
2288 void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2290 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2291 (*(d + GFX.DepthDelta) != 1 ?
2292 COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2294 COLOR_SUB (GFX.ScreenColors [b & bmask],
2296 GFX.ScreenColors [b & bmask]);
2299 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2302 uint8 *VRAM1 = Memory.VRAM + 1; \
2303 if (GFX.r2130 & 1) \
2305 if (IPPU.DirectColourMapsNeedRebuild) \
2306 S9xBuildDirectColourMaps (); \
2307 GFX.ScreenColors = DirectColourMaps [0]; \
2310 GFX.ScreenColors = IPPU.ScreenColors; \
2316 uint32 Right = 256; \
2317 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2322 Screen += GFX.StartY * GFX.Pitch; \
2323 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2324 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2325 bool8_32 allowSimpleCase = FALSE; \
2326 if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2327 && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2328 && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2330 allowSimpleCase = TRUE; \
2332 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2336 int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2337 int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2339 int CentreX = ((int) l->CentreX << M7) >> M7; \
2340 int CentreY = ((int) l->CentreY << M7) >> M7; \
2342 if (PPU.Mode7VFlip) \
2343 yy = 261 - (int) Line; \
2347 if (PPU.Mode7Repeat == 0) \
2348 yy += (VOffset - CentreY) % 1023; \
2350 yy += VOffset - CentreY; \
2351 bool8_32 simpleCase = FALSE; \
2354 /* Make a special case for the identity matrix, since it's a common case and */ \
2355 /* can be done much more quickly without special effects */ \
2356 if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2358 BB = CentreX << 8; \
2359 DD = (yy + CentreY) << 8; \
2360 simpleCase = TRUE; \
2364 BB = l->MatrixB * yy + (CentreX << 8); \
2365 DD = l->MatrixD * yy + (CentreY << 8); \
2368 for (uint32 clip = 0; clip < ClipCount; clip++) \
2370 if (GFX.pCurrentClip->Count [bg]) \
2372 Left = GFX.pCurrentClip->Left [clip][bg]; \
2373 Right = GFX.pCurrentClip->Right [clip][bg]; \
2374 if (Right <= Left) \
2377 TYPE *p = (TYPE *) Screen + Left; \
2378 uint8 *d = Depth + Left; \
2380 if (PPU.Mode7HFlip) \
2382 startx = Right - 1; \
2397 if (PPU.Mode7Repeat == 0) \
2398 xx = startx + (HOffset - CentreX) % 1023; \
2400 xx = startx + HOffset - CentreX; \
2408 AA = l->MatrixA * xx; \
2409 CC = l->MatrixC * xx; \
2413 if (!PPU.Mode7Repeat) \
2418 int X = ((AA + BB) >> 8) & 0x3ff; \
2419 int Y = (DD >> 8) & 0x3ff; \
2420 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2421 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2422 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2423 if (GFX.Z1 > *d && b) \
2425 TYPE theColor = COLORFUNC; \
2426 *p = (FUNC) | ALPHA_BITS_MASK; \
2429 AA += aa, p++, d++; \
2431 } while (x != endx); \
2437 int X = (AA + BB) >> 8; \
2440 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2446 if (((X | Y) & ~0x3ff) == 0) \
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 else if (PPU.Mode7Repeat == 3) \
2460 X = (x + HOffset) & 7; \
2461 Y = (yy + CentreY) & 7; \
2462 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2463 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2464 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2465 if (GFX.Z1 > *d && b) \
2467 TYPE theColor = COLORFUNC; \
2468 *p = (FUNC) | ALPHA_BITS_MASK; \
2472 AA += aa; p++; d++; \
2474 } while (x != endx); \
2477 else if (!PPU.Mode7Repeat) \
2479 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2480 /* the location of one point in the _sampled_ image, and weight them according */ \
2481 /* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
2484 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2485 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2486 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2487 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2488 /* You can think of this as a kind of mipmapping. */ \
2489 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2491 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2493 uint32 xPos = AA + BB; \
2494 uint32 xPix = xPos >> 8; \
2495 uint32 yPos = CC + DD; \
2496 uint32 yPix = yPos >> 8; \
2497 uint32 X = xPix & 0x3ff; \
2498 uint32 Y = yPix & 0x3ff; \
2499 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2500 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2501 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2502 if (GFX.Z1 > *d && b) \
2504 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2505 uint32 X10 = (xPix + dir) & 0x3ff; \
2506 uint32 Y01 = (yPix + dir) & 0x3ff; \
2507 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2508 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2509 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2510 uint32 p1 = COLORFUNC; \
2511 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2512 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2513 uint32 p2 = COLORFUNC; \
2514 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2515 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2516 uint32 p4 = COLORFUNC; \
2517 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2518 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2519 uint32 p3 = COLORFUNC; \
2520 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2521 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2522 uint32 Xdel = (xPos >> 3) & 0x1F; \
2523 uint32 Ydel = (yPos >> 3) & 0x1F; \
2524 uint32 XY = (Xdel*Ydel) >> 5; \
2525 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2526 uint32 area2 = Xdel - XY; \
2527 uint32 area3 = Ydel - XY; \
2528 uint32 area4 = XY; \
2529 uint32 tempColor = ((area1 * p1) + \
2532 (area4 * p4)) >> 5; \
2533 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2534 *p = (FUNC) | ALPHA_BITS_MASK; \
2540 /* The oversampling method: get the colors at four corners of a square */ \
2541 /* in the _displayed_ image, and average them. It's sharp and clean, but */ \
2542 /* gives the usual huge pixels when the source image gets "close." */ \
2544 /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2545 uint32 aaDelX = aa >> 1; \
2546 uint32 ccDelX = cc >> 1; \
2547 uint32 bbDelY = l->MatrixB >> 1; \
2548 uint32 ddDelY = l->MatrixD >> 1; \
2549 /* Offset the location within the source image so that the four sampled points */ \
2550 /* center around where the single point would otherwise have been drawn. */ \
2551 BB -= (bbDelY >> 1); \
2552 DD -= (ddDelY >> 1); \
2553 AA -= (aaDelX >> 1); \
2554 CC -= (ccDelX >> 1); \
2555 uint32 BB10 = BB + aaDelX; \
2556 uint32 BB01 = BB + bbDelY; \
2557 uint32 BB11 = BB + aaDelX + bbDelY; \
2558 uint32 DD10 = DD + ccDelX; \
2559 uint32 DD01 = DD + ddDelY; \
2560 uint32 DD11 = DD + ccDelX + ddDelY; \
2561 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2563 uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2564 uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2565 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2566 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2567 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2568 if (GFX.Z1 > *d && b) \
2570 /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2571 /* source image that we're going to examine. */ \
2572 uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2573 uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2574 uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2575 uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2576 uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2577 uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2578 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2579 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2580 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2581 TYPE p1 = COLORFUNC; \
2582 b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2583 TYPE p2 = COLORFUNC; \
2584 b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2585 TYPE p3 = COLORFUNC; \
2586 b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2587 TYPE p4 = COLORFUNC; \
2588 TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2589 *p = (FUNC) | ALPHA_BITS_MASK; \
2597 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2599 uint32 xPos = AA + BB; \
2600 uint32 xPix = xPos >> 8; \
2601 uint32 yPos = CC + DD; \
2602 uint32 yPix = yPos >> 8; \
2607 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2613 if (((X | Y) & ~0x3ff) == 0) \
2615 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2616 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2617 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2618 if (GFX.Z1 > *d && b) \
2620 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2621 uint32 X10 = (xPix + dir) & 0x3ff; \
2622 uint32 Y01 = (yPix + dir) & 0x3ff; \
2623 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2624 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2625 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2626 uint32 p1 = COLORFUNC; \
2627 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2628 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2629 uint32 p2 = COLORFUNC; \
2630 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2631 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2632 uint32 p4 = COLORFUNC; \
2633 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2634 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2635 uint32 p3 = COLORFUNC; \
2636 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2637 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2638 uint32 Xdel = (xPos >> 3) & 0x1F; \
2639 uint32 Ydel = (yPos >> 3) & 0x1F; \
2640 uint32 XY = (Xdel*Ydel) >> 5; \
2641 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2642 uint32 area2 = Xdel - XY; \
2643 uint32 area3 = Ydel - XY; \
2644 uint32 area4 = XY; \
2645 uint32 tempColor = ((area1 * p1) + \
2648 (area4 * p4)) >> 5; \
2649 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2650 *p = (FUNC) | ALPHA_BITS_MASK; \
2656 if (PPU.Mode7Repeat == 3) \
2658 X = (x + HOffset) & 7; \
2659 Y = (yy + CentreY) & 7; \
2660 uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2661 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2662 if (GFX.Z1 > *d && b) \
2664 TYPE theColor = COLORFUNC; \
2665 *p = (FUNC) | ALPHA_BITS_MASK; \
2675 STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2677 register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2678 ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2679 ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2680 ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2681 register uint32 y = (A & TWO_LOW_BITS_MASK) +
2682 (B & TWO_LOW_BITS_MASK) +
2683 (C & TWO_LOW_BITS_MASK) +
2684 (D & TWO_LOW_BITS_MASK);
2685 y = (y>>2) & TWO_LOW_BITS_MASK;
2689 void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2691 RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2694 void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2696 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2697 (*(d + GFX.DepthDelta) != 1 ?
2698 (COLOR_ADD (theColor,
2700 (COLOR_ADD (theColor,
2701 GFX.FixedColour))) :
2702 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2705 void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2707 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2708 (*(d + GFX.DepthDelta) != 1 ?
2709 COLOR_ADD1_2 (theColor,
2711 COLOR_ADD (theColor,
2713 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2716 void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2718 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2719 (*(d + GFX.DepthDelta) != 1 ?
2720 COLOR_SUB (theColor,
2722 COLOR_SUB (theColor,
2724 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2727 void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2729 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2730 (*(d + GFX.DepthDelta) != 1 ?
2731 COLOR_SUB1_2 (theColor,
2733 COLOR_SUB (theColor,
2735 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2738 #define _BUILD_SETUP(F) \
2739 GFX.BuildPixel = BuildPixel##F; \
2740 GFX.BuildPixel2 = BuildPixel2##F; \
2741 GFX.DecomposePixel = DecomposePixel##F; \
2742 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2743 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2744 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2745 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2746 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2747 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2748 MAX_RED = MAX_RED_##F; \
2749 MAX_GREEN = MAX_GREEN_##F; \
2750 MAX_BLUE = MAX_BLUE_##F; \
2751 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2752 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2753 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2754 GREEN_LOW_BIT_MASK_##F | \
2755 BLUE_LOW_BIT_MASK_##F); \
2756 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2757 GREEN_HI_BIT_MASK_##F | \
2758 BLUE_HI_BIT_MASK_##F); \
2759 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2760 GREEN_HI_BIT_MASK_##F | \
2761 BLUE_HI_BIT_MASK_##F) << 1); \
2762 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2763 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2764 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2765 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2766 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2767 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2768 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2769 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2770 ~TWO_LOW_BITS_MASK ) >> 2);
2772 void RenderScreen (uint8 *Screen, bool8_32 sub, bool8_32 force_no_add, uint8 D)
2784 GFX.pCurrentClip = &IPPU.Clip [0];
2785 BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2786 BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2787 BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2788 BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2789 OB = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2793 GFX.pCurrentClip = &IPPU.Clip [1];
2794 BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2795 BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2796 BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2797 BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2798 OB = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2801 sub |= force_no_add;
2803 if (PPU.BGMode <= 1)
2807 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2812 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2813 DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2817 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2818 DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2822 SelectTileRenderer (sub || !SUB_OR_ADD(2));
2823 DrawBackground (PPU.BGMode, 2, D + 3,
2824 (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2826 if (BG3 && PPU.BGMode == 0)
2828 SelectTileRenderer (sub || !SUB_OR_ADD(3));
2829 DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2832 else if (PPU.BGMode != 7)
2836 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2841 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2842 DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2844 if (PPU.BGMode != 6 && BG1)
2846 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2847 DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2854 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2857 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2861 if (Memory.FillRAM [0x2133] & 0x40)
2863 GFX.Mode7Mask = 0x7f;
2864 GFX.Mode7PriorityMask = 0x80;
2865 Mode7Depths [0] = 5 + D;
2866 Mode7Depths [1] = 9 + D;
2871 GFX.Mode7Mask = 0xff;
2872 GFX.Mode7PriorityMask = 0;
2873 Mode7Depths [0] = 5 + D;
2874 Mode7Depths [1] = 5 + D;
2877 if (sub || !SUB_OR_ADD(0))
2879 if (!Settings.Mode7Interpolate)
2880 DrawBGMode7Background16 (Screen, bg);
2882 DrawBGMode7Background16_i (Screen, bg);
2886 if (GFX.r2131 & 0x80)
2888 if (GFX.r2131 & 0x40)
2890 if (!Settings.Mode7Interpolate)
2891 DrawBGMode7Background16Sub1_2 (Screen, bg);
2893 DrawBGMode7Background16Sub1_2_i (Screen, bg);
2897 if (!Settings.Mode7Interpolate)
2898 DrawBGMode7Background16Sub (Screen, bg);
2900 DrawBGMode7Background16Sub_i (Screen, bg);
2905 if (GFX.r2131 & 0x40)
2907 if (!Settings.Mode7Interpolate)
2908 DrawBGMode7Background16Add1_2 (Screen, bg);
2910 DrawBGMode7Background16Add1_2_i (Screen, bg);
2914 if (!Settings.Mode7Interpolate)
2915 DrawBGMode7Background16Add (Screen, bg);
2917 DrawBGMode7Background16Add_i (Screen, bg);
2927 void DisplayChar (uint8 *Screen, uint8 c)
2929 int line = (((c & 0x7f) - 32) >> 4) * font_height;
2930 int offset = (((c & 0x7f) - 32) & 15) * font_width;
2932 if (Settings.SixteenBit)
2936 uint16 *s = (uint16 *) Screen;
2937 for (h = 0; h < font_height; h++, line++,
2938 s += GFX.PPL - font_width)
2940 for (w = 0; w < font_width; w++, s++)
2942 uint8 p = font [line][offset + w];
2957 for (h = 0; h < font_height; h++, line++,
2958 s += GFX.PPL - font_width)
2960 for (w = 0; w < font_width; w++, s++)
2962 uint8 p = font [line][offset + w];
2975 static void S9xDisplayFrameRate ()
2977 uint8 *Screen = GFX.Screen + 2 +
2978 (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch2;
2982 sprintf (string, "%02d/%02d", IPPU.DisplayedRenderedFrameCount,
2983 (int) Memory.ROMFramesPerSecond);
2987 Screen += (font_width - 1) * sizeof(uint16);
2989 for (i = 0; i < len; i++)
2991 DisplayChar (Screen, string [i]);
2992 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
2997 static void S9xDisplayString (const char *string)
2999 uint8 *Screen = GFX.Screen + 2 +
3000 (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch2;
3001 int len = strlen (string);
3002 int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
3006 for (i = 0; i < len; i++, char_count++)
3008 if (char_count >= max_chars || string [i] < 32)
3010 Screen -= Settings.SixteenBit ?
3011 (font_width - 1) * sizeof (uint16) * max_chars :
3012 (font_width - 1) * max_chars;
3013 Screen += font_height * GFX.Pitch;
3014 if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
3016 char_count -= max_chars;
3018 if (string [i] < 32)
3020 DisplayChar (Screen, string [i]);
3021 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
3026 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
3032 unsigned char *memoryfillram = Memory.FillRAM;
3034 // get local copies of vid registers to be used later
3035 GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN
3036 GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
3037 GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
3038 GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
3040 // If external sync is off and
3041 // main screens have not been configured the same as the sub screen and
3042 // color addition and subtraction has been diabled then
3044 // anything else it is 0
3045 GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
3046 (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
3047 (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
3049 // If sprite data has been changed then go through and
3050 // refresh the sprites.
3051 if (IPPU.OBJChanged)
3056 if (PPU.RecomputeClipWindows)
3058 ComputeClipWindows ();
3059 PPU.RecomputeClipWindows = FALSE;
3062 GFX.StartY = IPPU.PreviousLine;
3063 if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
3064 GFX.EndY = PPU.ScreenHeight - 1;
3066 uint32 starty = GFX.StartY;
3067 uint32 endy = GFX.EndY;
3069 #ifndef RC_OPTIMIZED
3070 if (Settings.SupportHiRes &&
3071 (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace))
3073 if (PPU.BGMode == 5 || PPU.BGMode == 6)
3075 IPPU.RenderedScreenWidth = 512;
3078 if (IPPU.LatchedInterlace)
3080 starty = GFX.StartY * 2;
3081 endy = GFX.EndY * 2 + 1;
3083 if (!IPPU.DoubleWidthPixels)
3085 // The game has switched from lo-res to hi-res mode part way down
3086 // the screen. Scale any existing lo-res pixels on screen
3088 if (Settings.SixteenBit)
3091 #if defined (USE_GLIDE) || defined (USE_OPENGL)
3094 (Settings.GlideEnable && GFX.Pitch == 512) ||
3097 (Settings.OpenGLEnable && GFX.Pitch == 512) ||
3101 // Have to back out of the speed up hack where the low res.
3102 // SNES image was rendered into a 256x239 sized buffer,
3103 // ignoring the true, larger size of the buffer.
3105 for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
3107 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3108 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.RealPitch) + 510;
3109 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3115 for (register uint32 y = 0; y < GFX.StartY; y++)
3117 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3118 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3119 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3126 for (register uint32 y = 0; y < GFX.StartY; y++)
3128 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3129 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3130 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3135 IPPU.DoubleWidthPixels = TRUE;
3138 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3140 uint32 black = BLACK | (BLACK << 16);
3142 // Are we worrying about transparencies?
3143 if (Settings.Transparency && Settings.SixteenBit)
3147 GFX.r2131 = 0x5f; //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3148 GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3149 Memory.FillRAM [0x212d]) & 15;
3150 GFX.r212c &= ~GFX.r212d; // make sure the main BG reg is the reverse of the sub BG reg
3151 GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3154 // Check to see if any transparency effects are currently in use
3155 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3156 (GFX.r2130 & 0x30) != 0x30 &&
3157 !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3159 // transparency effects in use, so lets get busy!
3160 struct ClipData *pClip;
3162 GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3163 IPPU.XB [PPU.FixedColourGreen],
3164 IPPU.XB [PPU.FixedColourBlue]);
3165 fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3166 // Clear the z-buffer, marking areas 'covered' by the fixed
3167 // colour as depth 1.
3168 pClip = &IPPU.Clip [1];
3170 // Clear the z-buffer
3172 if (pClip->Count [5])
3175 // Colour window enabled.
3178 for (uint32 y = starty; y <= endy; y++)
3181 ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3182 IPPU.RenderedScreenWidth);
3183 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3184 IPPU.RenderedScreenWidth);
3186 if (IPPU.Clip [0].Count [5])
3188 memset ((GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth);
3190 for (uint32 c = 0; c < pClip->Count [5]; c++)
3192 if (pClip->Right [c][5] > pClip->Left [c][5])
3194 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3195 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3196 if (IPPU.Clip [0].Count [5])
3198 // Blast, have to clear the sub-screen to the fixed-colour
3199 // because there is a colour window in effect clipping
3200 // the main screen that will allow the sub-screen
3201 // 'underneath' to show through.
3202 memset ((GFX.SubScreen + y * GFX.Pitch2) + pClip->Left [c][5] * x2,
3204 pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3210 #else // NOT RC_OPTIMIZED
3211 // loop around all of the lines being updated
3212 for (uint32 y = starty; y <= endy; y++)
3214 // Clear the subZbuffer
3215 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3216 IPPU.RenderedScreenWidth>>2);
3217 // Clear the Zbuffer
3218 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3219 IPPU.RenderedScreenWidth>>2);
3221 // if there is clipping then clear subscreen to a black color
3222 if (IPPU.Clip [0].Count [5])
3224 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth>>1);
3227 // loop through all window clippings
3228 for (uint32 c = 0; c < pClip->Count [5]; c++)
3230 if (pClip->Right [c][5] > pClip->Left [c][5])
3232 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3233 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3234 if (IPPU.Clip [0].Count [5])
3236 // Blast, have to clear the sub-screen to the fixed-colour
3237 // because there is a colour window in effect clipping
3238 // the main screen that will allow the sub-screen
3239 // 'underneath' to show through.
3241 register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch2);
3242 register uint16 *q = p + pClip->Right [c][5] * x2;
3243 p += pClip->Left [c][5] * x2;
3246 *p++ = (uint16) GFX.FixedColour;
3252 //#undef RC_OPTIMIZED
3257 // No windows are clipping the main screen
3258 // this simplifies the screen clearing process
3261 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3264 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3265 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3269 for (uint32 y = starty; y <= endy; y++)
3271 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3272 IPPU.RenderedScreenWidth);
3273 memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3274 IPPU.RenderedScreenWidth);
3278 if (IPPU.Clip [0].Count [5])
3280 // Blast, have to clear the sub-screen to the fixed-colour
3281 // because there is a colour window in effect clipping
3282 // the main screen that will allow the sub-screen
3283 // 'underneath' to show through.
3284 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3286 memset ((GFX.SubScreen + starty * GFX.Pitch2),
3287 GFX.FixedColour | (GFX.FixedColour << 16),
3288 GFX.Pitch2 * (endy - starty - 1));
3292 for (uint32 y = starty; y <= endy; y++)
3294 memset ((GFX.SubScreen + y * GFX.Pitch2),
3295 GFX.FixedColour | (GFX.FixedColour << 16),
3296 IPPU.RenderedScreenWidth);
3301 #else // NOT RC_OPTIMIZED
3302 // loop through all of the lines to be updated
3303 for (uint32 y = starty; y <= endy; y++)
3305 // Clear the Zbuffer
3306 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3307 IPPU.RenderedScreenWidth>>2);
3308 // clear the sub Zbuffer to 1
3309 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3310 IPPU.RenderedScreenWidth>>2);
3311 if (IPPU.Clip [0].Count [5])
3313 // Blast, have to clear the sub-screen to the fixed-colour
3314 // because there is a colour window in effect clipping
3315 // the main screen that will allow the sub-screen
3316 // 'underneath' to show through.
3319 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), fixedColour,
3320 IPPU.RenderedScreenWidth>>1);
3327 if (ANYTHING_ON_SUB)
3329 GFX.DB = GFX.SubZBuffer;
3330 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3333 if (IPPU.Clip [0].Count [5])
3335 for (uint32 y = starty; y <= endy; y++)
3337 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3338 register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3339 register uint8 *e = d + SNES_WIDTH;
3344 *p = *(p + GFX.Delta);
3353 GFX.DB = GFX.ZBuffer;
3354 RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3357 uint32 back = IPPU.ScreenColors [0];
3362 pClip = &IPPU.Clip [0];
3364 for (uint32 y = starty; y <= endy; y++)
3366 if (!(Count = pClip->Count [5]))
3373 for (uint32 b = 0; b < Count; b++)
3375 if (pClip->Count [5])
3377 Left = pClip->Left [b][5] * x2;
3378 Right = pClip->Right [b][5] * x2;
3383 if (GFX.r2131 & 0x80)
3385 if (GFX.r2131 & 0x40)
3387 // Subtract, halving the result.
3388 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3389 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3390 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3391 register uint8 *e = d + Right;
3392 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3402 *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3417 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3418 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3419 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3420 register uint8 *e = d + Right;
3421 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3431 *p = COLOR_SUB (back, *(p + GFX.Delta));
3445 if (GFX.r2131 & 0x40)
3447 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3448 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3449 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3450 register uint8 *e = d + Right;
3451 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3460 *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3475 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3476 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3477 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3478 register uint8 *e = d + Right;
3479 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3488 *p = COLOR_ADD (back, *(p + GFX.Delta));
3502 if (!pClip->Count [5])
3504 // The backdrop has not been cleared yet - so
3505 // copy the sub-screen to the main screen
3506 // or fill it with the back-drop colour if the
3507 // sub-screen is clear.
3508 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3509 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3510 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3511 register uint8 *e = d + Right;
3520 *p = *(p + GFX.Delta);
3522 *p = GFX.FixedColour;
3539 // Subscreen not being added to back
3540 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3541 pClip = &IPPU.Clip [0];
3543 if (pClip->Count [5])
3545 for (uint32 y = starty; y <= endy; y++)
3547 for (uint32 b = 0; b < pClip->Count [5]; b++)
3549 uint32 Left = pClip->Left [b][5] * x2;
3550 uint32 Right = pClip->Right [b][5] * x2;
3551 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3552 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3553 register uint8 *e = d + Right;
3567 for (uint32 y = starty; y <= endy; y++)
3569 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3570 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3571 register uint8 *e = d + 256 * x2;
3591 // 16bit and transparency but currently no transparency effects in
3594 // get the back colour of the current screen
3595 uint32 back = IPPU.ScreenColors [0] |
3596 (IPPU.ScreenColors [0] << 16);
3598 // if forceblanking in use then use black instead of the back color
3599 if (PPU.ForcedBlanking)
3602 // not sure what Clip is used for yet
3603 // could be a check to see if there is any clipping present?
3604 if (IPPU.Clip [0].Count[5])
3608 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3610 memset (GFX.Screen + starty * GFX.Pitch2, black,
3611 GFX.Pitch2 * (endy - starty - 1));
3615 for (uint32 y = starty; y <= endy; y++)
3617 memset (GFX.Screen + y * GFX.Pitch2, black,
3621 for (uint32 y = starty; y <= endy; y++)
3623 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3625 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3628 memset ((GFX.Screen + y * GFX.Pitch2) + IPPU.Clip [0].Left [c][5] * x2,
3630 IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3635 // loop through all of the lines that are going to be updated as part of this screen update
3636 for (uint32 y = starty; y <= endy; y++)
3638 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), black,
3639 IPPU.RenderedScreenWidth>>1);
3643 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3645 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3647 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2); // get pointer to current line in screen buffer
3648 register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3649 p += IPPU.Clip [0].Left [c][5] * x2;
3652 *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3662 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3664 memset (GFX.Screen + starty * GFX.Pitch2, back,
3665 GFX.Pitch2 * (endy - starty - 1));
3669 for (uint32 y = starty; y <= endy; y++)
3671 memset (GFX.Screen + y * GFX.Pitch2, back,
3676 // there is no clipping to worry about so just fill with the back colour
3677 for (uint32 y = starty; y <= endy; y++)
3679 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3680 IPPU.RenderedScreenWidth>>1);
3685 // If Forced blanking is not in effect
3686 if (!PPU.ForcedBlanking)
3689 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3691 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3692 GFX.ZPitch * (endy - starty - 1));
3696 for (uint32 y = starty; y <= endy; y++)
3698 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3703 // Clear the Zbuffer for each of the lines which are going to be updated
3704 for (uint32 y = starty; y <= endy; y++)
3706 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3710 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3711 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3715 else // Transparencys are disabled, ahh lovely ... nice and easy.
3718 if (Settings.SixteenBit)
3721 // get back colour to be used in clearing the screen
3722 register uint32 back;
3723 if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3724 (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3726 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3727 (IPPU.XB[PPU.FixedColourGreen] << 6) |
3728 (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3729 back = (back << 16) | back;
3733 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3736 // if Forcedblanking in use then back colour becomes black
3737 if (PPU.ForcedBlanking)
3741 SelectTileRenderer (TRUE); //selects the tile renderers to be used
3742 // TRUE means to use the default
3743 // FALSE means use best renderer based on current
3744 // graphics register settings
3747 // now clear all graphics lines which are being updated using the back colour
3748 for (register uint32 y = starty; y <= endy; y++)
3750 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3751 IPPU.RenderedScreenWidth>>1);
3755 else // Settings.SixteenBit == false
3757 // because we are in 8 bit we can just use 0 to clear the screen
3758 // this means we can use the Zero Memory function
3760 // Loop through all lines being updated and clear the pixels to 0
3761 for (uint32 y = starty; y <= endy; y++)
3763 ZeroMemory (GFX.Screen + y * GFX.Pitch2,
3764 IPPU.RenderedScreenWidth);
3768 if (!PPU.ForcedBlanking)
3770 // Loop through all lines being updated and clear the
3771 // zbuffer for each of the lines
3772 for (uint32 y = starty; y <= endy; y++)
3774 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3775 IPPU.RenderedScreenWidth>>2);
3777 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3778 GFX.pCurrentClip = &IPPU.Clip [0];
3780 // Define an inline function to handle clipping
3781 #define FIXCLIP(n) \
3782 if (GFX.r212c & (1 << (n))) \
3783 GFX.pCurrentClip = &IPPU.Clip [0]; \
3785 GFX.pCurrentClip = &IPPU.Clip [1]
3787 // Define an inline function to handle which BGs are being displayed
3788 #define DISPLAY(n) \
3790 (!(PPU.BG_Forced & n) && (GFX.r212c & n)) || \
3791 (((GFX.r212d & n) && subadd)) \
3794 uint8 subadd = GFX.r2131 & 0x3f;
3796 // go through all BGS are check if they need to be displayed
3797 bool BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3798 bool BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3799 bool BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3800 bool BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3801 bool OB = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3803 if (PPU.BGMode <= 1)
3805 // screen modes 0 and 1
3814 DrawBackground (PPU.BGMode, 0, 10, 14);
3819 DrawBackground (PPU.BGMode, 1, 9, 13);
3824 DrawBackground (PPU.BGMode, 2, 3,
3825 (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3827 if (BG3 && PPU.BGMode == 0)
3830 DrawBackground (PPU.BGMode, 3, 2, 5);
3833 else if (PPU.BGMode != 7)
3835 // screen modes 2 and up but not mode 7
3844 DrawBackground (PPU.BGMode, 0, 5, 13);
3846 if (BG1 && PPU.BGMode != 6)
3849 DrawBackground (PPU.BGMode, 1, 2, 9);
3860 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3864 if (Memory.FillRAM [0x2133] & 0x40)
3866 GFX.Mode7Mask = 0x7f;
3867 GFX.Mode7PriorityMask = 0x80;
3868 Mode7Depths [0] = 5;
3869 Mode7Depths [1] = 9;
3874 GFX.Mode7Mask = 0xff;
3875 GFX.Mode7PriorityMask = 0;
3876 Mode7Depths [0] = 5;
3877 Mode7Depths [1] = 5;
3882 if (!Settings.SixteenBit)
3883 DrawBGMode7Background (GFX.Screen, bg);
3887 if (!Settings.Mode7Interpolate)
3889 DrawBGMode7Background16 (GFX.Screen, bg);
3893 DrawBGMode7Background16_i (GFX.Screen, bg);
3900 #ifndef RC_OPTIMIZE // no hi res
3901 if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3903 if (IPPU.DoubleWidthPixels)
3905 // Mixure of background modes used on screen - scale width
3906 // of all non-mode 5 and 6 pixels.
3908 if (Settings.SixteenBit)
3911 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3913 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3914 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3915 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3922 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3924 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3925 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3926 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3933 if (IPPU.LatchedInterlace)
3935 // Interlace is enabled - double the height of all non-mode 5 and 6
3937 for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3939 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch2),
3940 (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch2),
3946 IPPU.PreviousLine = IPPU.CurrentLine;
3949 #ifdef GFX_MULTI_FORMAT
3951 #define _BUILD_PIXEL(F) \
3952 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
3954 return (BUILD_PIXEL_##F(R,G,B)); \
3956 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
3958 return (BUILD_PIXEL2_##F(R,G,B)); \
3960 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
3962 DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
3965 _BUILD_PIXEL(RGB565)
3966 _BUILD_PIXEL(RGB555)
3967 _BUILD_PIXEL(BGR565)
3968 _BUILD_PIXEL(BGR555)
3969 _BUILD_PIXEL(GBR565)
3970 _BUILD_PIXEL(GBR555)
3971 _BUILD_PIXEL(RGB5551)
3973 bool8_32 S9xSetRenderPixelFormat (int format)
3975 extern uint32 current_graphic_format;
3977 current_graphic_format = format;
3982 _BUILD_SETUP(RGB565)
3985 _BUILD_SETUP(RGB555)
3988 _BUILD_SETUP(BGR565)
3991 _BUILD_SETUP(BGR555)
3994 _BUILD_SETUP(GBR565)
3997 _BUILD_SETUP(GBR555)
4000 _BUILD_SETUP(RGB5551)