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"
53 #define USE_CRAZY_OPTS
59 extern void memcpy16(unsigned short *dest, unsigned short *src, int count);
60 extern void memcpy16bswap(unsigned short *dest, void *src, int count);
61 extern void memcpy32(uint32_t *dest, uint32_t *src, int count);
62 extern void memset32(uint32_t *dest, int c, int count);
70 void ComputeClipWindows ();
71 static void S9xDisplayFrameRate ();
72 static void S9xDisplayString (const char *string);
74 extern uint8 BitShifts[8][4];
75 extern uint8 TileShifts[8][4];
76 extern uint8 PaletteShifts[8][4];
77 extern uint8 PaletteMasks[8][4];
78 extern uint8 Depths[8][4];
79 extern uint8 BGSizes [2];
81 extern NormalTileRenderer DrawTilePtr;
82 extern ClippedTileRenderer DrawClippedTilePtr;
83 extern NormalTileRenderer DrawHiResTilePtr;
84 extern ClippedTileRenderer DrawHiResClippedTilePtr;
85 extern LargePixelRenderer DrawLargePixelPtr;
89 extern struct SLineData LineData[240];
90 extern struct SLineMatrixData LineMatrixData [240];
92 extern uint8 Mode7Depths [2];
95 (GFX.r212c & (1 << (N)) && \
96 !(PPU.BG_Forced & (1 << (N))))
98 #define SUB_OR_ADD(N) \
99 (GFX.r2131 & (1 << (N)))
102 ((GFX.r2130 & 0x30) != 0x30 && \
104 (GFX.r212d & (1 << N)) && \
105 !(PPU.BG_Forced & (1 << (N))))
107 #define ANYTHING_ON_SUB \
108 ((GFX.r2130 & 0x30) != 0x30 && \
112 #define ADD_OR_SUB_ON_ANYTHING \
115 #define BLACK BUILD_PIXEL(0,0,0)
117 void DrawTile (uint32 Tile, uint32 Offset, uint32 StartLine,
118 uint32 LineCount, struct SGFX * gfx);
119 void DrawClippedTile (uint32 Tile, uint32 Offset,
120 uint32 StartPixel, uint32 Width,
121 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
122 void DrawTilex2 (uint32 Tile, uint32 Offset, uint32 StartLine,
123 uint32 LineCount, struct SGFX * gfx);
124 void DrawClippedTilex2 (uint32 Tile, uint32 Offset,
125 uint32 StartPixel, uint32 Width,
126 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
127 void DrawTilex2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
128 uint32 LineCount, struct SGFX * gfx);
129 void DrawClippedTilex2x2 (uint32 Tile, uint32 Offset,
130 uint32 StartPixel, uint32 Width,
131 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
132 void DrawLargePixel (uint32 Tile, uint32 Offset,
133 uint32 StartPixel, uint32 Pixels,
134 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
136 void DrawTile16 (uint32 Tile, uint32 Offset, uint32 StartLine,
137 uint32 LineCount, struct SGFX * gfx);
138 void DrawClippedTile16 (uint32 Tile, uint32 Offset,
139 uint32 StartPixel, uint32 Width,
140 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
141 void DrawTile16x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
142 uint32 LineCount, struct SGFX * gfx);
143 void DrawClippedTile16x2 (uint32 Tile, uint32 Offset,
144 uint32 StartPixel, uint32 Width,
145 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
146 void DrawTile16x2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
147 uint32 LineCount, struct SGFX * gfx);
148 void DrawClippedTile16x2x2 (uint32 Tile, uint32 Offset,
149 uint32 StartPixel, uint32 Width,
150 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
151 void DrawLargePixel16 (uint32 Tile, uint32 Offset,
152 uint32 StartPixel, uint32 Pixels,
153 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
155 void DrawTile16Add (uint32 Tile, uint32 Offset, uint32 StartLine,
156 uint32 LineCount, struct SGFX * gfx);
158 void DrawClippedTile16Add (uint32 Tile, uint32 Offset,
159 uint32 StartPixel, uint32 Width,
160 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
162 void DrawTile16Add1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
163 uint32 LineCount, struct SGFX * gfx);
165 void DrawClippedTile16Add1_2 (uint32 Tile, uint32 Offset,
166 uint32 StartPixel, uint32 Width,
167 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
169 void DrawTile16FixedAdd1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
170 uint32 LineCount, struct SGFX * gfx);
172 void DrawClippedTile16FixedAdd1_2 (uint32 Tile, uint32 Offset,
173 uint32 StartPixel, uint32 Width,
174 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
176 void DrawTile16Sub (uint32 Tile, uint32 Offset, uint32 StartLine,
177 uint32 LineCount, struct SGFX * gfx);
179 void DrawClippedTile16Sub (uint32 Tile, uint32 Offset,
180 uint32 StartPixel, uint32 Width,
181 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
183 void DrawTile16Sub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
184 uint32 LineCount, struct SGFX * gfx);
186 void DrawClippedTile16Sub1_2 (uint32 Tile, uint32 Offset,
187 uint32 StartPixel, uint32 Width,
188 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
190 void DrawTile16FixedSub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
191 uint32 LineCount, struct SGFX * gfx);
193 void DrawClippedTile16FixedSub1_2 (uint32 Tile, uint32 Offset,
194 uint32 StartPixel, uint32 Width,
195 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
197 void DrawLargePixel16Add (uint32 Tile, uint32 Offset,
198 uint32 StartPixel, uint32 Pixels,
199 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
201 void DrawLargePixel16Add1_2 (uint32 Tile, uint32 Offset,
202 uint32 StartPixel, uint32 Pixels,
203 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
205 void DrawLargePixel16Sub (uint32 Tile, uint32 Offset,
206 uint32 StartPixel, uint32 Pixels,
207 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
209 void DrawLargePixel16Sub1_2 (uint32 Tile, uint32 Offset,
210 uint32 StartPixel, uint32 Pixels,
211 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
213 void DrawHiResClippedTile16 (uint32 Tile, uint32 Offset,
214 uint32 StartPixel, uint32 Width,
215 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
217 void DrawHiResTile16 (uint32 Tile, uint32 Offset,
218 uint32 StartLine, uint32 LineCount, struct SGFX * gfx);
220 bool8_32 S9xGraphicsInit ()
222 register uint32 PixelOdd = 1;
223 register uint32 PixelEven = 2;
225 #ifdef GFX_MULTI_FORMAT
226 if (GFX.BuildPixel == NULL)
227 S9xSetRenderPixelFormat (RGB565);
230 for (uint8 bitshift = 0; bitshift < 4; bitshift++)
232 for (register int i = 0; i < 16; i++)
234 register uint32 h = 0;
235 register uint32 l = 0;
237 #if defined(LSB_FIRST)
256 h |= (PixelOdd << 24);
258 h |= (PixelOdd << 16);
260 h |= (PixelOdd << 8);
264 l |= (PixelOdd << 24);
266 l |= (PixelOdd << 16);
268 l |= (PixelOdd << 8);
273 odd_high[bitshift][i] = h;
274 odd_low[bitshift][i] = l;
277 #if defined(LSB_FIRST)
283 h |= PixelEven << 16;
285 h |= PixelEven << 24;
291 l |= PixelEven << 16;
293 l |= PixelEven << 24;
296 h |= (PixelEven << 24);
298 h |= (PixelEven << 16);
300 h |= (PixelEven << 8);
304 l |= (PixelEven << 24);
306 l |= (PixelEven << 16);
308 l |= (PixelEven << 8);
313 even_high[bitshift][i] = h;
314 even_low[bitshift][i] = l;
320 GFX.RealPitch = GFX.Pitch2 = GFX.Pitch;
321 GFX.ZPitch = GFX.Pitch;
322 if (Settings.SixteenBit)
324 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
325 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
326 //GFX.InfoStringTimeout = 0;
327 //GFX.InfoString = NULL;
330 IPPU.OBJChanged = TRUE;
331 if (Settings.Transparency)
332 Settings.SixteenBit = TRUE;
334 IPPU.DirectColourMapsNeedRebuild = TRUE;
336 if (Settings.SixteenBit)
338 DrawTilePtr = DrawTile16;
339 DrawClippedTilePtr = DrawClippedTile16;
340 DrawLargePixelPtr = DrawLargePixel16;
341 DrawHiResTilePtr= DrawHiResTile16;
342 DrawHiResClippedTilePtr = DrawHiResClippedTile16;
343 GFX.PPL = GFX.Pitch >> 1;
344 GFX.PPLx2 = GFX.Pitch;
348 DrawTilePtr = DrawTile;
349 DrawClippedTilePtr = DrawClippedTile;
350 DrawLargePixelPtr = DrawLargePixel;
351 DrawHiResTilePtr = DrawTile;
352 DrawHiResClippedTilePtr = DrawClippedTile;
354 GFX.PPLx2 = GFX.Pitch * 2;
356 S9xFixColourBrightness ();
358 if (Settings.SixteenBit)
360 if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
363 if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
364 !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
368 free ((char *) GFX.ZERO_OR_X2);
369 GFX.ZERO_OR_X2 = NULL;
373 free ((char *) GFX.X2);
380 // Build a lookup table that multiplies a packed RGB value by 2 with
382 for (r = 0; r <= MAX_RED; r++)
387 for (g = 0; g <= MAX_GREEN; g++)
392 for (b = 0; b <= MAX_BLUE; b++)
397 GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
398 GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
402 ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
403 ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
404 // Build a lookup table that if the top bit of the color value is zero
405 // then the value is zero, otherwise multiply the value by 2. Used by
406 // the color subtraction code.
408 #if defined(OLD_COLOUR_BLENDING)
409 for (r = 0; r <= MAX_RED; r++)
412 if ((r2 & 0x10) == 0)
415 r2 = (r2 << 1) & MAX_RED;
417 for (g = 0; g <= MAX_GREEN; g++)
420 if ((g2 & GREEN_HI_BIT) == 0)
423 g2 = (g2 << 1) & MAX_GREEN;
425 for (b = 0; b <= MAX_BLUE; b++)
428 if ((b2 & 0x10) == 0)
431 b2 = (b2 << 1) & MAX_BLUE;
433 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
434 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
439 for (r = 0; r <= MAX_RED; r++)
442 if ((r2 & 0x10) == 0)
445 r2 = (r2 << 1) & MAX_RED;
449 for (g = 0; g <= MAX_GREEN; g++)
452 if ((g2 & GREEN_HI_BIT) == 0)
455 g2 = (g2 << 1) & MAX_GREEN;
459 for (b = 0; b <= MAX_BLUE; b++)
462 if ((b2 & 0x10) == 0)
465 b2 = (b2 << 1) & MAX_BLUE;
469 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
470 GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
476 // Build a lookup table that if the top bit of the color value is zero
477 // then the value is zero, otherwise its just the value.
478 for (r = 0; r <= MAX_RED; r++)
481 if ((r2 & 0x10) == 0)
486 for (g = 0; g <= MAX_GREEN; g++)
489 if ((g2 & GREEN_HI_BIT) == 0)
493 for (b = 0; b <= MAX_BLUE; b++)
496 if ((b2 & 0x10) == 0)
501 GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
502 GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
510 GFX.ZERO_OR_X2 = NULL;
517 void S9xGraphicsDeinit (void)
519 // Free any memory allocated in S9xGraphicsInit
522 free ((char *) GFX.X2);
527 free ((char *) GFX.ZERO_OR_X2);
528 GFX.ZERO_OR_X2 = NULL;
532 free ((char *) GFX.ZERO);
537 void S9xBuildDirectColourMaps ()
539 for (uint32 p = 0; p < 8; p++)
541 for (uint32 c = 0; c < 256; c++)
544 DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
545 ((c & 0x38) >> 1) | (p & 2),
546 ((c & 0xc0) >> 3) | (p & 4));
549 IPPU.DirectColourMapsNeedRebuild = FALSE;
552 void S9xStartScreenRefresh ()
554 if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0)
555 GFX.InfoString = NULL;
557 if (IPPU.RenderThisFrame)
560 if (!S9xInitUpdate ())
562 IPPU.RenderThisFrame = FALSE;
566 IPPU.RenderedFramesCount++;
567 IPPU.PreviousLine = IPPU.CurrentLine = 0;
568 IPPU.MaxBrightness = PPU.Brightness;
569 IPPU.LatchedBlanking = PPU.ForcedBlanking;
570 IPPU.LatchedInterlace = (Memory.FillRAM[0x2133] & 1);
571 IPPU.RenderedScreenWidth = 256;
572 IPPU.RenderedScreenHeight = PPU.ScreenHeight;
573 IPPU.DoubleWidthPixels = FALSE;
574 GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
575 GFX.PPL = GFX.PPLx2 >> 1;
576 GFX.ZPitch = GFX.RealPitch;
577 if (Settings.SixteenBit)
579 PPU.RecomputeClipWindows = TRUE;
580 GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
581 GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
583 if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0)
585 IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount;
586 IPPU.RenderedFramesCount = 0;
591 void RenderLine (uint8 C)
593 if (IPPU.RenderThisFrame)
596 LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
597 LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
598 LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
599 LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
603 struct SLineMatrixData *p = &LineMatrixData [C];
604 p->MatrixA = PPU.MatrixA;
605 p->MatrixB = PPU.MatrixB;
606 p->MatrixC = PPU.MatrixC;
607 p->MatrixD = PPU.MatrixD;
608 p->CentreX = PPU.CentreX;
609 p->CentreY = PPU.CentreY;
614 if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
615 PPU.BG[2].HOffset == 0xe000)
617 LineData[C].BG[2].VOffset = 0xe1;
618 LineData[C].BG[2].HOffset = 0;
624 LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
625 LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
626 LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
627 LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
631 IPPU.CurrentLine = C + 1;
636 void S9xEndScreenRefresh()
638 IPPU.HDMAStarted = FALSE;
641 if (IPPU.RenderThisFrame)
644 if (IPPU.ColorsChanged)
646 uint32 saved = PPU.CGDATA[0];
647 if (!Settings.SixteenBit)
649 // Hack for Super Mario World - to get its sky blue
650 // (It uses Fixed colour addition on the backdrop colour)
651 if (!(Memory.FillRAM [0x2131] & 0x80) &&
652 (Memory.FillRAM[0x2131] & 0x20) &&
653 (PPU.FixedColourRed || PPU.FixedColourGreen ||
654 PPU.FixedColourBlue))
656 PPU.CGDATA[0] = PPU.FixedColourRed |
657 (PPU.FixedColourGreen << 5) |
658 (PPU.FixedColourBlue << 10);
661 IPPU.ColorsChanged = FALSE;
665 PPU.CGDATA[0] = saved;
667 GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
668 GFX.PPL = GFX.PPLx2 >> 1;
670 if (Settings.DisplayFrameRate)
671 S9xDisplayFrameRate ();
673 S9xDisplayString (GFX.InfoString);
675 S9xDeinitUpdate (IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
676 Settings.SixteenBit);
684 if (CPU.Flags & FRAME_ADVANCE_FLAG)
686 if (ICPU.FrameAdvanceCount)
688 ICPU.FrameAdvanceCount--;
689 IPPU.RenderThisFrame = TRUE;
694 CPU.Flags &= ~FRAME_ADVANCE_FLAG;
695 CPU.Flags |= DEBUG_MODE_FLAG;
700 if (CPU.SRAMModified)
702 if (!CPU.AutoSaveTimer)
704 if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
705 CPU.SRAMModified = FALSE;
709 if (!--CPU.AutoSaveTimer)
712 CPU.SRAMModified = FALSE;
718 void S9xSetInfoString (const char *string)
720 GFX.InfoString = string;
721 GFX.InfoStringTimeout = 120;
724 INLINE void SelectTileRenderer (bool8_32 normal)
728 DrawTilePtr = DrawTile16;
729 DrawClippedTilePtr = DrawClippedTile16;
730 DrawLargePixelPtr = DrawLargePixel16;
734 if (GFX.r2131 & 0x80)
736 if (GFX.r2131 & 0x40)
740 DrawTilePtr = DrawTile16Sub1_2;
741 DrawClippedTilePtr = DrawClippedTile16Sub1_2;
745 // Fixed colour substraction
746 DrawTilePtr = DrawTile16FixedSub1_2;
747 DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
749 DrawLargePixelPtr = DrawLargePixel16Sub1_2;
753 DrawTilePtr = DrawTile16Sub;
754 DrawClippedTilePtr = DrawClippedTile16Sub;
755 DrawLargePixelPtr = DrawLargePixel16Sub;
760 if (GFX.r2131 & 0x40)
764 DrawTilePtr = DrawTile16Add1_2;
765 DrawClippedTilePtr = DrawClippedTile16Add1_2;
769 // Fixed colour addition
770 DrawTilePtr = DrawTile16FixedAdd1_2;
771 DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
773 DrawLargePixelPtr = DrawLargePixel16Add1_2;
777 DrawTilePtr = DrawTile16Add;
778 DrawClippedTilePtr = DrawClippedTile16Add;
779 DrawLargePixelPtr = DrawLargePixel16Add;
790 switch (PPU.OBJSizeSelect)
821 int FirstSprite = PPU.FirstSprite & 0x7f;
826 if (PPU.OBJ [S].Size)
831 long VPos = PPU.OBJ [S].VPos;
833 if (VPos >= PPU.ScreenHeight)
835 if (PPU.OBJ [S].HPos < 256 && PPU.OBJ [S].HPos > -Size &&
836 VPos < PPU.ScreenHeight && VPos > -Size)
838 GFX.OBJList [C++] = S;
840 GFX.VPositions[S] = VPos;
843 } while (S != FirstSprite);
845 // Terminate the list
846 GFX.OBJList [C] = -1;
847 IPPU.OBJChanged = FALSE;
850 void DrawOBJS (bool8_32 OnMain = FALSE, uint8 D = 0)
853 uint32 BaseTile, Tile;
859 BG.TileAddress = PPU.OBJNameBase;
860 BG.StartPalette = 128;
863 BG.Buffer = IPPU.TileCache [TILE_4BIT];
864 BG.Buffered = IPPU.TileCached [TILE_4BIT];
865 BG.NameSelect = PPU.OBJNameSelect;
866 BG.DirectColourMode = FALSE;
873 for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
875 int VPos = GFX.VPositions [S];
876 int Size = GFX.Sizes[S];
880 if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
883 if (OnMain && SUB_OR_ADD(4))
885 SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
888 BaseTile = PPU.OBJ[S].Name | (PPU.OBJ[S].Palette << 10);
890 if (PPU.OBJ[S].HFlip)
892 BaseTile += ((Size >> 3) - 1) | H_FLIP;
895 if (PPU.OBJ[S].VFlip)
898 int clipcount = GFX.pCurrentClip->Count [4];
902 GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
904 for (int clip = 0; clip < clipcount; clip++)
908 if (!GFX.pCurrentClip->Count [4])
915 Left = GFX.pCurrentClip->Left [clip][4];
916 Right = GFX.pCurrentClip->Right [clip][4];
919 if (Right <= Left || PPU.OBJ[S].HPos + Size <= Left ||
920 PPU.OBJ[S].HPos >= Right)
923 for (int Y = 0; Y < Size; Y += 8)
925 if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
932 if ((StartLine = VPos + Y) < (int) GFX.StartY)
934 StartLine = GFX.StartY - StartLine;
935 LineCount = 8 - StartLine;
942 if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
943 if ((LineCount -= Last) <= 0)
946 TileLine = StartLine << 3;
947 O = (VPos + Y + StartLine) * GFX.PPL;
948 if (!PPU.OBJ[S].VFlip)
949 Tile = BaseTile + (Y << 1);
951 Tile = BaseTile + ((Size - Y - 8) << 1);
953 int Middle = Size >> 3;
954 if (PPU.OBJ[S].HPos < Left)
956 Tile += ((Left - PPU.OBJ[S].HPos) >> 3) * TileInc;
957 Middle -= (Left - PPU.OBJ[S].HPos) >> 3;
958 O += Left * GFX.PixSize;
959 if ((Offset = (Left - PPU.OBJ[S].HPos) & 7))
961 O -= Offset * GFX.PixSize;
963 int Width = Right - Left;
966 (*DrawClippedTilePtr) (Tile, O, Offset, W,
967 TileLine, LineCount, &GFX);
973 O += 8 * GFX.PixSize;
977 O += PPU.OBJ[S].HPos * GFX.PixSize;
979 if (PPU.OBJ[S].HPos + Size >= Right)
981 Middle -= ((PPU.OBJ[S].HPos + Size + 7) -
983 Offset = (Right - (PPU.OBJ[S].HPos + Size)) & 7;
988 for (int X = 0; X < Middle; X++, O += 8 * GFX.PixSize,
991 (*DrawTilePtr) (Tile, O, TileLine, LineCount, &GFX);
995 (*DrawClippedTilePtr) (Tile, O, 0, Offset,
996 TileLine, LineCount, &GFX);
1004 void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1013 uint8 depths [2] = {Z1, Z2};
1016 BG.StartPalette = bg << 5;
1018 BG.StartPalette = 0;
1020 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1022 if (PPU.BG[bg].SCSize & 1)
1027 if (PPU.BG[bg].SCSize & 2)
1032 if (PPU.BG[bg].SCSize & 1)
1041 if (BG.TileSize == 16)
1052 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1054 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1055 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1056 uint32 MosaicOffset = Y % PPU.Mosaic;
1058 for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
1059 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1060 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1063 uint32 MosaicLine = VOffset + Y - MosaicOffset;
1065 if (Y + Lines > GFX.EndY)
1066 Lines = GFX.EndY + 1 - Y;
1067 uint32 VirtAlign = (MosaicLine & 7) << 3;
1072 uint32 ScreenLine = MosaicLine >> OffsetShift;
1073 uint32 Rem16 = MosaicLine & 15;
1075 if (ScreenLine & 0x20)
1080 b1 += (ScreenLine & 0x1f) << 5;
1081 b2 += (ScreenLine & 0x1f) << 5;
1086 uint32 ClipCount = GFX.pCurrentClip->Count [bg];
1087 uint32 HPos = HOffset;
1088 uint32 PixWidth = PPU.Mosaic;
1093 for (uint32 clip = 0; clip < ClipCount; clip++)
1095 if (GFX.pCurrentClip->Count [bg])
1097 Left = GFX.pCurrentClip->Left [clip][bg];
1098 Right = GFX.pCurrentClip->Right [clip][bg];
1099 uint32 r = Left % PPU.Mosaic;
1100 HPos = HOffset + Left;
1101 PixWidth = PPU.Mosaic - r;
1103 uint32 s = Y * GFX.PPL + Left * GFX.PixSize;
1104 for (uint32 x = Left; x < Right; x += PixWidth,
1105 s += PixWidth * GFX.PixSize,
1106 HPos += PixWidth, PixWidth = PPU.Mosaic)
1108 uint32 Quot = (HPos & OffsetMask) >> 3;
1110 if (x + PixWidth >= Right)
1111 PixWidth = Right - x;
1113 if (BG.TileSize == 8)
1116 t = b2 + (Quot & 0x1f);
1123 t = b2 + ((Quot >> 1) & 0x1f);
1125 t = b1 + (Quot >> 1);
1128 Tile = READ_2BYTES (t);
1129 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1132 if (BG.TileSize != 8)
1136 // Horizontal flip, but what about vertical flip ?
1139 // Both horzontal & vertical flip
1142 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1144 VirtAlign, Lines, &GFX);
1148 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1150 VirtAlign, Lines, &GFX);
1155 // Horizontal flip only
1158 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1160 VirtAlign, Lines, &GFX);
1164 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1166 VirtAlign, Lines, &GFX);
1172 // No horizontal flip, but is there a vertical flip ?
1175 // Vertical flip only
1178 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1180 VirtAlign, Lines, &GFX);
1184 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1186 VirtAlign, Lines, &GFX);
1194 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1196 VirtAlign, Lines, &GFX);
1200 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1202 VirtAlign, Lines, &GFX);
1208 (*DrawLargePixelPtr) (Tile, s, HPos & 7, PixWidth,
1209 VirtAlign, Lines, &GFX);
1215 void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1229 int VOffsetOffset = BGMode == 4 ? 0 : 32;
1230 uint8 depths [2] = {Z1, Z2};
1232 BG.StartPalette = 0;
1234 BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
1236 if (PPU.BG[2].SCSize & 1)
1241 if (PPU.BG[2].SCSize & 2)
1246 if (PPU.BG[2].SCSize & 1)
1251 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1253 if (PPU.BG[bg].SCSize & 1)
1258 if (PPU.BG[bg].SCSize & 2)
1262 if (PPU.BG[bg].SCSize & 1)
1267 static const int Lines = 1;
1270 int OffsetEnableMask = 1 << (bg + 13);
1272 if (BG.TileSize == 16)
1283 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
1285 uint32 VOff = LineData [Y].BG[2].VOffset;
1286 uint32 HOff = LineData [Y].BG[2].HOffset;
1288 int ScreenLine = VOff >> 3;
1295 if (ScreenLine & 0x20)
1296 s1 = BPS2, s2 = BPS3;
1298 s1 = BPS0, s2 = BPS1;
1300 s1 += (ScreenLine & 0x1f) << 5;
1301 s2 += (ScreenLine & 0x1f) << 5;
1303 int clipcount = GFX.pCurrentClip->Count [bg];
1307 for (int clip = 0; clip < clipcount; clip++)
1312 if (!GFX.pCurrentClip->Count [bg])
1319 Left = GFX.pCurrentClip->Left [clip][bg];
1320 Right = GFX.pCurrentClip->Right [clip][bg];
1328 uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
1339 uint32 TotalCount = 0;
1340 uint32 MaxCount = 8;
1342 uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1343 bool8_32 left_hand_edge = (Left == 0);
1344 Width = Right - Left;
1347 MaxCount = 8 - (Left & 7);
1349 while (Left < Right)
1353 // The SNES offset-per-tile background mode has a
1354 // hardware limitation that the offsets cannot be set
1355 // for the tile at the left-hand edge of the screen.
1356 VOffset = LineData [Y].BG[bg].VOffset;
1357 HOffset = LineHOffset;
1358 left_hand_edge = FALSE;
1362 // All subsequent offset tile data is shifted left by one,
1363 // hence the - 1 below.
1364 Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
1367 s0 = s2 + (Quot2 & 0x1f);
1371 HCellOffset = READ_2BYTES (s0);
1375 VOffset = LineData [Y].BG[bg].VOffset;
1376 HOffset=LineHOffset;
1377 if ((HCellOffset & OffsetEnableMask))
1379 if (HCellOffset & 0x8000)
1380 VOffset = HCellOffset + 1;
1382 HOffset = HCellOffset;
1387 VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
1388 if ((VCellOffset & OffsetEnableMask))
1389 VOffset = VCellOffset + 1;
1391 VOffset = LineData [Y].BG[bg].VOffset;
1393 if ((HCellOffset & OffsetEnableMask))
1394 HOffset = (HCellOffset & ~7)|(LineHOffset&7);
1396 HOffset=LineHOffset;
1399 VirtAlign = ((Y + VOffset) & 7) << 3;
1400 ScreenLine = (VOffset + Y) >> OffsetShift;
1402 if (((VOffset + Y) & 15) > 7)
1413 if (ScreenLine & 0x20)
1418 b1 += (ScreenLine & 0x1f) << 5;
1419 b2 += (ScreenLine & 0x1f) << 5;
1421 HPos = (HOffset + Left) & OffsetMask;
1425 if (BG.TileSize == 8)
1428 t = b2 + (Quot & 0x1f);
1435 t = b2 + ((Quot >> 1) & 0x1f);
1437 t = b1 + (Quot >> 1);
1440 if (MaxCount + TotalCount > Width)
1441 MaxCount = Width - TotalCount;
1446 if (Count > MaxCount)
1449 s -= Offset * GFX.PixSize;
1450 Tile = READ_2BYTES(t);
1451 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1453 if (BG.TileSize == 8)
1454 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines, &GFX);
1457 if (!(Tile & (V_FLIP | H_FLIP)))
1459 // Normal, unflipped
1460 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1461 s, Offset, Count, VirtAlign, Lines, &GFX);
1469 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1470 s, Offset, Count, VirtAlign, Lines, &GFX);
1475 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1476 s, Offset, Count, VirtAlign, Lines, &GFX);
1482 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1483 s, Offset, Count, VirtAlign, Lines, &GFX);
1488 TotalCount += Count;
1489 s += (Offset + Count) * GFX.PixSize;
1496 void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
1500 GFX.Pitch = GFX.RealPitch;
1501 GFX.PPL = GFX.PPLx2 >> 1;
1503 uint8 depths [2] = {Z1, Z2};
1512 BG.StartPalette = 0;
1514 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1516 if ((PPU.BG[bg].SCSize & 1))
1521 if ((PPU.BG[bg].SCSize & 2))
1526 if ((PPU.BG[bg].SCSize & 1))
1535 if (BG.TileSize == 16)
1537 VOffsetMask = 0x3ff;
1542 VOffsetMask = 0x1ff;
1545 int endy = GFX.EndY;
1547 for (int Y = GFX.StartY; Y <= endy; Y += Lines)
1550 uint32 VOffset = LineData [y].BG[bg].VOffset;
1551 uint32 HOffset = LineData [y].BG[bg].HOffset;
1552 int VirtAlign = (Y + VOffset) & 7;
1554 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1555 if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
1556 (HOffset != LineData [y + Lines].BG[bg].HOffset))
1560 if (Y + Lines > endy)
1561 Lines = endy + 1 - Y;
1563 int ScreenLine = (VOffset + Y) >> VOffsetShift;
1566 if (((VOffset + Y) & 15) > 7)
1579 if (ScreenLine & 0x20)
1584 b1 += (ScreenLine & 0x1f) << 5;
1585 b2 += (ScreenLine & 0x1f) << 5;
1587 int clipcount = GFX.pCurrentClip->Count [bg];
1590 for (int clip = 0; clip < clipcount; clip++)
1595 if (!GFX.pCurrentClip->Count [bg])
1602 Left = GFX.pCurrentClip->Left [clip][bg] * 2;
1603 Right = GFX.pCurrentClip->Right [clip][bg] * 2;
1609 uint32 s = (Left>>1) * GFX.PixSize + Y * GFX.PPL;
1610 uint32 HPos = (HOffset + Left * GFX.PixSize) & 0x3ff;
1612 uint32 Quot = HPos >> 3;
1617 t = b2 + ((Quot >> 1) & 0x1f);
1619 t = b1 + (Quot >> 1);
1621 Width = Right - Left;
1622 // Left hand edge clipped tile
1625 int Offset = (HPos & 7);
1630 Tile = READ_2BYTES (t);
1631 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1633 if (BG.TileSize == 8)
1635 if (!(Tile & H_FLIP))
1637 // Normal, unflipped
1638 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1639 s, Offset, Count, VirtAlign, Lines, &GFX);
1644 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1645 s, Offset, Count, VirtAlign, Lines, &GFX);
1650 if (!(Tile & (V_FLIP | H_FLIP)))
1652 // Normal, unflipped
1653 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1654 s, Offset, Count, VirtAlign, Lines, &GFX);
1662 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1663 s, Offset, Count, VirtAlign, Lines, &GFX);
1668 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1669 s, Offset, Count, VirtAlign, Lines, &GFX);
1675 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1676 s, Offset, Count, VirtAlign, Lines, &GFX);
1683 else if (Quot == 127)
1689 // Middle, unclipped tiles
1690 Count = Width - Count;
1691 int Middle = Count >> 3;
1693 for (int C = Middle; C > 0; s += 4, Quot++, C--)
1695 Tile = READ_2BYTES(t);
1696 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1697 if (BG.TileSize == 8)
1699 if (!(Tile & H_FLIP))
1701 // Normal, unflipped
1702 (*DrawHiResTilePtr) (Tile + (Quot & 1),
1703 s, VirtAlign, Lines, &GFX);
1708 (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1709 s, VirtAlign, Lines, &GFX);
1714 if (!(Tile & (V_FLIP | H_FLIP)))
1716 // Normal, unflipped
1717 (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1718 s, VirtAlign, Lines, &GFX);
1726 (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1727 s, VirtAlign, Lines, &GFX);
1732 (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1733 s, VirtAlign, Lines, &GFX);
1739 (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1740 s, VirtAlign, Lines, &GFX);
1752 // Right-hand edge clipped tiles
1755 Tile = READ_2BYTES(t);
1756 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1757 if (BG.TileSize == 8)
1759 if (!(Tile & H_FLIP))
1761 // Normal, unflipped
1762 (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1763 s, 0, Count, VirtAlign, Lines, &GFX);
1768 (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1769 s, 0, Count, VirtAlign, Lines, &GFX);
1774 if (!(Tile & (V_FLIP | H_FLIP)))
1776 // Normal, unflipped
1777 (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1778 s, 0, Count, VirtAlign, Lines, &GFX);
1786 (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1787 s, 0, Count, VirtAlign, Lines, &GFX);
1792 (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1793 s, 0, Count, VirtAlign, Lines, &GFX);
1799 (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1800 s, 0, Count, VirtAlign, Lines, &GFX);
1808 void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1812 BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1813 BG.BitShift = BitShifts[BGMode][bg];
1814 BG.TileShift = TileShifts[BGMode][bg];
1815 BG.TileAddress = PPU.BG[bg].NameBase << 1;
1817 BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1818 BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1819 BG.PaletteShift = PaletteShifts[BGMode][bg];
1820 BG.PaletteMask = PaletteMasks[BGMode][bg];
1821 BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1824 if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1826 DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1833 if (Settings.WrestlemaniaArcade)
1835 case 4: // Used by Puzzle Bobble
1836 DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1840 case 6: // XXX: is also offset per tile.
1841 DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1857 uint8 depths [2] = {Z1, Z2};
1860 BG.StartPalette = bg << 5;
1862 BG.StartPalette = 0;
1864 SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1866 if (PPU.BG[bg].SCSize & 1)
1871 if (PPU.BG[bg].SCSize & 2)
1876 if (PPU.BG[bg].SCSize & 1)
1885 if (BG.TileSize == 16)
1896 for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1898 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1899 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1900 int VirtAlign = (Y + VOffset) & 7;
1902 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1903 if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1904 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1907 if (Y + Lines > GFX.EndY)
1908 Lines = GFX.EndY + 1 - Y;
1912 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1915 if (((VOffset + Y) & 15) > 7)
1928 if (ScreenLine & 0x20)
1933 b1 += (ScreenLine & 0x1f) << 5;
1934 b2 += (ScreenLine & 0x1f) << 5;
1936 int clipcount = GFX.pCurrentClip->Count [bg];
1939 for (int clip = 0; clip < clipcount; clip++)
1944 if (!GFX.pCurrentClip->Count [bg])
1951 Left = GFX.pCurrentClip->Left [clip][bg];
1952 Right = GFX.pCurrentClip->Right [clip][bg];
1958 uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1959 uint32 HPos = (HOffset + Left) & OffsetMask;
1961 uint32 Quot = HPos >> 3;
1965 if (BG.TileSize == 8)
1968 t = b2 + (Quot & 0x1f);
1975 t = b2 + ((Quot >> 1) & 0x1f);
1977 t = b1 + (Quot >> 1);
1980 Width = Right - Left;
1981 // Left hand edge clipped tile
1984 uint32 Offset = (HPos & 7);
1988 s -= Offset * GFX.PixSize;
1989 Tile = READ_2BYTES(t);
1990 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1992 if (BG.TileSize == 8)
1994 (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1999 if (!(Tile & (V_FLIP | H_FLIP)))
2001 // Normal, unflipped
2002 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
2003 s, Offset, Count, VirtAlign, Lines, &GFX);
2011 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2012 s, Offset, Count, VirtAlign, Lines, &GFX);
2017 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2018 s, Offset, Count, VirtAlign, Lines, &GFX);
2024 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
2025 Offset, Count, VirtAlign, Lines, &GFX);
2029 if (BG.TileSize == 8)
2034 else if (Quot == 63)
2042 else if (Quot == 127)
2046 s += 8 * GFX.PixSize;
2049 // Middle, unclipped tiles
2050 Count = Width - Count;
2051 int Middle = Count >> 3;
2053 for (int C = Middle; C > 0; s += 8 * GFX.PixSize, Quot++, C--)
2055 Tile = READ_2BYTES(t);
2056 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
2058 if (BG.TileSize != 8)
2062 // Horizontal flip, but what about vertical flip ?
2065 // Both horzontal & vertical flip
2066 (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
2067 VirtAlign, Lines, &GFX);
2071 // Horizontal flip only
2072 (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
2073 VirtAlign, Lines, &GFX);
2078 // No horizontal flip, but is there a vertical flip ?
2081 // Vertical flip only
2082 (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
2083 VirtAlign, Lines, &GFX);
2088 (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
2089 VirtAlign, Lines, &GFX);
2095 (*DrawTilePtr) (Tile, s, VirtAlign, Lines, &GFX);
2098 if (BG.TileSize == 8)
2117 // Right-hand edge clipped tiles
2120 Tile = READ_2BYTES(t);
2121 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
2123 if (BG.TileSize == 8)
2124 (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
2128 if (!(Tile & (V_FLIP | H_FLIP)))
2130 // Normal, unflipped
2131 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
2132 Count, VirtAlign, Lines, &GFX);
2140 (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2141 s, 0, Count, VirtAlign,
2147 (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2148 s, 0, Count, VirtAlign,
2155 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
2156 s, 0, Count, VirtAlign,
2165 #define RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2166 const uint8 bmask = MASK; \
2167 for (int x = startx; x != endx; \
2168 x += (HFLIP ? -1 : 1), AA += aa, CC += cc, p++, d++) \
2170 int X = ((AA + BB) >> 8) & 0x3ff; \
2171 int Y = ((CC + DD) >> 8) & 0x3ff; \
2172 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2173 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2174 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2182 #define RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,CFILT) \
2183 register int AABB = AA + BB; \
2184 register int CCDD = CC + DD; \
2185 const uint8 bmask = MASK; \
2186 for (int x = startx; x != endx; \
2187 x += (HFLIP ? -1 : 1), AABB += aa, CCDD += cc, p++, d++) \
2189 register uint16 X = ((AABB) >> 8) CFILT; \
2190 register uint16 Y = ((CCDD) >> 8) CFILT; \
2192 if (((X | Y) & ~0x3ff) == 0) { \
2193 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2194 uint8 b = TileData[((Y & 7) << 4) + ((X & 7) << 1)]; \
2195 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2196 if (z > *d && b) { \
2200 } else if (REPEAT == 3) { \
2201 X = (x + HOffset) & 7; \
2202 Y = (yy + CentreY) & 7; \
2203 uint8 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2204 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2205 if (z > *d && b) { \
2212 #define RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,MASK,PRIOMASK) \
2213 for (uint32 clip = 0; clip < ClipCount; clip++) \
2215 if (GFX.pCurrentClip->Count [bg]) \
2217 Left = GFX.pCurrentClip->Left [clip][bg]; \
2218 Right = GFX.pCurrentClip->Right [clip][bg]; \
2219 if (Right <= Left) \
2222 register TYPE *p = (TYPE *) Screen + Left; \
2223 register uint8 *d = Depth + Left; \
2227 startx = Right - 1; \
2241 xx = startx + (HOffset - CentreX) % 1023; \
2243 xx = startx + HOffset - CentreX; \
2244 int AA = l->MatrixA * xx; \
2245 int CC = l->MatrixC * xx; \
2249 RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2250 } else if (DEZAEMON) { \
2251 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,& 0x7ff) \
2253 RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,) \
2257 #ifdef USE_CRAZY_OPTS
2259 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON) \
2260 if (GFX.Mode7PriorityMask) { \
2261 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0x7f,0x80) \
2263 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0xff,0x00) \
2266 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,HFLIP) \
2267 if (Settings.Dezaemon && PPU.Mode7Repeat) { \
2268 switch (PPU.Mode7Repeat) { \
2269 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,1); break; \
2270 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,1); break; \
2271 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,1); break; \
2274 switch (PPU.Mode7Repeat) { \
2275 case 0: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,0,0); break; \
2276 case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,0); break; \
2277 case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,0); break; \
2278 case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,0); break; \
2282 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC) \
2283 if (PPU.Mode7HFlip) { \
2284 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,1); \
2286 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,0); \
2289 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2290 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC)
2294 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2295 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,PPU.Mode7HFlip,PPU.Mode7Repeat,Settings.Dezaemon,GFX.Mode7Mask,GFX.Mode7PriorityMask)
2299 #define RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2300 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2304 int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2305 int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2307 int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2308 int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2310 if (PPU.Mode7VFlip) \
2311 yy = 261 - (int) Line; \
2315 if (PPU.Mode7Repeat == 0) \
2316 yy += (VOffset - CentreY) % 1023; \
2318 yy += VOffset - CentreY; \
2319 int BB = l->MatrixB * yy + (CentreX << 8); \
2320 int DD = l->MatrixD * yy + (CentreY << 8); \
2322 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2325 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2328 uint8 * const VRAM1 = Memory.VRAM + 1; \
2329 if (GFX.r2130 & 1) \
2331 if (IPPU.DirectColourMapsNeedRebuild) \
2332 S9xBuildDirectColourMaps (); \
2333 GFX.ScreenColors = DirectColourMaps [0]; \
2336 GFX.ScreenColors = IPPU.ScreenColors; \
2341 uint32 Right = 256; \
2342 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2347 Screen += GFX.StartY * GFX.Pitch; \
2348 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2349 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2350 RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2354 void DrawBGMode7Background (uint8 *Screen, int bg)
2356 RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & bmask))
2359 void DrawBGMode7Background16 (uint8 *Screen, int bg)
2361 RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2364 void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2366 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2367 (*(d + GFX.DepthDelta) != 1 ?
2368 COLOR_ADD (GFX.ScreenColors [b & bmask],
2370 COLOR_ADD (GFX.ScreenColors [b & bmask],
2372 GFX.ScreenColors [b & bmask]);
2375 void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2377 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2378 (*(d + GFX.DepthDelta) != 1 ?
2379 COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2381 COLOR_ADD (GFX.ScreenColors [b & bmask],
2383 GFX.ScreenColors [b & bmask]);
2386 void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2388 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2389 (*(d + GFX.DepthDelta) != 1 ?
2390 COLOR_SUB (GFX.ScreenColors [b & bmask],
2392 COLOR_SUB (GFX.ScreenColors [b & bmask],
2394 GFX.ScreenColors [b & bmask]);
2397 void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2399 RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2400 (*(d + GFX.DepthDelta) != 1 ?
2401 COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2403 COLOR_SUB (GFX.ScreenColors [b & bmask],
2405 GFX.ScreenColors [b & bmask]);
2408 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2411 uint8 *VRAM1 = Memory.VRAM + 1; \
2412 if (GFX.r2130 & 1) \
2414 if (IPPU.DirectColourMapsNeedRebuild) \
2415 S9xBuildDirectColourMaps (); \
2416 GFX.ScreenColors = DirectColourMaps [0]; \
2419 GFX.ScreenColors = IPPU.ScreenColors; \
2425 uint32 Right = 256; \
2426 uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2431 Screen += GFX.StartY * GFX.Pitch; \
2432 uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2433 struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2434 bool8_32 allowSimpleCase = FALSE; \
2435 if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2436 && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2437 && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2439 allowSimpleCase = TRUE; \
2441 for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2445 int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2446 int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2448 int CentreX = ((int) l->CentreX << M7) >> M7; \
2449 int CentreY = ((int) l->CentreY << M7) >> M7; \
2451 if (PPU.Mode7VFlip) \
2452 yy = 261 - (int) Line; \
2456 if (PPU.Mode7Repeat == 0) \
2457 yy += (VOffset - CentreY) % 1023; \
2459 yy += VOffset - CentreY; \
2460 bool8_32 simpleCase = FALSE; \
2463 /* Make a special case for the identity matrix, since it's a common case and */ \
2464 /* can be done much more quickly without special effects */ \
2465 if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2467 BB = CentreX << 8; \
2468 DD = (yy + CentreY) << 8; \
2469 simpleCase = TRUE; \
2473 BB = l->MatrixB * yy + (CentreX << 8); \
2474 DD = l->MatrixD * yy + (CentreY << 8); \
2477 for (uint32 clip = 0; clip < ClipCount; clip++) \
2479 if (GFX.pCurrentClip->Count [bg]) \
2481 Left = GFX.pCurrentClip->Left [clip][bg]; \
2482 Right = GFX.pCurrentClip->Right [clip][bg]; \
2483 if (Right <= Left) \
2486 TYPE *p = (TYPE *) Screen + Left; \
2487 uint8 *d = Depth + Left; \
2489 if (PPU.Mode7HFlip) \
2491 startx = Right - 1; \
2506 if (PPU.Mode7Repeat == 0) \
2507 xx = startx + (HOffset - CentreX) % 1023; \
2509 xx = startx + HOffset - CentreX; \
2517 AA = l->MatrixA * xx; \
2518 CC = l->MatrixC * xx; \
2522 if (!PPU.Mode7Repeat) \
2527 int X = ((AA + BB) >> 8) & 0x3ff; \
2528 int Y = (DD >> 8) & 0x3ff; \
2529 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2530 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2531 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2532 if (GFX.Z1 > *d && b) \
2534 TYPE theColor = COLORFUNC; \
2535 *p = (FUNC) | ALPHA_BITS_MASK; \
2538 AA += aa, p++, d++; \
2540 } while (x != endx); \
2546 int X = (AA + BB) >> 8; \
2549 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2555 if (((X | Y) & ~0x3ff) == 0) \
2557 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2558 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2559 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2560 if (GFX.Z1 > *d && b) \
2562 TYPE theColor = COLORFUNC; \
2563 *p = (FUNC) | ALPHA_BITS_MASK; \
2567 else if (PPU.Mode7Repeat == 3) \
2569 X = (x + HOffset) & 7; \
2570 Y = (yy + CentreY) & 7; \
2571 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2572 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2573 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2574 if (GFX.Z1 > *d && b) \
2576 TYPE theColor = COLORFUNC; \
2577 *p = (FUNC) | ALPHA_BITS_MASK; \
2581 AA += aa; p++; d++; \
2583 } while (x != endx); \
2586 else if (!PPU.Mode7Repeat) \
2588 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2589 /* the location of one point in the _sampled_ image, and weight them according */ \
2590 /* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
2593 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2594 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2595 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2596 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2597 /* You can think of this as a kind of mipmapping. */ \
2598 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2600 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2602 uint32 xPos = AA + BB; \
2603 uint32 xPix = xPos >> 8; \
2604 uint32 yPos = CC + DD; \
2605 uint32 yPix = yPos >> 8; \
2606 uint32 X = xPix & 0x3ff; \
2607 uint32 Y = yPix & 0x3ff; \
2608 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2609 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2610 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2611 if (GFX.Z1 > *d && b) \
2613 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2614 uint32 X10 = (xPix + dir) & 0x3ff; \
2615 uint32 Y01 = (yPix + dir) & 0x3ff; \
2616 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2617 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2618 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2619 uint32 p1 = COLORFUNC; \
2620 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2621 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2622 uint32 p2 = COLORFUNC; \
2623 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2624 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2625 uint32 p4 = COLORFUNC; \
2626 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2627 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2628 uint32 p3 = COLORFUNC; \
2629 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2630 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2631 uint32 Xdel = (xPos >> 3) & 0x1F; \
2632 uint32 Ydel = (yPos >> 3) & 0x1F; \
2633 uint32 XY = (Xdel*Ydel) >> 5; \
2634 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2635 uint32 area2 = Xdel - XY; \
2636 uint32 area3 = Ydel - XY; \
2637 uint32 area4 = XY; \
2638 uint32 tempColor = ((area1 * p1) + \
2641 (area4 * p4)) >> 5; \
2642 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2643 *p = (FUNC) | ALPHA_BITS_MASK; \
2649 /* The oversampling method: get the colors at four corners of a square */ \
2650 /* in the _displayed_ image, and average them. It's sharp and clean, but */ \
2651 /* gives the usual huge pixels when the source image gets "close." */ \
2653 /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2654 uint32 aaDelX = aa >> 1; \
2655 uint32 ccDelX = cc >> 1; \
2656 uint32 bbDelY = l->MatrixB >> 1; \
2657 uint32 ddDelY = l->MatrixD >> 1; \
2658 /* Offset the location within the source image so that the four sampled points */ \
2659 /* center around where the single point would otherwise have been drawn. */ \
2660 BB -= (bbDelY >> 1); \
2661 DD -= (ddDelY >> 1); \
2662 AA -= (aaDelX >> 1); \
2663 CC -= (ccDelX >> 1); \
2664 uint32 BB10 = BB + aaDelX; \
2665 uint32 BB01 = BB + bbDelY; \
2666 uint32 BB11 = BB + aaDelX + bbDelY; \
2667 uint32 DD10 = DD + ccDelX; \
2668 uint32 DD01 = DD + ddDelY; \
2669 uint32 DD11 = DD + ccDelX + ddDelY; \
2670 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2672 uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2673 uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2674 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2675 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2676 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2677 if (GFX.Z1 > *d && b) \
2679 /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2680 /* source image that we're going to examine. */ \
2681 uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2682 uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2683 uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2684 uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2685 uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2686 uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2687 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2688 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2689 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2690 TYPE p1 = COLORFUNC; \
2691 b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2692 TYPE p2 = COLORFUNC; \
2693 b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2694 TYPE p3 = COLORFUNC; \
2695 b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2696 TYPE p4 = COLORFUNC; \
2697 TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2698 *p = (FUNC) | ALPHA_BITS_MASK; \
2706 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2708 uint32 xPos = AA + BB; \
2709 uint32 xPix = xPos >> 8; \
2710 uint32 yPos = CC + DD; \
2711 uint32 yPix = yPos >> 8; \
2716 if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2722 if (((X | Y) & ~0x3ff) == 0) \
2724 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2725 uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2726 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2727 if (GFX.Z1 > *d && b) \
2729 /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2730 uint32 X10 = (xPix + dir) & 0x3ff; \
2731 uint32 Y01 = (yPix + dir) & 0x3ff; \
2732 uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2733 uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2734 uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2735 uint32 p1 = COLORFUNC; \
2736 p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2737 b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2738 uint32 p2 = COLORFUNC; \
2739 p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2740 b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2741 uint32 p4 = COLORFUNC; \
2742 p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2743 b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2744 uint32 p3 = COLORFUNC; \
2745 p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2746 /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2747 uint32 Xdel = (xPos >> 3) & 0x1F; \
2748 uint32 Ydel = (yPos >> 3) & 0x1F; \
2749 uint32 XY = (Xdel*Ydel) >> 5; \
2750 uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2751 uint32 area2 = Xdel - XY; \
2752 uint32 area3 = Ydel - XY; \
2753 uint32 area4 = XY; \
2754 uint32 tempColor = ((area1 * p1) + \
2757 (area4 * p4)) >> 5; \
2758 TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2759 *p = (FUNC) | ALPHA_BITS_MASK; \
2765 if (PPU.Mode7Repeat == 3) \
2767 X = (x + HOffset) & 7; \
2768 Y = (yy + CentreY) & 7; \
2769 uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2770 GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2771 if (GFX.Z1 > *d && b) \
2773 TYPE theColor = COLORFUNC; \
2774 *p = (FUNC) | ALPHA_BITS_MASK; \
2784 STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2786 register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2787 ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2788 ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2789 ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2790 register uint32 y = (A & TWO_LOW_BITS_MASK) +
2791 (B & TWO_LOW_BITS_MASK) +
2792 (C & TWO_LOW_BITS_MASK) +
2793 (D & TWO_LOW_BITS_MASK);
2794 y = (y>>2) & TWO_LOW_BITS_MASK;
2798 void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2800 RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2803 void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2805 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2806 (*(d + GFX.DepthDelta) != 1 ?
2807 (COLOR_ADD (theColor,
2809 (COLOR_ADD (theColor,
2810 GFX.FixedColour))) :
2811 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2814 void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2816 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2817 (*(d + GFX.DepthDelta) != 1 ?
2818 COLOR_ADD1_2 (theColor,
2820 COLOR_ADD (theColor,
2822 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2825 void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2827 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2828 (*(d + GFX.DepthDelta) != 1 ?
2829 COLOR_SUB (theColor,
2831 COLOR_SUB (theColor,
2833 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2836 void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2838 RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2839 (*(d + GFX.DepthDelta) != 1 ?
2840 COLOR_SUB1_2 (theColor,
2842 COLOR_SUB (theColor,
2844 theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2847 #define _BUILD_SETUP(F) \
2848 GFX.BuildPixel = BuildPixel##F; \
2849 GFX.BuildPixel2 = BuildPixel2##F; \
2850 GFX.DecomposePixel = DecomposePixel##F; \
2851 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2852 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2853 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2854 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2855 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2856 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2857 MAX_RED = MAX_RED_##F; \
2858 MAX_GREEN = MAX_GREEN_##F; \
2859 MAX_BLUE = MAX_BLUE_##F; \
2860 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2861 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2862 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2863 GREEN_LOW_BIT_MASK_##F | \
2864 BLUE_LOW_BIT_MASK_##F); \
2865 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2866 GREEN_HI_BIT_MASK_##F | \
2867 BLUE_HI_BIT_MASK_##F); \
2868 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2869 GREEN_HI_BIT_MASK_##F | \
2870 BLUE_HI_BIT_MASK_##F) << 1); \
2871 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2872 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2873 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2874 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2875 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2876 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2877 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2878 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2879 ~TWO_LOW_BITS_MASK ) >> 2);
2881 void RenderScreen (uint8 *Screen, bool8_32 sub, bool8_32 force_no_add, uint8 D)
2893 GFX.pCurrentClip = &IPPU.Clip [0];
2894 BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2895 BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2896 BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2897 BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2898 OB = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2902 GFX.pCurrentClip = &IPPU.Clip [1];
2903 BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2904 BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2905 BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2906 BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2907 OB = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2910 sub |= force_no_add;
2912 if (PPU.BGMode <= 1)
2916 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2921 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2922 DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2926 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2927 DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2931 SelectTileRenderer (sub || !SUB_OR_ADD(2));
2932 DrawBackground (PPU.BGMode, 2, D + 3,
2933 (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2935 if (BG3 && PPU.BGMode == 0)
2937 SelectTileRenderer (sub || !SUB_OR_ADD(3));
2938 DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2941 else if (PPU.BGMode != 7)
2945 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2950 SelectTileRenderer (sub || !SUB_OR_ADD(0));
2951 DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2953 if (PPU.BGMode != 6 && BG1)
2955 SelectTileRenderer (sub || !SUB_OR_ADD(1));
2956 DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2963 SelectTileRenderer (sub || !SUB_OR_ADD(4));
2966 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2970 if (Memory.FillRAM [0x2133] & 0x40)
2972 GFX.Mode7Mask = 0x7f;
2973 GFX.Mode7PriorityMask = 0x80;
2974 Mode7Depths [0] = 5 + D;
2975 Mode7Depths [1] = 9 + D;
2980 GFX.Mode7Mask = 0xff;
2981 GFX.Mode7PriorityMask = 0;
2982 Mode7Depths [0] = 5 + D;
2983 Mode7Depths [1] = 5 + D;
2986 if (sub || !SUB_OR_ADD(0))
2988 if (!Settings.Mode7Interpolate)
2989 DrawBGMode7Background16 (Screen, bg);
2991 DrawBGMode7Background16_i (Screen, bg);
2995 if (GFX.r2131 & 0x80)
2997 if (GFX.r2131 & 0x40)
2999 if (!Settings.Mode7Interpolate)
3000 DrawBGMode7Background16Sub1_2 (Screen, bg);
3002 DrawBGMode7Background16Sub1_2_i (Screen, bg);
3006 if (!Settings.Mode7Interpolate)
3007 DrawBGMode7Background16Sub (Screen, bg);
3009 DrawBGMode7Background16Sub_i (Screen, bg);
3014 if (GFX.r2131 & 0x40)
3016 if (!Settings.Mode7Interpolate)
3017 DrawBGMode7Background16Add1_2 (Screen, bg);
3019 DrawBGMode7Background16Add1_2_i (Screen, bg);
3023 if (!Settings.Mode7Interpolate)
3024 DrawBGMode7Background16Add (Screen, bg);
3026 DrawBGMode7Background16Add_i (Screen, bg);
3036 void DisplayChar (uint8 *Screen, uint8 c)
3038 int line = (((c & 0x7f) - 32) >> 4) * font_height;
3039 int offset = (((c & 0x7f) - 32) & 15) * font_width;
3041 if (Settings.SixteenBit)
3045 uint16 *s = (uint16 *) Screen;
3046 for (h = 0; h < font_height; h++, line++,
3047 s += GFX.PPL - font_width)
3049 for (w = 0; w < font_width; w++, s++)
3051 uint8 p = font [line][offset + w];
3066 for (h = 0; h < font_height; h++, line++,
3067 s += GFX.PPL - font_width)
3069 for (w = 0; w < font_width; w++, s++)
3071 uint8 p = font [line][offset + w];
3084 static void S9xDisplayFrameRate ()
3086 uint8 *Screen = GFX.Screen + 2 +
3087 (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch2;
3091 sprintf (string, "%02d/%02d", IPPU.DisplayedRenderedFrameCount,
3092 (int) Memory.ROMFramesPerSecond);
3096 Screen += (font_width - 1) * sizeof(uint16);
3098 for (i = 0; i < len; i++)
3100 DisplayChar (Screen, string [i]);
3101 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
3106 static void S9xDisplayString (const char *string)
3108 uint8 *Screen = GFX.Screen + 2 +
3109 (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch2;
3110 int len = strlen (string);
3111 int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
3115 for (i = 0; i < len; i++, char_count++)
3117 if (char_count >= max_chars || string [i] < 32)
3119 Screen -= Settings.SixteenBit ?
3120 (font_width - 1) * sizeof (uint16) * max_chars :
3121 (font_width - 1) * max_chars;
3122 Screen += font_height * GFX.Pitch;
3123 if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
3125 char_count -= max_chars;
3127 if (string [i] < 32)
3129 DisplayChar (Screen, string [i]);
3130 Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
3135 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
3141 unsigned char *memoryfillram = Memory.FillRAM;
3143 // get local copies of vid registers to be used later
3144 GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN
3145 GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
3146 GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
3147 GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
3149 // If external sync is off and
3150 // main screens have not been configured the same as the sub screen and
3151 // color addition and subtraction has been diabled then
3153 // anything else it is 0
3154 GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
3155 (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
3156 (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
3158 // If sprite data has been changed then go through and
3159 // refresh the sprites.
3160 if (IPPU.OBJChanged)
3165 if (PPU.RecomputeClipWindows)
3167 ComputeClipWindows ();
3168 PPU.RecomputeClipWindows = FALSE;
3171 GFX.StartY = IPPU.PreviousLine;
3172 if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
3173 GFX.EndY = PPU.ScreenHeight - 1;
3175 uint32 starty = GFX.StartY;
3176 uint32 endy = GFX.EndY;
3178 #ifndef RC_OPTIMIZED
3179 if (Settings.SupportHiRes &&
3180 (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace))
3182 if (PPU.BGMode == 5 || PPU.BGMode == 6)
3184 IPPU.RenderedScreenWidth = 512;
3187 if (IPPU.LatchedInterlace)
3189 starty = GFX.StartY * 2;
3190 endy = GFX.EndY * 2 + 1;
3192 if (!IPPU.DoubleWidthPixels)
3194 // The game has switched from lo-res to hi-res mode part way down
3195 // the screen. Scale any existing lo-res pixels on screen
3197 if (Settings.SixteenBit)
3200 #if defined (USE_GLIDE) || defined (USE_OPENGL)
3203 (Settings.GlideEnable && GFX.Pitch == 512) ||
3206 (Settings.OpenGLEnable && GFX.Pitch == 512) ||
3210 // Have to back out of the speed up hack where the low res.
3211 // SNES image was rendered into a 256x239 sized buffer,
3212 // ignoring the true, larger size of the buffer.
3214 for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
3216 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3217 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.RealPitch) + 510;
3218 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3221 GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
3222 GFX.PPL = GFX.Pitch >> 1;
3223 GFX.PPLx2 = GFX.Pitch;
3224 GFX.ZPitch = GFX.PPL;
3228 for (register uint32 y = 0; y < GFX.StartY; y++)
3230 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3231 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3232 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3239 for (register uint32 y = 0; y < GFX.StartY; y++)
3241 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3242 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3243 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3248 IPPU.DoubleWidthPixels = TRUE;
3251 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3253 uint32 black = BLACK | (BLACK << 16);
3255 // Are we worrying about transparencies?
3256 if (Settings.Transparency && Settings.SixteenBit)
3260 GFX.r2131 = 0x5f; //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3261 GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3262 Memory.FillRAM [0x212d]) & 15;
3263 GFX.r212c &= ~GFX.r212d; // make sure the main BG reg is the reverse of the sub BG reg
3264 GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3267 // Check to see if any transparency effects are currently in use
3268 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3269 (GFX.r2130 & 0x30) != 0x30 &&
3270 !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3272 // transparency effects in use, so lets get busy!
3273 struct ClipData *pClip;
3275 GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3276 IPPU.XB [PPU.FixedColourGreen],
3277 IPPU.XB [PPU.FixedColourBlue]);
3278 fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3279 // Clear the z-buffer, marking areas 'covered' by the fixed
3280 // colour as depth 1.
3281 pClip = &IPPU.Clip [1];
3283 // Clear the z-buffer
3285 if (pClip->Count [5])
3288 // Colour window enabled.
3291 for (uint32 y = starty; y <= endy; y++)
3294 ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3295 IPPU.RenderedScreenWidth);
3296 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3297 IPPU.RenderedScreenWidth);
3299 if (IPPU.Clip [0].Count [5])
3301 memset ((GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth);
3303 for (uint32 c = 0; c < pClip->Count [5]; c++)
3305 if (pClip->Right [c][5] > pClip->Left [c][5])
3307 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3308 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3309 if (IPPU.Clip [0].Count [5])
3311 // Blast, have to clear the sub-screen to the fixed-colour
3312 // because there is a colour window in effect clipping
3313 // the main screen that will allow the sub-screen
3314 // 'underneath' to show through.
3315 memset ((GFX.SubScreen + y * GFX.Pitch2) + pClip->Left [c][5] * x2,
3317 pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3323 #else // NOT RC_OPTIMIZED
3324 // loop around all of the lines being updated
3325 for (uint32 y = starty; y <= endy; y++)
3327 // Clear the subZbuffer
3328 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3329 IPPU.RenderedScreenWidth>>2);
3330 // Clear the Zbuffer
3331 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3332 IPPU.RenderedScreenWidth>>2);
3334 // if there is clipping then clear subscreen to a black color
3335 if (IPPU.Clip [0].Count [5])
3337 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth>>1);
3340 // loop through all window clippings
3341 for (uint32 c = 0; c < pClip->Count [5]; c++)
3343 if (pClip->Right [c][5] > pClip->Left [c][5])
3345 memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3346 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3347 if (IPPU.Clip [0].Count [5])
3349 // Blast, have to clear the sub-screen to the fixed-colour
3350 // because there is a colour window in effect clipping
3351 // the main screen that will allow the sub-screen
3352 // 'underneath' to show through.
3354 register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch2);
3355 register uint16 *q = p + pClip->Right [c][5] * x2;
3356 p += pClip->Left [c][5] * x2;
3359 *p++ = (uint16) GFX.FixedColour;
3365 //#undef RC_OPTIMIZED
3370 // No windows are clipping the main screen
3371 // this simplifies the screen clearing process
3374 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3377 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3378 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3382 for (uint32 y = starty; y <= endy; y++)
3384 ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3385 IPPU.RenderedScreenWidth);
3386 memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3387 IPPU.RenderedScreenWidth);
3391 if (IPPU.Clip [0].Count [5])
3393 // Blast, have to clear the sub-screen to the fixed-colour
3394 // because there is a colour window in effect clipping
3395 // the main screen that will allow the sub-screen
3396 // 'underneath' to show through.
3397 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3399 memset ((GFX.SubScreen + starty * GFX.Pitch2),
3400 GFX.FixedColour | (GFX.FixedColour << 16),
3401 GFX.Pitch2 * (endy - starty - 1));
3405 for (uint32 y = starty; y <= endy; y++)
3407 memset ((GFX.SubScreen + y * GFX.Pitch2),
3408 GFX.FixedColour | (GFX.FixedColour << 16),
3409 IPPU.RenderedScreenWidth);
3414 #else // NOT RC_OPTIMIZED
3415 // loop through all of the lines to be updated
3416 for (uint32 y = starty; y <= endy; y++)
3418 // Clear the Zbuffer
3419 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3420 IPPU.RenderedScreenWidth>>2);
3421 // clear the sub Zbuffer to 1
3422 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3423 IPPU.RenderedScreenWidth>>2);
3424 if (IPPU.Clip [0].Count [5])
3426 // Blast, have to clear the sub-screen to the fixed-colour
3427 // because there is a colour window in effect clipping
3428 // the main screen that will allow the sub-screen
3429 // 'underneath' to show through.
3432 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), fixedColour,
3433 IPPU.RenderedScreenWidth>>1);
3440 if (ANYTHING_ON_SUB)
3442 GFX.DB = GFX.SubZBuffer;
3443 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3446 if (IPPU.Clip [0].Count [5])
3448 for (uint32 y = starty; y <= endy; y++)
3450 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3451 register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3452 register uint8 *e = d + SNES_WIDTH;
3457 *p = *(p + GFX.Delta);
3466 GFX.DB = GFX.ZBuffer;
3467 RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3470 uint32 back = IPPU.ScreenColors [0];
3475 pClip = &IPPU.Clip [0];
3477 for (uint32 y = starty; y <= endy; y++)
3479 if (!(Count = pClip->Count [5]))
3486 for (uint32 b = 0; b < Count; b++)
3488 if (pClip->Count [5])
3490 Left = pClip->Left [b][5] * x2;
3491 Right = pClip->Right [b][5] * x2;
3496 if (GFX.r2131 & 0x80)
3498 if (GFX.r2131 & 0x40)
3500 // Subtract, halving the result.
3501 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3502 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3503 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3504 register uint8 *e = d + Right;
3505 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3515 *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3530 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3531 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3532 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3533 register uint8 *e = d + Right;
3534 uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3544 *p = COLOR_SUB (back, *(p + GFX.Delta));
3558 if (GFX.r2131 & 0x40)
3560 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3561 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3562 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3563 register uint8 *e = d + Right;
3564 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3573 *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3588 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3589 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3590 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3591 register uint8 *e = d + Right;
3592 uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3601 *p = COLOR_ADD (back, *(p + GFX.Delta));
3615 if (!pClip->Count [5])
3617 // The backdrop has not been cleared yet - so
3618 // copy the sub-screen to the main screen
3619 // or fill it with the back-drop colour if the
3620 // sub-screen is clear.
3621 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3622 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3623 register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3624 register uint8 *e = d + Right;
3633 *p = *(p + GFX.Delta);
3635 *p = GFX.FixedColour;
3652 // Subscreen not being added to back
3653 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3654 pClip = &IPPU.Clip [0];
3656 if (pClip->Count [5])
3658 for (uint32 y = starty; y <= endy; y++)
3660 for (uint32 b = 0; b < pClip->Count [5]; b++)
3662 uint32 Left = pClip->Left [b][5] * x2;
3663 uint32 Right = pClip->Right [b][5] * x2;
3664 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3665 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3666 register uint8 *e = d + Right;
3680 for (uint32 y = starty; y <= endy; y++)
3682 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3683 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3684 register uint8 *e = d + 256 * x2;
3704 // 16bit and transparency but currently no transparency effects in
3707 // get the back colour of the current screen
3708 uint32 back = IPPU.ScreenColors [0] |
3709 (IPPU.ScreenColors [0] << 16);
3711 // if forceblanking in use then use black instead of the back color
3712 if (PPU.ForcedBlanking)
3715 // not sure what Clip is used for yet
3716 // could be a check to see if there is any clipping present?
3717 if (IPPU.Clip [0].Count[5])
3721 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3723 memset (GFX.Screen + starty * GFX.Pitch2, black,
3724 GFX.Pitch2 * (endy - starty - 1));
3728 for (uint32 y = starty; y <= endy; y++)
3730 memset (GFX.Screen + y * GFX.Pitch2, black,
3734 for (uint32 y = starty; y <= endy; y++)
3736 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3738 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3741 memset ((GFX.Screen + y * GFX.Pitch2) + IPPU.Clip [0].Left [c][5] * x2,
3743 IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3748 // loop through all of the lines that are going to be updated as part of this screen update
3749 for (uint32 y = starty; y <= endy; y++)
3751 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), black,
3752 IPPU.RenderedScreenWidth>>1);
3756 for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3758 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3760 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2); // get pointer to current line in screen buffer
3761 register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3762 p += IPPU.Clip [0].Left [c][5] * x2;
3765 *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3775 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3777 memset (GFX.Screen + starty * GFX.Pitch2, back,
3778 GFX.Pitch2 * (endy - starty - 1));
3782 for (uint32 y = starty; y <= endy; y++)
3784 memset (GFX.Screen + y * GFX.Pitch2, back,
3789 // there is no clipping to worry about so just fill with the back colour
3790 for (uint32 y = starty; y <= endy; y++)
3792 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3793 IPPU.RenderedScreenWidth>>1);
3798 // If Forced blanking is not in effect
3799 if (!PPU.ForcedBlanking)
3802 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3804 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3805 GFX.ZPitch * (endy - starty - 1));
3809 for (uint32 y = starty; y <= endy; y++)
3811 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3816 // Clear the Zbuffer for each of the lines which are going to be updated
3817 for (uint32 y = starty; y <= endy; y++)
3819 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3823 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3824 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3828 else // Transparencys are disabled, ahh lovely ... nice and easy.
3831 if (Settings.SixteenBit)
3834 // get back colour to be used in clearing the screen
3835 register uint32 back;
3836 if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3837 (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3839 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3840 (IPPU.XB[PPU.FixedColourGreen] << 6) |
3841 (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3842 back = (back << 16) | back;
3846 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3849 // if Forcedblanking in use then back colour becomes black
3850 if (PPU.ForcedBlanking)
3854 SelectTileRenderer (TRUE); //selects the tile renderers to be used
3855 // TRUE means to use the default
3856 // FALSE means use best renderer based on current
3857 // graphics register settings
3860 // now clear all graphics lines which are being updated using the back colour
3861 for (register uint32 y = starty; y <= endy; y++)
3863 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3864 IPPU.RenderedScreenWidth>>1);
3868 else // Settings.SixteenBit == false
3870 // because we are in 8 bit we can just use 0 to clear the screen
3871 // this means we can use the Zero Memory function
3873 // Loop through all lines being updated and clear the pixels to 0
3874 for (uint32 y = starty; y <= endy; y++)
3876 ZeroMemory (GFX.Screen + y * GFX.Pitch2,
3877 IPPU.RenderedScreenWidth);
3881 if (!PPU.ForcedBlanking)
3883 // Loop through all lines being updated and clear the
3884 // zbuffer for each of the lines
3885 for (uint32 y = starty; y <= endy; y++)
3887 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3888 IPPU.RenderedScreenWidth>>2);
3890 GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3891 GFX.pCurrentClip = &IPPU.Clip [0];
3893 // Define an inline function to handle clipping
3894 #define FIXCLIP(n) \
3895 if (GFX.r212c & (1 << (n))) \
3896 GFX.pCurrentClip = &IPPU.Clip [0]; \
3898 GFX.pCurrentClip = &IPPU.Clip [1]
3900 // Define an inline function to handle which BGs are being displayed
3901 #define DISPLAY(n) \
3902 (!(PPU.BG_Forced & n) && \
3903 (GFX.r212c & n) || \
3904 ((GFX.r212d & n) && subadd))
3906 uint8 subadd = GFX.r2131 & 0x3f;
3908 // go through all BGS are check if they need to be displayed
3909 bool8_32 BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3910 bool8_32 BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3911 bool8_32 BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3912 bool8_32 BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3913 bool8_32 OB = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3915 if (PPU.BGMode <= 1)
3917 // screen modes 0 and 1
3926 DrawBackground (PPU.BGMode, 0, 10, 14);
3931 DrawBackground (PPU.BGMode, 1, 9, 13);
3936 DrawBackground (PPU.BGMode, 2, 3,
3937 (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3939 if (BG3 && PPU.BGMode == 0)
3942 DrawBackground (PPU.BGMode, 3, 2, 5);
3945 else if (PPU.BGMode != 7)
3947 // screen modes 2 and up but not mode 7
3956 DrawBackground (PPU.BGMode, 0, 5, 13);
3958 if (BG1 && PPU.BGMode != 6)
3961 DrawBackground (PPU.BGMode, 1, 2, 9);
3972 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3976 if (Memory.FillRAM [0x2133] & 0x40)
3978 GFX.Mode7Mask = 0x7f;
3979 GFX.Mode7PriorityMask = 0x80;
3980 Mode7Depths [0] = 5;
3981 Mode7Depths [1] = 9;
3986 GFX.Mode7Mask = 0xff;
3987 GFX.Mode7PriorityMask = 0;
3988 Mode7Depths [0] = 5;
3989 Mode7Depths [1] = 5;
3994 if (!Settings.SixteenBit)
3995 DrawBGMode7Background (GFX.Screen, bg);
3999 if (!Settings.Mode7Interpolate)
4001 DrawBGMode7Background16 (GFX.Screen, bg);
4005 DrawBGMode7Background16_i (GFX.Screen, bg);
4012 #ifndef RC_OPTIMIZE // no hi res
4013 if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
4015 if (IPPU.DoubleWidthPixels)
4017 // Mixure of background modes used on screen - scale width
4018 // of all non-mode 5 and 6 pixels.
4020 if (Settings.SixteenBit)
4023 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
4025 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
4026 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
4027 for (register int x = 255; x >= 0; x--, p--, q -= 2)
4034 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
4036 register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
4037 register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
4038 for (register int x = 255; x >= 0; x--, p--, q -= 2)
4045 if (IPPU.LatchedInterlace)
4047 // Interlace is enabled - double the height of all non-mode 5 and 6
4049 for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
4051 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch2),
4052 (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch2),
4058 IPPU.PreviousLine = IPPU.CurrentLine;
4061 #ifdef GFX_MULTI_FORMAT
4063 #define _BUILD_PIXEL(F) \
4064 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
4066 return (BUILD_PIXEL_##F(R,G,B)); \
4068 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
4070 return (BUILD_PIXEL2_##F(R,G,B)); \
4072 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
4074 DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
4077 _BUILD_PIXEL(RGB565)
4078 _BUILD_PIXEL(RGB555)
4079 _BUILD_PIXEL(BGR565)
4080 _BUILD_PIXEL(BGR555)
4081 _BUILD_PIXEL(GBR565)
4082 _BUILD_PIXEL(GBR555)
4083 _BUILD_PIXEL(RGB5551)
4085 bool8_32 S9xSetRenderPixelFormat (int format)
4087 extern uint32 current_graphic_format;
4089 current_graphic_format = format;
4094 _BUILD_SETUP(RGB565)
4097 _BUILD_SETUP(RGB555)
4100 _BUILD_SETUP(BGR565)
4103 _BUILD_SETUP(BGR555)
4106 _BUILD_SETUP(GBR565)
4109 _BUILD_SETUP(GBR555)
4112 _BUILD_SETUP(RGB5551)