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.
51 //#include "asmmemfuncs.h"
57 extern void memcpy16(unsigned short *dest, unsigned short *src, int count);
58 extern void memcpy16bswap(unsigned short *dest, void *src, int count);
59 extern void memcpy32(uint32_t *dest, uint32_t *src, int count);
60 extern void memset32(uint32_t *dest, int c, int count);
68 void ComputeClipWindows ();
69 static void S9xDisplayFrameRate ();
70 static void S9xDisplayString (const char *string);
72 extern uint8 BitShifts[8][4];
73 extern uint8 TileShifts[8][4];
74 extern uint8 PaletteShifts[8][4];
75 extern uint8 PaletteMasks[8][4];
76 extern uint8 Depths[8][4];
77 extern uint8 BGSizes [2];
79 extern NormalTileRenderer DrawTilePtr;
80 extern ClippedTileRenderer DrawClippedTilePtr;
81 extern NormalTileRenderer DrawHiResTilePtr;
82 extern ClippedTileRenderer DrawHiResClippedTilePtr;
83 extern LargePixelRenderer DrawLargePixelPtr;
87 extern struct SLineData LineData[240];
88 extern struct SLineMatrixData LineMatrixData [240];
90 extern uint8 Mode7Depths [2];
93 (GFX.r212c & (1 << (N)) && \
94 !(PPU.BG_Forced & (1 << (N))))
96 #define SUB_OR_ADD(N) \
97 (GFX.r2131 & (1 << (N)))
100 ((GFX.r2130 & 0x30) != 0x30 && \
102 (GFX.r212d & (1 << N)) && \
103 !(PPU.BG_Forced & (1 << (N))))
105 #define ANYTHING_ON_SUB \
106 ((GFX.r2130 & 0x30) != 0x30 && \
110 #define ADD_OR_SUB_ON_ANYTHING \
113 #define BLACK BUILD_PIXEL(0,0,0)
115 void DrawTile (uint32 Tile, uint32 Offset, uint32 StartLine,
116 uint32 LineCount, struct SGFX * gfx);
117 void DrawClippedTile (uint32 Tile, uint32 Offset,
118 uint32 StartPixel, uint32 Width,
119 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
120 void DrawTilex2 (uint32 Tile, uint32 Offset, uint32 StartLine,
121 uint32 LineCount, struct SGFX * gfx);
122 void DrawClippedTilex2 (uint32 Tile, uint32 Offset,
123 uint32 StartPixel, uint32 Width,
124 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
125 void DrawTilex2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
126 uint32 LineCount, struct SGFX * gfx);
127 void DrawClippedTilex2x2 (uint32 Tile, uint32 Offset,
128 uint32 StartPixel, uint32 Width,
129 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
130 void DrawLargePixel (uint32 Tile, uint32 Offset,
131 uint32 StartPixel, uint32 Pixels,
132 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
134 void DrawTile16 (uint32 Tile, uint32 Offset, uint32 StartLine,
135 uint32 LineCount, struct SGFX * gfx);
136 void DrawClippedTile16 (uint32 Tile, uint32 Offset,
137 uint32 StartPixel, uint32 Width,
138 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
139 void DrawTile16x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
140 uint32 LineCount, struct SGFX * gfx);
141 void DrawClippedTile16x2 (uint32 Tile, uint32 Offset,
142 uint32 StartPixel, uint32 Width,
143 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
144 void DrawTile16x2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
145 uint32 LineCount, struct SGFX * gfx);
146 void DrawClippedTile16x2x2 (uint32 Tile, uint32 Offset,
147 uint32 StartPixel, uint32 Width,
148 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
149 void DrawLargePixel16 (uint32 Tile, uint32 Offset,
150 uint32 StartPixel, uint32 Pixels,
151 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
153 void DrawTile16Add (uint32 Tile, uint32 Offset, uint32 StartLine,
154 uint32 LineCount, struct SGFX * gfx);
156 void DrawClippedTile16Add (uint32 Tile, uint32 Offset,
157 uint32 StartPixel, uint32 Width,
158 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
160 void DrawTile16Add1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
161 uint32 LineCount, struct SGFX * gfx);
163 void DrawClippedTile16Add1_2 (uint32 Tile, uint32 Offset,
164 uint32 StartPixel, uint32 Width,
165 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
167 void DrawTile16FixedAdd1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
168 uint32 LineCount, struct SGFX * gfx);
170 void DrawClippedTile16FixedAdd1_2 (uint32 Tile, uint32 Offset,
171 uint32 StartPixel, uint32 Width,
172 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
174 void DrawTile16Sub (uint32 Tile, uint32 Offset, uint32 StartLine,
175 uint32 LineCount, struct SGFX * gfx);
177 void DrawClippedTile16Sub (uint32 Tile, uint32 Offset,
178 uint32 StartPixel, uint32 Width,
179 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
181 void DrawTile16Sub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
182 uint32 LineCount, struct SGFX * gfx);
184 void DrawClippedTile16Sub1_2 (uint32 Tile, uint32 Offset,
185 uint32 StartPixel, uint32 Width,
186 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
188 void DrawTile16FixedSub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
189 uint32 LineCount, struct SGFX * gfx);
191 void DrawClippedTile16FixedSub1_2 (uint32 Tile, uint32 Offset,
192 uint32 StartPixel, uint32 Width,
193 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
195 void DrawLargePixel16Add (uint32 Tile, uint32 Offset,
196 uint32 StartPixel, uint32 Pixels,
197 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
199 void DrawLargePixel16Add1_2 (uint32 Tile, uint32 Offset,
200 uint32 StartPixel, uint32 Pixels,
201 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
203 void DrawLargePixel16Sub (uint32 Tile, uint32 Offset,
204 uint32 StartPixel, uint32 Pixels,
205 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
207 void DrawLargePixel16Sub1_2 (uint32 Tile, uint32 Offset,
208 uint32 StartPixel, uint32 Pixels,
209 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
211 void DrawHiResClippedTile16 (uint32 Tile, uint32 Offset,
212 uint32 StartPixel, uint32 Width,
213 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
215 void DrawHiResTile16 (uint32 Tile, uint32 Offset,
216 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
218 bool8_32 S9xGraphicsInit ()
220 register uint32 PixelOdd = 1;
221 register uint32 PixelEven = 2;
223 #ifdef GFX_MULTI_FORMAT
224 if (GFX.BuildPixel == NULL)
225 S9xSetRenderPixelFormat (RGB565);
228 for (uint8 bitshift = 0; bitshift < 4; bitshift++)
230 for (register int i = 0; i < 16; i++)
232 register uint32 h = 0;
233 register uint32 l = 0;
235 #if defined(LSB_FIRST)
254 h |= (PixelOdd << 24);
256 h |= (PixelOdd << 16);
258 h |= (PixelOdd << 8);
262 l |= (PixelOdd << 24);
264 l |= (PixelOdd << 16);
266 l |= (PixelOdd << 8);
271 odd_high[bitshift][i] = h;
272 odd_low[bitshift][i] = l;
275 #if defined(LSB_FIRST)
281 h |= PixelEven << 16;
283 h |= PixelEven << 24;
289 l |= PixelEven << 16;
291 l |= PixelEven << 24;
294 h |= (PixelEven << 24);
296 h |= (PixelEven << 16);
298 h |= (PixelEven << 8);
302 l |= (PixelEven << 24);
304 l |= (PixelEven << 16);
306 l |= (PixelEven << 8);
311 even_high[bitshift][i] = h;
312 even_low[bitshift][i] = l;
318 GFX.RealPitch = GFX.Pitch2 = GFX.Pitch;
319 GFX.ZPitch = GFX.Pitch;
320 if (Settings.SixteenBit)
322 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
323 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
324 //GFX.InfoStringTimeout = 0;
325 //GFX.InfoString = NULL;
328 IPPU.OBJChanged = TRUE;
329 if (Settings.Transparency)
330 Settings.SixteenBit = TRUE;
332 IPPU.DirectColourMapsNeedRebuild = TRUE;
334 if (Settings.SixteenBit)
336 DrawTilePtr = DrawTile16;
337 DrawClippedTilePtr = DrawClippedTile16;
338 DrawLargePixelPtr = DrawLargePixel16;
339 DrawHiResTilePtr= DrawHiResTile16;
340 DrawHiResClippedTilePtr = DrawHiResClippedTile16;
341 GFX.PPL = GFX.Pitch >> 1;
342 GFX.PPLx2 = GFX.Pitch;
346 DrawTilePtr = DrawTile;
347 DrawClippedTilePtr = DrawClippedTile;
348 DrawLargePixelPtr = DrawLargePixel;
349 DrawHiResTilePtr = DrawTile;
350 DrawHiResClippedTilePtr = DrawClippedTile;
352 GFX.PPLx2 = GFX.Pitch * 2;
354 S9xFixColourBrightness ();
356 if (Settings.SixteenBit)
358 if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
361 if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
362 !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
366 free ((char *) GFX.ZERO_OR_X2);
367 GFX.ZERO_OR_X2 = NULL;
371 free ((char *) GFX.X2);
378 // Build a lookup table that multiplies a packed RGB value by 2 with
380 for (r = 0; r <= MAX_RED; r++)
385 for (g = 0; g <= MAX_GREEN; g++)
390 for (b = 0; b <= MAX_BLUE; b++)
395 GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
396 GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
400 ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
401 ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
402 // Build a lookup table that if the top bit of the color value is zero
403 // then the value is zero, otherwise multiply the value by 2. Used by
404 // the color subtraction code.
406 #if defined(OLD_COLOUR_BLENDING)
407 for (r = 0; r <= MAX_RED; r++)
410 if ((r2 & 0x10) == 0)
413 r2 = (r2 << 1) & MAX_RED;
415 for (g = 0; g <= MAX_GREEN; g++)
418 if ((g2 & GREEN_HI_BIT) == 0)
421 g2 = (g2 << 1) & MAX_GREEN;
423 for (b = 0; b <= MAX_BLUE; b++)
426 if ((b2 & 0x10) == 0)
429 b2 = (b2 << 1) & MAX_BLUE;
431 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
432 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
437 for (r = 0; r <= MAX_RED; r++)
440 if ((r2 & 0x10) == 0)
443 r2 = (r2 << 1) & MAX_RED;
447 for (g = 0; g <= MAX_GREEN; g++)
450 if ((g2 & GREEN_HI_BIT) == 0)
453 g2 = (g2 << 1) & MAX_GREEN;
457 for (b = 0; b <= MAX_BLUE; b++)
460 if ((b2 & 0x10) == 0)
463 b2 = (b2 << 1) & MAX_BLUE;
467 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
468 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
474 // Build a lookup table that if the top bit of the color value is zero
475 // then the value is zero, otherwise its just the value.
476 for (r = 0; r <= MAX_RED; r++)
479 if ((r2 & 0x10) == 0)
484 for (g = 0; g <= MAX_GREEN; g++)
487 if ((g2 & GREEN_HI_BIT) == 0)
491 for (b = 0; b <= MAX_BLUE; b++)
494 if ((b2 & 0x10) == 0)
499 GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
500 GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
508 GFX.ZERO_OR_X2 = NULL;
515 void S9xGraphicsDeinit (void)
517 // Free any memory allocated in S9xGraphicsInit
520 free ((char *) GFX.X2);
525 free ((char *) GFX.ZERO_OR_X2);
526 GFX.ZERO_OR_X2 = NULL;
530 free ((char *) GFX.ZERO);
535 void S9xBuildDirectColourMaps ()
537 for (uint32 p = 0; p < 8; p++)
539 for (uint32 c = 0; c < 256; c++)
542 DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
543 ((c & 0x38) >> 1) | (p & 2),
544 ((c & 0xc0) >> 3) | (p & 4));
547 IPPU.DirectColourMapsNeedRebuild = FALSE;
550 void S9xStartScreenRefresh ()
552 if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0)
553 GFX.InfoString = NULL;
555 if (IPPU.RenderThisFrame)
558 if (!S9xInitUpdate ())
560 IPPU.RenderThisFrame = FALSE;
564 IPPU.RenderedFramesCount++;
565 IPPU.PreviousLine = IPPU.CurrentLine = 0;
566 IPPU.MaxBrightness = PPU.Brightness;
567 IPPU.LatchedBlanking = PPU.ForcedBlanking;
568 IPPU.LatchedInterlace = (Memory.FillRAM[0x2133] & 1);
569 IPPU.RenderedScreenWidth = 256;
570 IPPU.RenderedScreenHeight = PPU.ScreenHeight;
571 IPPU.DoubleWidthPixels = FALSE;
572 GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
573 GFX.PPL = GFX.PPLx2 >> 1;
574 GFX.ZPitch = GFX.RealPitch;
575 if (Settings.SixteenBit)
577 PPU.RecomputeClipWindows = TRUE;
578 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
579 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
581 if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0)
583 IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount;
584 IPPU.RenderedFramesCount = 0;
589 void RenderLine (uint8 C)
591 if (IPPU.RenderThisFrame)
594 LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
595 LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
596 LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
597 LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
601 struct SLineMatrixData *p = &LineMatrixData [C];
602 p->MatrixA = PPU.MatrixA;
603 p->MatrixB = PPU.MatrixB;
604 p->MatrixC = PPU.MatrixC;
605 p->MatrixD = PPU.MatrixD;
606 p->CentreX = PPU.CentreX;
607 p->CentreY = PPU.CentreY;
612 if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
613 PPU.BG[2].HOffset == 0xe000)
615 LineData[C].BG[2].VOffset = 0xe1;
616 LineData[C].BG[2].HOffset = 0;
622 LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
623 LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
624 LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
625 LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
629 IPPU.CurrentLine = C + 1;
634 void S9xEndScreenRefresh()
636 IPPU.HDMAStarted = FALSE;
639 if (IPPU.RenderThisFrame)
642 if (IPPU.ColorsChanged)
644 uint32 saved = PPU.CGDATA[0];
645 if (!Settings.SixteenBit)
647 // Hack for Super Mario World - to get its sky blue
648 // (It uses Fixed colour addition on the backdrop colour)
649 if (!(Memory.FillRAM [0x2131] & 0x80) &&
650 (Memory.FillRAM[0x2131] & 0x20) &&
651 (PPU.FixedColourRed || PPU.FixedColourGreen ||
652 PPU.FixedColourBlue))
654 PPU.CGDATA[0] = PPU.FixedColourRed |
655 (PPU.FixedColourGreen << 5) |
656 (PPU.FixedColourBlue << 10);
659 IPPU.ColorsChanged = FALSE;
663 PPU.CGDATA[0] = saved;
665 GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
666 GFX.PPL = GFX.PPLx2 >> 1;
668 if (Settings.DisplayFrameRate)
669 S9xDisplayFrameRate ();
671 S9xDisplayString (GFX.InfoString);
673 S9xDeinitUpdate (IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
674 Settings.SixteenBit);
682 if (CPU.Flags & FRAME_ADVANCE_FLAG)
684 if (ICPU.FrameAdvanceCount)
686 ICPU.FrameAdvanceCount--;
687 IPPU.RenderThisFrame = TRUE;
692 CPU.Flags &= ~FRAME_ADVANCE_FLAG;
693 CPU.Flags |= DEBUG_MODE_FLAG;
698 if (CPU.SRAMModified)
700 if (!CPU.AutoSaveTimer)
702 if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
703 CPU.SRAMModified = FALSE;
707 if (!--CPU.AutoSaveTimer)
710 CPU.SRAMModified = FALSE;
716 void S9xSetInfoString (const char *string)
718 GFX.InfoString = string;
719 GFX.InfoStringTimeout = 120;
722 INLINE void SelectTileRenderer (bool8_32 normal)
726 DrawTilePtr = DrawTile16;
727 DrawClippedTilePtr = DrawClippedTile16;
728 DrawLargePixelPtr = DrawLargePixel16;
732 if (GFX.r2131 & 0x80)
734 if (GFX.r2131 & 0x40)
738 DrawTilePtr = DrawTile16Sub1_2;
739 DrawClippedTilePtr = DrawClippedTile16Sub1_2;
743 // Fixed colour substraction
744 DrawTilePtr = DrawTile16FixedSub1_2;
745 DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
747 DrawLargePixelPtr = DrawLargePixel16Sub1_2;
751 DrawTilePtr = DrawTile16Sub;
752 DrawClippedTilePtr = DrawClippedTile16Sub;
753 DrawLargePixelPtr = DrawLargePixel16Sub;
758 if (GFX.r2131 & 0x40)
762 DrawTilePtr = DrawTile16Add1_2;
763 DrawClippedTilePtr = DrawClippedTile16Add1_2;
767 // Fixed colour addition
768 DrawTilePtr = DrawTile16FixedAdd1_2;
769 DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
771 DrawLargePixelPtr = DrawLargePixel16Add1_2;
775 DrawTilePtr = DrawTile16Add;
776 DrawClippedTilePtr = DrawClippedTile16Add;
777 DrawLargePixelPtr = DrawLargePixel16Add;
788 switch (PPU.OBJSizeSelect)
819 int FirstSprite = PPU.FirstSprite & 0x7f;
824 if (PPU.OBJ [S].Size)
829 long VPos = PPU.OBJ [S].VPos;
831 if (VPos >= PPU.ScreenHeight)
833 if (PPU.OBJ [S].HPos < 256 && PPU.OBJ [S].HPos > -Size &&
834 VPos < PPU.ScreenHeight && VPos > -Size)
836 GFX.OBJList [C++] = S;
838 GFX.VPositions[S] = VPos;
841 } while (S != FirstSprite);
843 // Terminate the list
844 GFX.OBJList [C] = -1;
845 IPPU.OBJChanged = FALSE;
848 void DrawOBJS (bool8_32 OnMain = FALSE, uint8 D = 0)
851 uint32 BaseTile, Tile;
857 BG.TileAddress = PPU.OBJNameBase;
858 BG.StartPalette = 128;
861 BG.Buffer = IPPU.TileCache [TILE_4BIT];
862 BG.Buffered = IPPU.TileCached [TILE_4BIT];
863 BG.NameSelect = PPU.OBJNameSelect;
864 BG.DirectColourMode = FALSE;
871 for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
873 int VPos = GFX.VPositions [S];
874 int Size = GFX.Sizes[S];
878 if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
881 if (OnMain && SUB_OR_ADD(4))
883 SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
886 BaseTile = PPU.OBJ[S].Name | (PPU.OBJ[S].Palette << 10);
888 if (PPU.OBJ[S].HFlip)
890 BaseTile += ((Size >> 3) - 1) | H_FLIP;
893 if (PPU.OBJ[S].VFlip)
896 int clipcount = GFX.pCurrentClip->Count [4];
900 GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
902 for (int clip = 0; clip < clipcount; clip++)
906 if (!GFX.pCurrentClip->Count [4])
913 Left = GFX.pCurrentClip->Left [clip][4];
914 Right = GFX.pCurrentClip->Right [clip][4];
917 if (Right <= Left || PPU.OBJ[S].HPos + Size <= Left ||
918 PPU.OBJ[S].HPos >= Right)
921 for (int Y = 0; Y < Size; Y += 8)
923 if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
930 if ((StartLine = VPos + Y) < (int) GFX.StartY)
932 StartLine = GFX.StartY - StartLine;
933 LineCount = 8 - StartLine;
940 if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
941 if ((LineCount -= Last) <= 0)
944 TileLine = StartLine << 3;
945 O = (VPos + Y + StartLine) * GFX.PPL;
946 if (!PPU.OBJ[S].VFlip)
947 Tile = BaseTile + (Y << 1);
949 Tile = BaseTile + ((Size - Y - 8) << 1);
951 int Middle = Size >> 3;
952 if (PPU.OBJ[S].HPos < Left)
954 Tile += ((Left - PPU.OBJ[S].HPos) >> 3) * TileInc;
955 Middle -= (Left - PPU.OBJ[S].HPos) >> 3;
956 O += Left * GFX.PixSize;
957 if ((Offset = (Left - PPU.OBJ[S].HPos) & 7))
959 O -= Offset * GFX.PixSize;
961 int Width = Right - Left;
964 (*DrawClippedTilePtr) (Tile, O, Offset, W,
965 TileLine, LineCount, &GFX);
971 O += 8 * GFX.PixSize;
975 O += PPU.OBJ[S].HPos * GFX.PixSize;
977 if (PPU.OBJ[S].HPos + Size >= Right)
979 Middle -= ((PPU.OBJ[S].HPos + Size + 7) -
981 Offset = (Right - (PPU.OBJ[S].HPos + Size)) & 7;
986 for (int X = 0; X < Middle; X++, O += 8 * GFX.PixSize,
989 (*DrawTilePtr) (Tile, O, TileLine, LineCount, &GFX);
993 (*DrawClippedTilePtr) (Tile, O, 0, Offset,
994 TileLine, LineCount, &GFX);
1002 void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1011 uint8 depths [2] = {Z1, Z2};
1014 BG.StartPalette = bg << 5;
1016 BG.StartPalette = 0;
1018 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1020 if (PPU.BG[bg].SCSize & 1)
1025 if (PPU.BG[bg].SCSize & 2)
1030 if (PPU.BG[bg].SCSize & 1)
1039 if (BG.TileSize == 16)
1050 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1052 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1053 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1054 uint32 MosaicOffset = Y % PPU.Mosaic;
1056 for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
1057 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1058 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1061 uint32 MosaicLine = VOffset + Y - MosaicOffset;
1063 if (Y + Lines > GFX.EndY)
1064 Lines = GFX.EndY + 1 - Y;
1065 uint32 VirtAlign = (MosaicLine & 7) << 3;
1070 uint32 ScreenLine = MosaicLine >> OffsetShift;
1071 uint32 Rem16 = MosaicLine & 15;
1073 if (ScreenLine & 0x20)
1078 b1 += (ScreenLine & 0x1f) << 5;
1079 b2 += (ScreenLine & 0x1f) << 5;
1084 uint32 ClipCount = GFX.pCurrentClip->Count [bg];
1085 uint32 HPos = HOffset;
1086 uint32 PixWidth = PPU.Mosaic;
1091 for (uint32 clip = 0; clip < ClipCount; clip++)
1093 if (GFX.pCurrentClip->Count [bg])
1095 Left = GFX.pCurrentClip->Left [clip][bg];
1096 Right = GFX.pCurrentClip->Right [clip][bg];
1097 uint32 r = Left % PPU.Mosaic;
1098 HPos = HOffset + Left;
1099 PixWidth = PPU.Mosaic - r;
1101 uint32 s = Y * GFX.PPL + Left * GFX.PixSize;
1102 for (uint32 x = Left; x < Right; x += PixWidth,
1103 s += PixWidth * GFX.PixSize,
1104 HPos += PixWidth, PixWidth = PPU.Mosaic)
1106 uint32 Quot = (HPos & OffsetMask) >> 3;
1108 if (x + PixWidth >= Right)
1109 PixWidth = Right - x;
1111 if (BG.TileSize == 8)
1114 t = b2 + (Quot & 0x1f);
1121 t = b2 + ((Quot >> 1) & 0x1f);
1123 t = b1 + (Quot >> 1);
1126 Tile = READ_2BYTES (t);
1127 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1130 if (BG.TileSize != 8)
1134 // Horizontal flip, but what about vertical flip ?
1137 // Both horzontal & vertical flip
1140 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1142 VirtAlign, Lines, &GFX);
1146 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1148 VirtAlign, Lines, &GFX);
1153 // Horizontal flip only
1156 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1158 VirtAlign, Lines, &GFX);
1162 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1164 VirtAlign, Lines, &GFX);
1170 // No horizontal flip, but is there a vertical flip ?
1173 // Vertical flip only
1176 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1178 VirtAlign, Lines, &GFX);
1182 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1184 VirtAlign, Lines, &GFX);
1192 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1194 VirtAlign, Lines, &GFX);
1198 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1200 VirtAlign, Lines, &GFX);
1206 (*DrawLargePixelPtr) (Tile, s, HPos & 7, PixWidth,
1207 VirtAlign, Lines, &GFX);
1213 void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1227 int VOffsetOffset = BGMode == 4 ? 0 : 32;
1228 uint8 depths [2] = {Z1, Z2};
1230 BG.StartPalette = 0;
1232 BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
1234 if (PPU.BG[2].SCSize & 1)
1239 if (PPU.BG[2].SCSize & 2)
1244 if (PPU.BG[2].SCSize & 1)
1249 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1251 if (PPU.BG[bg].SCSize & 1)
1256 if (PPU.BG[bg].SCSize & 2)
1260 if (PPU.BG[bg].SCSize & 1)
1265 static const int Lines = 1;
1268 int OffsetEnableMask = 1 << (bg + 13);
1270 if (BG.TileSize == 16)
1281 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
1283 uint32 VOff = LineData [Y].BG[2].VOffset;
1284 uint32 HOff = LineData [Y].BG[2].HOffset;
1286 int ScreenLine = VOff >> 3;
1293 if (ScreenLine & 0x20)
1294 s1 = BPS2, s2 = BPS3;
1296 s1 = BPS0, s2 = BPS1;
1298 s1 += (ScreenLine & 0x1f) << 5;
1299 s2 += (ScreenLine & 0x1f) << 5;
1301 int clipcount = GFX.pCurrentClip->Count [bg];
1305 for (int clip = 0; clip < clipcount; clip++)
1310 if (!GFX.pCurrentClip->Count [bg])
1317 Left = GFX.pCurrentClip->Left [clip][bg];
1318 Right = GFX.pCurrentClip->Right [clip][bg];
1326 uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
1337 uint32 TotalCount = 0;
1338 uint32 MaxCount = 8;
1340 uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1341 bool8_32 left_hand_edge = (Left == 0);
1342 Width = Right - Left;
1345 MaxCount = 8 - (Left & 7);
1347 while (Left < Right)
1351 // The SNES offset-per-tile background mode has a
1352 // hardware limitation that the offsets cannot be set
1353 // for the tile at the left-hand edge of the screen.
1354 VOffset = LineData [Y].BG[bg].VOffset;
1355 HOffset = LineHOffset;
1356 left_hand_edge = FALSE;
1360 // All subsequent offset tile data is shifted left by one,
1361 // hence the - 1 below.
1362 Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
1365 s0 = s2 + (Quot2 & 0x1f);
1369 HCellOffset = READ_2BYTES (s0);
1373 VOffset = LineData [Y].BG[bg].VOffset;
1374 HOffset=LineHOffset;
1375 if ((HCellOffset & OffsetEnableMask))
1377 if (HCellOffset & 0x8000)
1378 VOffset = HCellOffset + 1;
1380 HOffset = HCellOffset;
1385 VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
1386 if ((VCellOffset & OffsetEnableMask))
1387 VOffset = VCellOffset + 1;
1389 VOffset = LineData [Y].BG[bg].VOffset;
1391 if ((HCellOffset & OffsetEnableMask))
1392 HOffset = (HCellOffset & ~7)|(LineHOffset&7);
1394 HOffset=LineHOffset;
1397 VirtAlign = ((Y + VOffset) & 7) << 3;
1398 ScreenLine = (VOffset + Y) >> OffsetShift;
1400 if (((VOffset + Y) & 15) > 7)
1411 if (ScreenLine & 0x20)
1416 b1 += (ScreenLine & 0x1f) << 5;
1417 b2 += (ScreenLine & 0x1f) << 5;
1419 HPos = (HOffset + Left) & OffsetMask;
1423 if (BG.TileSize == 8)
1426 t = b2 + (Quot & 0x1f);
1433 t = b2 + ((Quot >> 1) & 0x1f);
1435 t = b1 + (Quot >> 1);
1438 if (MaxCount + TotalCount > Width)
1439 MaxCount = Width - TotalCount;
1444 if (Count > MaxCount)
1447 s -= Offset * GFX.PixSize;
1448 Tile = READ_2BYTES(t);
1449 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1451 if (BG.TileSize == 8)
1452 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines, &GFX);
1455 if (!(Tile & (V_FLIP | H_FLIP)))
1457 // Normal, unflipped
1458 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1459 s, Offset, Count, VirtAlign, Lines, &GFX);
1467 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1468 s, Offset, Count, VirtAlign, Lines, &GFX);
1473 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1474 s, Offset, Count, VirtAlign, Lines, &GFX);
1480 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1481 s, Offset, Count, VirtAlign, Lines, &GFX);
1486 TotalCount += Count;
1487 s += (Offset + Count) * GFX.PixSize;
1494 void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
1498 GFX.Pitch = GFX.RealPitch;
1499 GFX.PPL = GFX.PPLx2 >> 1;
1501 uint8 depths [2] = {Z1, Z2};
1510 BG.StartPalette = 0;
1512 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1514 if ((PPU.BG[bg].SCSize & 1))
1519 if ((PPU.BG[bg].SCSize & 2))
1524 if ((PPU.BG[bg].SCSize & 1))
1533 if (BG.TileSize == 16)
1535 VOffsetMask = 0x3ff;
1540 VOffsetMask = 0x1ff;
1543 int endy = GFX.EndY;
1545 for (int Y = GFX.StartY; Y <= endy; Y += Lines)
1548 uint32 VOffset = LineData [y].BG[bg].VOffset;
1549 uint32 HOffset = LineData [y].BG[bg].HOffset;
1550 int VirtAlign = (Y + VOffset) & 7;
1552 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1553 if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
1554 (HOffset != LineData [y + Lines].BG[bg].HOffset))
1558 if (Y + Lines > endy)
1559 Lines = endy + 1 - Y;
1561 int ScreenLine = (VOffset + Y) >> VOffsetShift;
1564 if (((VOffset + Y) & 15) > 7)
1577 if (ScreenLine & 0x20)
1582 b1 += (ScreenLine & 0x1f) << 5;
1583 b2 += (ScreenLine & 0x1f) << 5;
1585 int clipcount = GFX.pCurrentClip->Count [bg];
1588 for (int clip = 0; clip < clipcount; clip++)
1593 if (!GFX.pCurrentClip->Count [bg])
1600 Left = GFX.pCurrentClip->Left [clip][bg] * 2;
1601 Right = GFX.pCurrentClip->Right [clip][bg] * 2;
1607 uint32 s = (Left>>1) * GFX.PixSize + Y * GFX.PPL;
1608 uint32 HPos = (HOffset + Left * GFX.PixSize) & 0x3ff;
1610 uint32 Quot = HPos >> 3;
1615 t = b2 + ((Quot >> 1) & 0x1f);
1617 t = b1 + (Quot >> 1);
1619 Width = Right - Left;
1620 // Left hand edge clipped tile
1623 int Offset = (HPos & 7);
1628 Tile = READ_2BYTES (t);
1629 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1631 if (BG.TileSize == 8)
1633 if (!(Tile & H_FLIP))
1635 // Normal, unflipped
1636 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1637 s, Offset, Count, VirtAlign, Lines, &GFX);
1642 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1643 s, Offset, Count, VirtAlign, Lines, &GFX);
1648 if (!(Tile & (V_FLIP | H_FLIP)))
1650 // Normal, unflipped
1651 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1652 s, Offset, Count, VirtAlign, Lines, &GFX);
1660 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1661 s, Offset, Count, VirtAlign, Lines, &GFX);
1666 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1667 s, Offset, Count, VirtAlign, Lines, &GFX);
1673 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1674 s, Offset, Count, VirtAlign, Lines, &GFX);
1681 else if (Quot == 127)
1687 // Middle, unclipped tiles
1688 Count = Width - Count;
1689 int Middle = Count >> 3;
1691 for (int C = Middle; C > 0; s += 4, Quot++, C--)
1693 Tile = READ_2BYTES(t);
1694 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1695 if (BG.TileSize == 8)
1697 if (!(Tile & H_FLIP))
1699 // Normal, unflipped
1700 (*DrawHiResTilePtr) (Tile + (Quot & 1),
1701 s, VirtAlign, Lines, &GFX);
1706 (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1707 s, VirtAlign, Lines, &GFX);
1712 if (!(Tile & (V_FLIP | H_FLIP)))
1714 // Normal, unflipped
1715 (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1716 s, VirtAlign, Lines, &GFX);
1724 (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1725 s, VirtAlign, Lines, &GFX);
1730 (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1731 s, VirtAlign, Lines, &GFX);
1737 (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1738 s, VirtAlign, Lines, &GFX);
1750 // Right-hand edge clipped tiles
1753 Tile = READ_2BYTES(t);
1754 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1755 if (BG.TileSize == 8)
1757 if (!(Tile & H_FLIP))
1759 // Normal, unflipped
1760 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1761 s, 0, Count, VirtAlign, Lines, &GFX);
1766 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1767 s, 0, Count, VirtAlign, Lines, &GFX);
1772 if (!(Tile & (V_FLIP | H_FLIP)))
1774 // Normal, unflipped
1775 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1776 s, 0, Count, VirtAlign, Lines, &GFX);
1784 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1785 s, 0, Count, VirtAlign, Lines, &GFX);
1790 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1791 s, 0, Count, VirtAlign, Lines, &GFX);
1797 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1798 s, 0, Count, VirtAlign, Lines, &GFX);
1806 void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1810 BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1811 BG.BitShift = BitShifts[BGMode][bg];
1812 BG.TileShift = TileShifts[BGMode][bg];
1813 BG.TileAddress = PPU.BG[bg].NameBase << 1;
1815 BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1816 BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1817 BG.PaletteShift = PaletteShifts[BGMode][bg];
1818 BG.PaletteMask = PaletteMasks[BGMode][bg];
1819 BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1822 if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1824 DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1831 if (Settings.WrestlemaniaArcade)
1833 case 4: // Used by Puzzle Bobble
1834 DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1838 case 6: // XXX: is also offset per tile.
1839 DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1855 uint8 depths [2] = {Z1, Z2};
1858 BG.StartPalette = bg << 5;
1860 BG.StartPalette = 0;
1862 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1864 if (PPU.BG[bg].SCSize & 1)
1869 if (PPU.BG[bg].SCSize & 2)
1874 if (PPU.BG[bg].SCSize & 1)
1883 if (BG.TileSize == 16)
1894 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1896 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1897 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1898 int VirtAlign = (Y + VOffset) & 7;
1900 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1901 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1902 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1905 if (Y + Lines > GFX.EndY)
1906 Lines = GFX.EndY + 1 - Y;
1910 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1913 if (((VOffset + Y) & 15) > 7)
1926 if (ScreenLine & 0x20)
1931 b1 += (ScreenLine & 0x1f) << 5;
1932 b2 += (ScreenLine & 0x1f) << 5;
1934 int clipcount = GFX.pCurrentClip->Count [bg];
1937 for (int clip = 0; clip < clipcount; clip++)
1942 if (!GFX.pCurrentClip->Count [bg])
1949 Left = GFX.pCurrentClip->Left [clip][bg];
1950 Right = GFX.pCurrentClip->Right [clip][bg];
1956 uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1957 uint32 HPos = (HOffset + Left) & OffsetMask;
1959 uint32 Quot = HPos >> 3;
1963 if (BG.TileSize == 8)
1966 t = b2 + (Quot & 0x1f);
1973 t = b2 + ((Quot >> 1) & 0x1f);
1975 t = b1 + (Quot >> 1);
1978 Width = Right - Left;
1979 // Left hand edge clipped tile
1982 uint32 Offset = (HPos & 7);
1986 s -= Offset * GFX.PixSize;
1987 Tile = READ_2BYTES(t);
1988 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1990 if (BG.TileSize == 8)
1992 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1997 if (!(Tile & (V_FLIP | H_FLIP)))
1999 // Normal, unflipped
2000 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
2001 s, Offset, Count, VirtAlign, Lines, &GFX);
2009 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2010 s, Offset, Count, VirtAlign, Lines, &GFX);
2015 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2016 s, Offset, Count, VirtAlign, Lines, &GFX);
2022 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
2023 Offset, Count, VirtAlign, Lines, &GFX);
2027 if (BG.TileSize == 8)
2032 else if (Quot == 63)
2040 else if (Quot == 127)
2044 s += 8 * GFX.PixSize;
2047 // Middle, unclipped tiles
2048 Count = Width - Count;
2049 int Middle = Count >> 3;
2051 for (int C = Middle; C > 0; s += 8 * GFX.PixSize, Quot++, C--)
2053 Tile = READ_2BYTES(t);
2054 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
2056 if (BG.TileSize != 8)
2060 // Horizontal flip, but what about vertical flip ?
2063 // Both horzontal & vertical flip
2064 (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
2065 VirtAlign, Lines, &GFX);
2069 // Horizontal flip only
2070 (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
2071 VirtAlign, Lines, &GFX);
2076 // No horizontal flip, but is there a vertical flip ?
2079 // Vertical flip only
2080 (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
2081 VirtAlign, Lines, &GFX);
2086 (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
2087 VirtAlign, Lines, &GFX);
2093 (*DrawTilePtr) (Tile, s, VirtAlign, Lines, &GFX);
2096 if (BG.TileSize == 8)
2115 // Right-hand edge clipped tiles
2118 Tile = READ_2BYTES(t);
2119 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
2121 if (BG.TileSize == 8)
2122 (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
2126 if (!(Tile & (V_FLIP | H_FLIP)))
2128 // Normal, unflipped
2129 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
2130 Count, VirtAlign, Lines, &GFX);
2138 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2139 s, 0, Count, VirtAlign,
2145 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2146 s, 0, Count, VirtAlign,
2153 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
2154 s, 0, Count, VirtAlign,
2163 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2166 uint8 *VRAM1 = Memory.VRAM + 1; \
2167 if (GFX.r2130 & 1) \
2169 if (IPPU.DirectColourMapsNeedRebuild) \
2170 S9xBuildDirectColourMaps (); \
2171 GFX.ScreenColors = DirectColourMaps [0]; \
2174 GFX.ScreenColors = IPPU.ScreenColors; \
2180 uint32 Right = 256; \
2181 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2186 Screen += GFX.StartY * GFX.Pitch; \
2187 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2188 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2190 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2194 int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2195 int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2197 int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2198 int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2200 if (PPU.Mode7VFlip) \
2201 yy = 261 - (int) Line; \
2205 if (PPU.Mode7Repeat == 0) \
2206 yy += (VOffset - CentreY) % 1023; \
2208 yy += VOffset - CentreY; \
2209 int BB = l->MatrixB * yy + (CentreX << 8); \
2210 int DD = l->MatrixD * yy + (CentreY << 8); \
2212 for (uint32 clip = 0; clip < ClipCount; clip++) \
2214 if (GFX.pCurrentClip->Count [bg]) \
2216 Left = GFX.pCurrentClip->Left [clip][bg]; \
2217 Right = GFX.pCurrentClip->Right [clip][bg]; \
2218 if (Right <= Left) \
2221 TYPE *p = (TYPE *) Screen + Left; \
2222 uint8 *d = Depth + Left; \
2224 if (PPU.Mode7HFlip) \
2226 startx = Right - 1; \
2241 if (PPU.Mode7Repeat == 0) \
2242 xx = startx + (HOffset - CentreX) % 1023; \
2244 xx = startx + HOffset - CentreX; \
2245 int AA = l->MatrixA * xx; \
2246 int CC = l->MatrixC * xx; \
2248 if (!PPU.Mode7Repeat) \
2250 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2252 int X = ((AA + BB) >> 8) & 0x3ff; \
2253 int Y = ((CC + DD) >> 8) & 0x3ff; \
2254 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2255 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2256 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2257 if (GFX.Z1 > *d && b) \
2266 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2268 int X = ((AA + BB) >> 8); \
2269 int Y = ((CC + DD) >> 8); \
2271 if (Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2277 if (((X | Y) & ~0x3ff) == 0) \
2279 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2280 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2281 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2282 if (GFX.Z1 > *d && b) \
2290 if (PPU.Mode7Repeat == 3) \
2292 X = (x + HOffset) & 7; \
2293 Y = (yy + CentreY) & 7; \
2294 uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2295 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2296 if (GFX.Z1 > *d && b) \
2308 void DrawBGMode7Background (uint8 *Screen, int bg)
2310 RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & GFX.Mode7Mask))
2313 void DrawBGMode7Background16 (uint8 *Screen, int bg)
2315 RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & GFX.Mode7Mask]);
2318 void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2320 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2321 (*(d + GFX.DepthDelta) != 1 ?
2322 COLOR_ADD (GFX.ScreenColors [b & GFX.Mode7Mask],
2324 COLOR_ADD (GFX.ScreenColors [b & GFX.Mode7Mask],
2326 GFX.ScreenColors [b & GFX.Mode7Mask]);
2329 void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2331 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2332 (*(d + GFX.DepthDelta) != 1 ?
2333 COLOR_ADD1_2 (GFX.ScreenColors [b & GFX.Mode7Mask],
2335 COLOR_ADD (GFX.ScreenColors [b & GFX.Mode7Mask],
2337 GFX.ScreenColors [b & GFX.Mode7Mask]);
2340 void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2342 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2343 (*(d + GFX.DepthDelta) != 1 ?
2344 COLOR_SUB (GFX.ScreenColors [b & GFX.Mode7Mask],
2346 COLOR_SUB (GFX.ScreenColors [b & GFX.Mode7Mask],
2348 GFX.ScreenColors [b & GFX.Mode7Mask]);
2351 void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2353 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2354 (*(d + GFX.DepthDelta) != 1 ?
2355 COLOR_SUB1_2 (GFX.ScreenColors [b & GFX.Mode7Mask],
2357 COLOR_SUB (GFX.ScreenColors [b & GFX.Mode7Mask],
2359 GFX.ScreenColors [b & GFX.Mode7Mask]);
2362 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2365 uint8 *VRAM1 = Memory.VRAM + 1; \
2366 if (GFX.r2130 & 1) \
2368 if (IPPU.DirectColourMapsNeedRebuild) \
2369 S9xBuildDirectColourMaps (); \
2370 GFX.ScreenColors = DirectColourMaps [0]; \
2373 GFX.ScreenColors = IPPU.ScreenColors; \
2379 uint32 Right = 256; \
2380 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2385 Screen += GFX.StartY * GFX.Pitch; \
2386 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2387 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2388 bool8_32 allowSimpleCase = FALSE; \
2389 if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2390 && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2391 && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2393 allowSimpleCase = TRUE; \
2395 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2399 int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2400 int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2402 int CentreX = ((int) l->CentreX << M7) >> M7; \
2403 int CentreY = ((int) l->CentreY << M7) >> M7; \
2405 if (PPU.Mode7VFlip) \
2406 yy = 261 - (int) Line; \
2410 if (PPU.Mode7Repeat == 0) \
2411 yy += (VOffset - CentreY) % 1023; \
2413 yy += VOffset - CentreY; \
2414 bool8_32 simpleCase = FALSE; \
2417 /* Make a special case for the identity matrix, since it's a common case and */ \
2418 /* can be done much more quickly without special effects */ \
2419 if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2421 BB = CentreX << 8; \
2422 DD = (yy + CentreY) << 8; \
2423 simpleCase = TRUE; \
2427 BB = l->MatrixB * yy + (CentreX << 8); \
2428 DD = l->MatrixD * yy + (CentreY << 8); \
2431 for (uint32 clip = 0; clip < ClipCount; clip++) \
2433 if (GFX.pCurrentClip->Count [bg]) \
2435 Left = GFX.pCurrentClip->Left [clip][bg]; \
2436 Right = GFX.pCurrentClip->Right [clip][bg]; \
2437 if (Right <= Left) \
2440 TYPE *p = (TYPE *) Screen + Left; \
2441 uint8 *d = Depth + Left; \
2443 if (PPU.Mode7HFlip) \
2445 startx = Right - 1; \
2460 if (PPU.Mode7Repeat == 0) \
2461 xx = startx + (HOffset - CentreX) % 1023; \
2463 xx = startx + HOffset - CentreX; \
2471 AA = l->MatrixA * xx; \
2472 CC = l->MatrixC * xx; \
2476 if (!PPU.Mode7Repeat) \
2481 int X = ((AA + BB) >> 8) & 0x3ff; \
2482 int Y = (DD >> 8) & 0x3ff; \
2483 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2484 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2485 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2486 if (GFX.Z1 > *d && b) \
2488 TYPE theColor = COLORFUNC; \
2489 *p = (FUNC) | ALPHA_BITS_MASK; \
2492 AA += aa, p++, d++; \
2494 } while (x != endx); \
2500 int X = (AA + BB) >> 8; \
2503 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2509 if (((X | Y) & ~0x3ff) == 0) \
2511 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2512 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2513 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2514 if (GFX.Z1 > *d && b) \
2516 TYPE theColor = COLORFUNC; \
2517 *p = (FUNC) | ALPHA_BITS_MASK; \
2521 else if (PPU.Mode7Repeat == 3) \
2523 X = (x + HOffset) & 7; \
2524 Y = (yy + CentreY) & 7; \
2525 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2526 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2527 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2528 if (GFX.Z1 > *d && b) \
2530 TYPE theColor = COLORFUNC; \
2531 *p = (FUNC) | ALPHA_BITS_MASK; \
2535 AA += aa; p++; d++; \
2537 } while (x != endx); \
2540 else if (!PPU.Mode7Repeat) \
2542 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2543 /* the location of one point in the _sampled_ image, and weight them according */ \
2544 /* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
2547 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2548 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2549 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2550 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2551 /* You can think of this as a kind of mipmapping. */ \
2552 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2554 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2556 uint32 xPos = AA + BB; \
2557 uint32 xPix = xPos >> 8; \
2558 uint32 yPos = CC + DD; \
2559 uint32 yPix = yPos >> 8; \
2560 uint32 X = xPix & 0x3ff; \
2561 uint32 Y = yPix & 0x3ff; \
2562 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2563 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2564 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2565 if (GFX.Z1 > *d && b) \
2567 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2568 uint32 X10 = (xPix + dir) & 0x3ff; \
2569 uint32 Y01 = (yPix + dir) & 0x3ff; \
2570 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2571 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2572 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2573 uint32 p1 = COLORFUNC; \
2574 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2575 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2576 uint32 p2 = COLORFUNC; \
2577 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2578 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2579 uint32 p4 = COLORFUNC; \
2580 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2581 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2582 uint32 p3 = COLORFUNC; \
2583 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2584 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2585 uint32 Xdel = (xPos >> 3) & 0x1F; \
2586 uint32 Ydel = (yPos >> 3) & 0x1F; \
2587 uint32 XY = (Xdel*Ydel) >> 5; \
2588 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2589 uint32 area2 = Xdel - XY; \
2590 uint32 area3 = Ydel - XY; \
2591 uint32 area4 = XY; \
2592 uint32 tempColor = ((area1 * p1) + \
2595 (area4 * p4)) >> 5; \
2596 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2597 *p = (FUNC) | ALPHA_BITS_MASK; \
2603 /* The oversampling method: get the colors at four corners of a square */ \
2604 /* in the _displayed_ image, and average them. It's sharp and clean, but */ \
2605 /* gives the usual huge pixels when the source image gets "close." */ \
2607 /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2608 uint32 aaDelX = aa >> 1; \
2609 uint32 ccDelX = cc >> 1; \
2610 uint32 bbDelY = l->MatrixB >> 1; \
2611 uint32 ddDelY = l->MatrixD >> 1; \
2612 /* Offset the location within the source image so that the four sampled points */ \
2613 /* center around where the single point would otherwise have been drawn. */ \
2614 BB -= (bbDelY >> 1); \
2615 DD -= (ddDelY >> 1); \
2616 AA -= (aaDelX >> 1); \
2617 CC -= (ccDelX >> 1); \
2618 uint32 BB10 = BB + aaDelX; \
2619 uint32 BB01 = BB + bbDelY; \
2620 uint32 BB11 = BB + aaDelX + bbDelY; \
2621 uint32 DD10 = DD + ccDelX; \
2622 uint32 DD01 = DD + ddDelY; \
2623 uint32 DD11 = DD + ccDelX + ddDelY; \
2624 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2626 uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2627 uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2628 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2629 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2630 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2631 if (GFX.Z1 > *d && b) \
2633 /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2634 /* source image that we're going to examine. */ \
2635 uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2636 uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2637 uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2638 uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2639 uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2640 uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2641 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2642 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2643 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2644 TYPE p1 = COLORFUNC; \
2645 b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2646 TYPE p2 = COLORFUNC; \
2647 b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2648 TYPE p3 = COLORFUNC; \
2649 b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2650 TYPE p4 = COLORFUNC; \
2651 TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2652 *p = (FUNC) | ALPHA_BITS_MASK; \
2660 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2662 uint32 xPos = AA + BB; \
2663 uint32 xPix = xPos >> 8; \
2664 uint32 yPos = CC + DD; \
2665 uint32 yPix = yPos >> 8; \
2670 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2676 if (((X | Y) & ~0x3ff) == 0) \
2678 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2679 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2680 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2681 if (GFX.Z1 > *d && b) \
2683 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2684 uint32 X10 = (xPix + dir) & 0x3ff; \
2685 uint32 Y01 = (yPix + dir) & 0x3ff; \
2686 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2687 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2688 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2689 uint32 p1 = COLORFUNC; \
2690 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2691 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2692 uint32 p2 = COLORFUNC; \
2693 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2694 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2695 uint32 p4 = COLORFUNC; \
2696 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2697 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2698 uint32 p3 = COLORFUNC; \
2699 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2700 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2701 uint32 Xdel = (xPos >> 3) & 0x1F; \
2702 uint32 Ydel = (yPos >> 3) & 0x1F; \
2703 uint32 XY = (Xdel*Ydel) >> 5; \
2704 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2705 uint32 area2 = Xdel - XY; \
2706 uint32 area3 = Ydel - XY; \
2707 uint32 area4 = XY; \
2708 uint32 tempColor = ((area1 * p1) + \
2711 (area4 * p4)) >> 5; \
2712 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2713 *p = (FUNC) | ALPHA_BITS_MASK; \
2719 if (PPU.Mode7Repeat == 3) \
2721 X = (x + HOffset) & 7; \
2722 Y = (yy + CentreY) & 7; \
2723 uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2724 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2725 if (GFX.Z1 > *d && b) \
2727 TYPE theColor = COLORFUNC; \
2728 *p = (FUNC) | ALPHA_BITS_MASK; \
2738 STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2740 register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2741 ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2742 ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2743 ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2744 register uint32 y = (A & TWO_LOW_BITS_MASK) +
2745 (B & TWO_LOW_BITS_MASK) +
2746 (C & TWO_LOW_BITS_MASK) +
2747 (D & TWO_LOW_BITS_MASK);
2748 y = (y>>2) & TWO_LOW_BITS_MASK;
2752 void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2754 RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2757 void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2759 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2760 (*(d + GFX.DepthDelta) != 1 ?
2761 (COLOR_ADD (theColor,
2763 (COLOR_ADD (theColor,
2764 GFX.FixedColour))) :
2765 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2768 void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2770 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2771 (*(d + GFX.DepthDelta) != 1 ?
2772 COLOR_ADD1_2 (theColor,
2774 COLOR_ADD (theColor,
2776 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2779 void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2781 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2782 (*(d + GFX.DepthDelta) != 1 ?
2783 COLOR_SUB (theColor,
2785 COLOR_SUB (theColor,
2787 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2790 void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2792 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2793 (*(d + GFX.DepthDelta) != 1 ?
2794 COLOR_SUB1_2 (theColor,
2796 COLOR_SUB (theColor,
2798 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2801 #define _BUILD_SETUP(F) \
2802 GFX.BuildPixel = BuildPixel##F; \
2803 GFX.BuildPixel2 = BuildPixel2##F; \
2804 GFX.DecomposePixel = DecomposePixel##F; \
2805 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2806 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2807 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2808 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2809 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2810 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2811 MAX_RED = MAX_RED_##F; \
2812 MAX_GREEN = MAX_GREEN_##F; \
2813 MAX_BLUE = MAX_BLUE_##F; \
2814 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2815 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2816 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2817 GREEN_LOW_BIT_MASK_##F | \
2818 BLUE_LOW_BIT_MASK_##F); \
2819 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2820 GREEN_HI_BIT_MASK_##F | \
2821 BLUE_HI_BIT_MASK_##F); \
2822 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2823 GREEN_HI_BIT_MASK_##F | \
2824 BLUE_HI_BIT_MASK_##F) << 1); \
2825 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2826 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2827 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2828 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2829 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2830 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2831 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2832 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2833 ~TWO_LOW_BITS_MASK ) >> 2);
2835 void RenderScreen (uint8 *Screen, bool8_32 sub, bool8_32 force_no_add, uint8 D)
2847 GFX.pCurrentClip = &IPPU.Clip [0];
2848 BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2849 BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2850 BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2851 BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2852 OB = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2856 GFX.pCurrentClip = &IPPU.Clip [1];
2857 BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2858 BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2859 BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2860 BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2861 OB = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2864 sub |= force_no_add;
2866 if (PPU.BGMode <= 1)
2870 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2875 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2876 DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2880 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2881 DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2885 SelectTileRenderer (sub || !SUB_OR_ADD(2));
2886 DrawBackground (PPU.BGMode, 2, D + 3,
2887 (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2889 if (BG3 && PPU.BGMode == 0)
2891 SelectTileRenderer (sub || !SUB_OR_ADD(3));
2892 DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2895 else if (PPU.BGMode != 7)
2899 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2904 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2905 DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2907 if (PPU.BGMode != 6 && BG1)
2909 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2910 DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2917 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2920 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2924 if (Memory.FillRAM [0x2133] & 0x40)
2926 GFX.Mode7Mask = 0x7f;
2927 GFX.Mode7PriorityMask = 0x80;
2928 Mode7Depths [0] = 5 + D;
2929 Mode7Depths [1] = 9 + D;
2934 GFX.Mode7Mask = 0xff;
2935 GFX.Mode7PriorityMask = 0;
2936 Mode7Depths [0] = 5 + D;
2937 Mode7Depths [1] = 5 + D;
2940 if (sub || !SUB_OR_ADD(0))
2942 if (!Settings.Mode7Interpolate)
2943 DrawBGMode7Background16 (Screen, bg);
2945 DrawBGMode7Background16_i (Screen, bg);
2949 if (GFX.r2131 & 0x80)
2951 if (GFX.r2131 & 0x40)
2953 if (!Settings.Mode7Interpolate)
2954 DrawBGMode7Background16Sub1_2 (Screen, bg);
2956 DrawBGMode7Background16Sub1_2_i (Screen, bg);
2960 if (!Settings.Mode7Interpolate)
2961 DrawBGMode7Background16Sub (Screen, bg);
2963 DrawBGMode7Background16Sub_i (Screen, bg);
2968 if (GFX.r2131 & 0x40)
2970 if (!Settings.Mode7Interpolate)
2971 DrawBGMode7Background16Add1_2 (Screen, bg);
2973 DrawBGMode7Background16Add1_2_i (Screen, bg);
2977 if (!Settings.Mode7Interpolate)
2978 DrawBGMode7Background16Add (Screen, bg);
2980 DrawBGMode7Background16Add_i (Screen, bg);
2990 void DisplayChar (uint8 *Screen, uint8 c)
2992 int line = (((c & 0x7f) - 32) >> 4) * font_height;
2993 int offset = (((c & 0x7f) - 32) & 15) * font_width;
2995 if (Settings.SixteenBit)
2999 uint16 *s = (uint16 *) Screen;
3000 for (h = 0; h < font_height; h++, line++,
3001 s += GFX.PPL - font_width)
3003 for (w = 0; w < font_width; w++, s++)
3005 uint8 p = font [line][offset + w];
3020 for (h = 0; h < font_height; h++, line++,
3021 s += GFX.PPL - font_width)
3023 for (w = 0; w < font_width; w++, s++)
3025 uint8 p = font [line][offset + w];
3038 static void S9xDisplayFrameRate ()
3040 uint8 *Screen = GFX.Screen + 2 +
3041 (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch2;
3045 sprintf (string, "%02d/%02d", IPPU.DisplayedRenderedFrameCount,
3046 (int) Memory.ROMFramesPerSecond);
3050 Screen += (font_width - 1) * sizeof(uint16);
3052 for (i = 0; i < len; i++)
3054 DisplayChar (Screen, string [i]);
3055 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
3060 static void S9xDisplayString (const char *string)
3062 uint8 *Screen = GFX.Screen + 2 +
3063 (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch2;
3064 int len = strlen (string);
3065 int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
3069 for (i = 0; i < len; i++, char_count++)
3071 if (char_count >= max_chars || string [i] < 32)
3073 Screen -= Settings.SixteenBit ?
3074 (font_width - 1) * sizeof (uint16) * max_chars :
3075 (font_width - 1) * max_chars;
3076 Screen += font_height * GFX.Pitch;
3077 if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
3079 char_count -= max_chars;
3081 if (string [i] < 32)
3083 DisplayChar (Screen, string [i]);
3084 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
3089 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
3095 unsigned char *memoryfillram = Memory.FillRAM;
3097 // get local copies of vid registers to be used later
3098 GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN
3099 GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
3100 GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
3101 GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
3103 // If external sync is off and
3104 // main screens have not been configured the same as the sub screen and
3105 // color addition and subtraction has been diabled then
3107 // anything else it is 0
3108 GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
3109 (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
3110 (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
3112 // If sprite data has been changed then go through and
3113 // refresh the sprites.
3114 if (IPPU.OBJChanged)
3119 if (PPU.RecomputeClipWindows)
3121 ComputeClipWindows ();
3122 PPU.RecomputeClipWindows = FALSE;
3125 GFX.StartY = IPPU.PreviousLine;
3126 if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
3127 GFX.EndY = PPU.ScreenHeight - 1;
3129 uint32 starty = GFX.StartY;
3130 uint32 endy = GFX.EndY;
3132 #ifndef RC_OPTIMIZED
3133 if (Settings.SupportHiRes &&
3134 (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace))
3136 if (PPU.BGMode == 5 || PPU.BGMode == 6)
3138 IPPU.RenderedScreenWidth = 512;
3141 if (IPPU.LatchedInterlace)
3143 starty = GFX.StartY * 2;
3144 endy = GFX.EndY * 2 + 1;
3146 if (!IPPU.DoubleWidthPixels)
3148 // The game has switched from lo-res to hi-res mode part way down
3149 // the screen. Scale any existing lo-res pixels on screen
3151 if (Settings.SixteenBit)
3154 #if defined (USE_GLIDE) || defined (USE_OPENGL)
3157 (Settings.GlideEnable && GFX.Pitch == 512) ||
3160 (Settings.OpenGLEnable && GFX.Pitch == 512) ||
3164 // Have to back out of the speed up hack where the low res.
3165 // SNES image was rendered into a 256x239 sized buffer,
3166 // ignoring the true, larger size of the buffer.
3168 for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
3170 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3171 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.RealPitch) + 510;
3172 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3175 GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
3176 GFX.PPL = GFX.Pitch >> 1;
3177 GFX.PPLx2 = GFX.Pitch;
3178 GFX.ZPitch = GFX.PPL;
3182 for (register uint32 y = 0; y < GFX.StartY; y++)
3184 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3185 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3186 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3193 for (register uint32 y = 0; y < GFX.StartY; y++)
3195 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3196 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3197 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3202 IPPU.DoubleWidthPixels = TRUE;
3205 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3207 uint32 black = BLACK | (BLACK << 16);
3209 // Are we worrying about transparencies?
3210 if (Settings.Transparency && Settings.SixteenBit)
3214 GFX.r2131 = 0x5f; //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3215 GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3216 Memory.FillRAM [0x212d]) & 15;
3217 GFX.r212c &= ~GFX.r212d; // make sure the main BG reg is the reverse of the sub BG reg
3218 GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3221 // Check to see if any transparency effects are currently in use
3222 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3223 (GFX.r2130 & 0x30) != 0x30 &&
3224 !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3226 // transparency effects in use, so lets get busy!
3227 struct ClipData *pClip;
3229 GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3230 IPPU.XB [PPU.FixedColourGreen],
3231 IPPU.XB [PPU.FixedColourBlue]);
3232 fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3233 // Clear the z-buffer, marking areas 'covered' by the fixed
3234 // colour as depth 1.
3235 pClip = &IPPU.Clip [1];
3237 // Clear the z-buffer
3239 if (pClip->Count [5])
3242 // Colour window enabled.
3245 for (uint32 y = starty; y <= endy; y++)
3248 ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3249 IPPU.RenderedScreenWidth);
3250 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3251 IPPU.RenderedScreenWidth);
3253 if (IPPU.Clip [0].Count [5])
3255 memset ((GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth);
3257 for (uint32 c = 0; c < pClip->Count [5]; c++)
3259 if (pClip->Right [c][5] > pClip->Left [c][5])
3261 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3262 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3263 if (IPPU.Clip [0].Count [5])
3265 // Blast, have to clear the sub-screen to the fixed-colour
3266 // because there is a colour window in effect clipping
3267 // the main screen that will allow the sub-screen
3268 // 'underneath' to show through.
3269 memset ((GFX.SubScreen + y * GFX.Pitch2) + pClip->Left [c][5] * x2,
3271 pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3277 #else // NOT RC_OPTIMIZED
3278 // loop around all of the lines being updated
3279 for (uint32 y = starty; y <= endy; y++)
3281 // Clear the subZbuffer
3282 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3283 IPPU.RenderedScreenWidth>>2);
3284 // Clear the Zbuffer
3285 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3286 IPPU.RenderedScreenWidth>>2);
3288 // if there is clipping then clear subscreen to a black color
3289 if (IPPU.Clip [0].Count [5])
3291 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth>>1);
3294 // loop through all window clippings
3295 for (uint32 c = 0; c < pClip->Count [5]; c++)
3297 if (pClip->Right [c][5] > pClip->Left [c][5])
3299 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3300 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3301 if (IPPU.Clip [0].Count [5])
3303 // Blast, have to clear the sub-screen to the fixed-colour
3304 // because there is a colour window in effect clipping
3305 // the main screen that will allow the sub-screen
3306 // 'underneath' to show through.
3308 register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch2);
3309 register uint16 *q = p + pClip->Right [c][5] * x2;
3310 p += pClip->Left [c][5] * x2;
3313 *p++ = (uint16) GFX.FixedColour;
3319 //#undef RC_OPTIMIZED
3324 // No windows are clipping the main screen
3325 // this simplifies the screen clearing process
3328 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3331 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3332 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3336 for (uint32 y = starty; y <= endy; y++)
3338 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3339 IPPU.RenderedScreenWidth);
3340 memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3341 IPPU.RenderedScreenWidth);
3345 if (IPPU.Clip [0].Count [5])
3347 // Blast, have to clear the sub-screen to the fixed-colour
3348 // because there is a colour window in effect clipping
3349 // the main screen that will allow the sub-screen
3350 // 'underneath' to show through.
3351 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3353 memset ((GFX.SubScreen + starty * GFX.Pitch2),
3354 GFX.FixedColour | (GFX.FixedColour << 16),
3355 GFX.Pitch2 * (endy - starty - 1));
3359 for (uint32 y = starty; y <= endy; y++)
3361 memset ((GFX.SubScreen + y * GFX.Pitch2),
3362 GFX.FixedColour | (GFX.FixedColour << 16),
3363 IPPU.RenderedScreenWidth);
3368 #else // NOT RC_OPTIMIZED
3369 // loop through all of the lines to be updated
3370 for (uint32 y = starty; y <= endy; y++)
3372 // Clear the Zbuffer
3373 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3374 IPPU.RenderedScreenWidth>>2);
3375 // clear the sub Zbuffer to 1
3376 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3377 IPPU.RenderedScreenWidth>>2);
3378 if (IPPU.Clip [0].Count [5])
3380 // Blast, have to clear the sub-screen to the fixed-colour
3381 // because there is a colour window in effect clipping
3382 // the main screen that will allow the sub-screen
3383 // 'underneath' to show through.
3386 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), fixedColour,
3387 IPPU.RenderedScreenWidth>>1);
3394 if (ANYTHING_ON_SUB)
3396 GFX.DB = GFX.SubZBuffer;
3397 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3400 if (IPPU.Clip [0].Count [5])
3402 for (uint32 y = starty; y <= endy; y++)
3404 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3405 register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3406 register uint8 *e = d + SNES_WIDTH;
3411 *p = *(p + GFX.Delta);
3420 GFX.DB = GFX.ZBuffer;
3421 RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3424 uint32 back = IPPU.ScreenColors [0];
3429 pClip = &IPPU.Clip [0];
3431 for (uint32 y = starty; y <= endy; y++)
3433 if (!(Count = pClip->Count [5]))
3440 for (uint32 b = 0; b < Count; b++)
3442 if (pClip->Count [5])
3444 Left = pClip->Left [b][5] * x2;
3445 Right = pClip->Right [b][5] * x2;
3450 if (GFX.r2131 & 0x80)
3452 if (GFX.r2131 & 0x40)
3454 // Subtract, halving the result.
3455 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3456 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3457 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3458 register uint8 *e = d + Right;
3459 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3469 *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3484 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3485 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3486 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3487 register uint8 *e = d + Right;
3488 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3498 *p = COLOR_SUB (back, *(p + GFX.Delta));
3512 if (GFX.r2131 & 0x40)
3514 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3515 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3516 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3517 register uint8 *e = d + Right;
3518 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3527 *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3542 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3543 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3544 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3545 register uint8 *e = d + Right;
3546 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3555 *p = COLOR_ADD (back, *(p + GFX.Delta));
3569 if (!pClip->Count [5])
3571 // The backdrop has not been cleared yet - so
3572 // copy the sub-screen to the main screen
3573 // or fill it with the back-drop colour if the
3574 // sub-screen is clear.
3575 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3576 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3577 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3578 register uint8 *e = d + Right;
3587 *p = *(p + GFX.Delta);
3589 *p = GFX.FixedColour;
3606 // Subscreen not being added to back
3607 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3608 pClip = &IPPU.Clip [0];
3610 if (pClip->Count [5])
3612 for (uint32 y = starty; y <= endy; y++)
3614 for (uint32 b = 0; b < pClip->Count [5]; b++)
3616 uint32 Left = pClip->Left [b][5] * x2;
3617 uint32 Right = pClip->Right [b][5] * x2;
3618 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3619 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3620 register uint8 *e = d + Right;
3634 for (uint32 y = starty; y <= endy; y++)
3636 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3637 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3638 register uint8 *e = d + 256 * x2;
3658 // 16bit and transparency but currently no transparency effects in
3661 // get the back colour of the current screen
3662 uint32 back = IPPU.ScreenColors [0] |
3663 (IPPU.ScreenColors [0] << 16);
3665 // if forceblanking in use then use black instead of the back color
3666 if (PPU.ForcedBlanking)
3669 // not sure what Clip is used for yet
3670 // could be a check to see if there is any clipping present?
3671 if (IPPU.Clip [0].Count[5])
3675 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3677 memset (GFX.Screen + starty * GFX.Pitch2, black,
3678 GFX.Pitch2 * (endy - starty - 1));
3682 for (uint32 y = starty; y <= endy; y++)
3684 memset (GFX.Screen + y * GFX.Pitch2, black,
3688 for (uint32 y = starty; y <= endy; y++)
3690 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3692 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3695 memset ((GFX.Screen + y * GFX.Pitch2) + IPPU.Clip [0].Left [c][5] * x2,
3697 IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3702 // loop through all of the lines that are going to be updated as part of this screen update
3703 for (uint32 y = starty; y <= endy; y++)
3705 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), black,
3706 IPPU.RenderedScreenWidth>>1);
3710 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3712 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3714 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2); // get pointer to current line in screen buffer
3715 register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3716 p += IPPU.Clip [0].Left [c][5] * x2;
3719 *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3729 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3731 memset (GFX.Screen + starty * GFX.Pitch2, back,
3732 GFX.Pitch2 * (endy - starty - 1));
3736 for (uint32 y = starty; y <= endy; y++)
3738 memset (GFX.Screen + y * GFX.Pitch2, back,
3743 // there is no clipping to worry about so just fill with the back colour
3744 for (uint32 y = starty; y <= endy; y++)
3746 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3747 IPPU.RenderedScreenWidth>>1);
3752 // If Forced blanking is not in effect
3753 if (!PPU.ForcedBlanking)
3756 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3758 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3759 GFX.ZPitch * (endy - starty - 1));
3763 for (uint32 y = starty; y <= endy; y++)
3765 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3770 // Clear the Zbuffer for each of the lines which are going to be updated
3771 for (uint32 y = starty; y <= endy; y++)
3773 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3777 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3778 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3782 else // Transparencys are disabled, ahh lovely ... nice and easy.
3785 if (Settings.SixteenBit)
3788 // get back colour to be used in clearing the screen
3789 register uint32 back;
3790 if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3791 (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3793 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3794 (IPPU.XB[PPU.FixedColourGreen] << 6) |
3795 (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3796 back = (back << 16) | back;
3800 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3803 // if Forcedblanking in use then back colour becomes black
3804 if (PPU.ForcedBlanking)
3808 SelectTileRenderer (TRUE); //selects the tile renderers to be used
3809 // TRUE means to use the default
3810 // FALSE means use best renderer based on current
3811 // graphics register settings
3814 // now clear all graphics lines which are being updated using the back colour
3815 for (register uint32 y = starty; y <= endy; y++)
3817 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3818 IPPU.RenderedScreenWidth>>1);
3822 else // Settings.SixteenBit == false
3824 // because we are in 8 bit we can just use 0 to clear the screen
3825 // this means we can use the Zero Memory function
3827 // Loop through all lines being updated and clear the pixels to 0
3828 for (uint32 y = starty; y <= endy; y++)
3830 ZeroMemory (GFX.Screen + y * GFX.Pitch2,
3831 IPPU.RenderedScreenWidth);
3835 if (!PPU.ForcedBlanking)
3837 // Loop through all lines being updated and clear the
3838 // zbuffer for each of the lines
3839 for (uint32 y = starty; y <= endy; y++)
3841 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3842 IPPU.RenderedScreenWidth>>2);
3844 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3845 GFX.pCurrentClip = &IPPU.Clip [0];
3847 // Define an inline function to handle clipping
3848 #define FIXCLIP(n) \
3849 if (GFX.r212c & (1 << (n))) \
3850 GFX.pCurrentClip = &IPPU.Clip [0]; \
3852 GFX.pCurrentClip = &IPPU.Clip [1]
3854 // Define an inline function to handle which BGs are being displayed
3855 #define DISPLAY(n) \
3856 (!(PPU.BG_Forced & n) && \
3857 (GFX.r212c & n) || \
3858 ((GFX.r212d & n) && subadd))
3860 uint8 subadd = GFX.r2131 & 0x3f;
3862 // go through all BGS are check if they need to be displayed
3863 bool8_32 BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3864 bool8_32 BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3865 bool8_32 BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3866 bool8_32 BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3867 bool8_32 OB = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3869 if (PPU.BGMode <= 1)
3871 // screen modes 0 and 1
3880 DrawBackground (PPU.BGMode, 0, 10, 14);
3885 DrawBackground (PPU.BGMode, 1, 9, 13);
3890 DrawBackground (PPU.BGMode, 2, 3,
3891 (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3893 if (BG3 && PPU.BGMode == 0)
3896 DrawBackground (PPU.BGMode, 3, 2, 5);
3899 else if (PPU.BGMode != 7)
3901 // screen modes 2 and up but not mode 7
3910 DrawBackground (PPU.BGMode, 0, 5, 13);
3912 if (BG1 && PPU.BGMode != 6)
3915 DrawBackground (PPU.BGMode, 1, 2, 9);
3926 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3930 if (Memory.FillRAM [0x2133] & 0x40)
3932 GFX.Mode7Mask = 0x7f;
3933 GFX.Mode7PriorityMask = 0x80;
3934 Mode7Depths [0] = 5;
3935 Mode7Depths [1] = 9;
3940 GFX.Mode7Mask = 0xff;
3941 GFX.Mode7PriorityMask = 0;
3942 Mode7Depths [0] = 5;
3943 Mode7Depths [1] = 5;
3948 if (!Settings.SixteenBit)
3949 DrawBGMode7Background (GFX.Screen, bg);
3953 if (!Settings.Mode7Interpolate)
3955 DrawBGMode7Background16 (GFX.Screen, bg);
3959 DrawBGMode7Background16_i (GFX.Screen, bg);
3966 #ifndef RC_OPTIMIZE // no hi res
3967 if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3969 if (IPPU.DoubleWidthPixels)
3971 // Mixure of background modes used on screen - scale width
3972 // of all non-mode 5 and 6 pixels.
3974 if (Settings.SixteenBit)
3977 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3979 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3980 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3981 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3988 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3990 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3991 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3992 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3999 if (IPPU.LatchedInterlace)
4001 // Interlace is enabled - double the height of all non-mode 5 and 6
4003 for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
4005 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch2),
4006 (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch2),
4012 IPPU.PreviousLine = IPPU.CurrentLine;
4015 #ifdef GFX_MULTI_FORMAT
4017 #define _BUILD_PIXEL(F) \
4018 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
4020 return (BUILD_PIXEL_##F(R,G,B)); \
4022 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
4024 return (BUILD_PIXEL2_##F(R,G,B)); \
4026 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
4028 DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
4031 _BUILD_PIXEL(RGB565)
4032 _BUILD_PIXEL(RGB555)
4033 _BUILD_PIXEL(BGR565)
4034 _BUILD_PIXEL(BGR555)
4035 _BUILD_PIXEL(GBR565)
4036 _BUILD_PIXEL(GBR555)
4037 _BUILD_PIXEL(RGB5551)
4039 bool8_32 S9xSetRenderPixelFormat (int format)
4041 extern uint32 current_graphic_format;
4043 current_graphic_format = format;
4048 _BUILD_SETUP(RGB565)
4051 _BUILD_SETUP(RGB555)
4054 _BUILD_SETUP(BGR565)
4057 _BUILD_SETUP(BGR555)
4060 _BUILD_SETUP(GBR565)
4063 _BUILD_SETUP(GBR555)
4066 _BUILD_SETUP(RGB5551)