fix most compiler code style warnings
[drnoksnes] / gfx.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
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).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
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.
25  *
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.
29  *
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.
33  *
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
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41
42 #include <stdarg.h>
43
44 #include "snes9x.h"
45
46 #include "memmap.h"
47 #include "ppu.h"
48 #include "cpuexec.h"
49 #include "display.h"
50 #include "gfx.h"
51 #include "apu.h"
52 #include "cheats.h"
53 #include "tile.h"
54 #include "misc.h"
55
56 #define USE_CRAZY_OPTS
57
58 #define M7 19
59 #define M8 19
60
61 void ComputeClipWindows ();
62 static void S9xDisplayFrameRate ();
63 static void S9xDisplayString (const char *string);
64
65 extern uint8 BitShifts[8][4];
66 extern uint8 TileShifts[8][4];
67 extern uint8 PaletteShifts[8][4];
68 extern uint8 PaletteMasks[8][4];
69 extern uint8 Depths[8][4];
70 extern uint8 BGSizes [2];
71
72 extern NormalTileRenderer DrawTilePtr;
73 extern ClippedTileRenderer DrawClippedTilePtr;
74 extern NormalTileRenderer DrawHiResTilePtr;
75 extern ClippedTileRenderer DrawHiResClippedTilePtr;
76 extern LargePixelRenderer DrawLargePixelPtr;
77
78 extern struct SBG BG;
79
80 extern struct SLineData LineData[240];
81 extern struct SLineMatrixData LineMatrixData [240];
82
83 extern uint8  Mode7Depths [2];
84
85 #define ON_MAIN(N) \
86 (GFX.r212c & (1 << (N)) && \
87  !(PPU.BG_Forced & (1 << (N))))
88
89 #define SUB_OR_ADD(N) \
90 (GFX.r2131 & (1 << (N)))
91
92 #define ON_SUB(N) \
93 ((GFX.r2130 & 0x30) != 0x30 && \
94  (GFX.r2130 & 2) && \
95  (GFX.r212d & (1 << N)) && \
96  !(PPU.BG_Forced & (1 << (N))))
97
98 #define ANYTHING_ON_SUB \
99 ((GFX.r2130 & 0x30) != 0x30 && \
100  (GFX.r2130 & 2) && \
101  (GFX.r212d & 0x1f))
102
103 #define ADD_OR_SUB_ON_ANYTHING \
104 (GFX.r2131 & 0x3f)
105
106 #define BLACK BUILD_PIXEL(0,0,0)
107
108 bool8_32 S9xGraphicsInit ()
109 {
110     register uint32 PixelOdd = 1;
111     register uint32 PixelEven = 2;
112
113 #ifdef GFX_MULTI_FORMAT
114     if (GFX.BuildPixel == NULL)
115         S9xSetRenderPixelFormat (RGB565);
116 #endif
117
118     for (uint8 bitshift = 0; bitshift < 4; bitshift++)
119     {
120         for (register int i = 0; i < 16; i++)
121         {
122             register uint32 h = 0;
123             register uint32 l = 0;
124
125 #if defined(LSB_FIRST)
126             if (i & 8)
127                 h |= PixelOdd;
128             if (i & 4)
129                 h |= PixelOdd << 8;
130             if (i & 2)
131                 h |= PixelOdd << 16;
132             if (i & 1)
133                 h |= PixelOdd << 24;
134             if (i & 8)
135                 l |= PixelOdd;
136             if (i & 4)
137                 l |= PixelOdd << 8;
138             if (i & 2)
139                 l |= PixelOdd << 16;
140             if (i & 1)
141                 l |= PixelOdd << 24;
142 #else
143             if (i & 8)
144                 h |= (PixelOdd << 24);
145             if (i & 4)
146                 h |= (PixelOdd << 16);
147             if (i & 2)
148                 h |= (PixelOdd << 8);
149             if (i & 1)
150                 h |= PixelOdd;
151             if (i & 8)
152                 l |= (PixelOdd << 24);
153             if (i & 4)
154                 l |= (PixelOdd << 16);
155             if (i & 2)
156                 l |= (PixelOdd << 8);
157             if (i & 1)
158                 l |= PixelOdd;
159 #endif
160
161             odd_high[bitshift][i] = h;
162             odd_low[bitshift][i] = l;
163             h = l = 0;
164
165 #if defined(LSB_FIRST)
166             if (i & 8)
167                 h |= PixelEven;
168             if (i & 4)
169                 h |= PixelEven << 8;
170             if (i & 2)
171                 h |= PixelEven << 16;
172             if (i & 1)
173                 h |= PixelEven << 24;
174             if (i & 8)
175                 l |= PixelEven;
176             if (i & 4)
177                 l |= PixelEven << 8;
178             if (i & 2)
179                 l |= PixelEven << 16;
180             if (i & 1)
181                 l |= PixelEven << 24;
182 #else
183             if (i & 8)
184                 h |= (PixelEven << 24);
185             if (i & 4)
186                 h |= (PixelEven << 16);
187             if (i & 2)
188                 h |= (PixelEven << 8);
189             if (i & 1)
190                 h |= PixelEven;
191             if (i & 8)
192                 l |= (PixelEven << 24);
193             if (i & 4)
194                 l |= (PixelEven << 16);
195             if (i & 2)
196                 l |= (PixelEven << 8);
197             if (i & 1)
198                 l |= PixelEven;
199 #endif
200
201             even_high[bitshift][i] = h;
202             even_low[bitshift][i] = l;
203         }
204         PixelEven <<= 2;
205         PixelOdd <<= 2;
206     }
207
208     GFX.InfoStringTimeout = 0;
209     GFX.InfoString = NULL;
210
211     PPU.BG_Forced = 0;
212     IPPU.OBJChanged = TRUE;
213     if (Settings.Transparency)
214         Settings.SixteenBit = TRUE;
215
216     IPPU.DirectColourMapsNeedRebuild = TRUE;
217     GFX.PixSize = 1;
218     if (Settings.SixteenBit)
219     {
220         DrawTilePtr = DrawTile16;
221         DrawClippedTilePtr = DrawClippedTile16;
222         DrawLargePixelPtr = DrawLargePixel16;
223         DrawHiResTilePtr= DrawHiResTile16;
224         DrawHiResClippedTilePtr = DrawHiResClippedTile16;
225         GFX.PPL = GFX.Pitch >> 1;
226         GFX.PPLx2 = GFX.Pitch;
227     }
228     else
229     {
230         DrawTilePtr = DrawTile;
231         DrawClippedTilePtr = DrawClippedTile;
232         DrawLargePixelPtr = DrawLargePixel;
233         DrawHiResTilePtr = DrawTile;
234         DrawHiResClippedTilePtr = DrawClippedTile;
235         GFX.PPL = GFX.Pitch;
236         GFX.PPLx2 = GFX.Pitch * 2;
237     }
238     S9xFixColourBrightness ();
239
240     if (Settings.SixteenBit)
241     {
242         if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
243             return (FALSE);
244
245         if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
246             !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
247         {
248             if (GFX.ZERO_OR_X2)
249             {
250                 free ((char *) GFX.ZERO_OR_X2);
251                 GFX.ZERO_OR_X2 = NULL;
252             }
253             if (GFX.X2)
254             {
255                 free ((char *) GFX.X2);
256                 GFX.X2 = NULL;
257             }
258             return (FALSE);
259         }
260         uint32 r, g, b;
261
262         // Build a lookup table that multiplies a packed RGB value by 2 with
263         // saturation.
264         for (r = 0; r <= MAX_RED; r++)
265         {
266             uint32 r2 = r << 1;
267             if (r2 > MAX_RED)
268                 r2 = MAX_RED;
269             for (g = 0; g <= MAX_GREEN; g++)
270             {
271                 uint32 g2 = g << 1;
272                 if (g2 > MAX_GREEN)
273                     g2 = MAX_GREEN;
274                 for (b = 0; b <= MAX_BLUE; b++)
275                 {
276                     uint32 b2 = b << 1;
277                     if (b2 > MAX_BLUE)
278                         b2 = MAX_BLUE;
279                     GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
280                     GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
281                 }
282             }
283         }
284         ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
285         ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
286         // Build a lookup table that if the top bit of the color value is zero
287         // then the value is zero, otherwise multiply the value by 2. Used by
288         // the color subtraction code.
289
290 #if defined(OLD_COLOUR_BLENDING)
291         for (r = 0; r <= MAX_RED; r++)
292         {
293             uint32 r2 = r;
294             if ((r2 & 0x10) == 0)
295                 r2 = 0;
296             else
297                 r2 = (r2 << 1) & MAX_RED;
298
299             for (g = 0; g <= MAX_GREEN; g++)
300             {
301                 uint32 g2 = g;
302                 if ((g2 & GREEN_HI_BIT) == 0)
303                     g2 = 0;
304                 else
305                     g2 = (g2 << 1) & MAX_GREEN;
306
307                 for (b = 0; b <= MAX_BLUE; b++)
308                 {
309                     uint32 b2 = b;
310                     if ((b2 & 0x10) == 0)
311                         b2 = 0;
312                     else
313                         b2 = (b2 << 1) & MAX_BLUE;
314
315                     GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
316                     GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
317                 }
318             }
319         }
320 #else
321         for (r = 0; r <= MAX_RED; r++)
322         {
323             uint32 r2 = r;
324             if ((r2 & 0x10) == 0)
325                 r2 = 0;
326             else
327                 r2 = (r2 << 1) & MAX_RED;
328
329             if (r2 == 0)
330                 r2 = 1;
331             for (g = 0; g <= MAX_GREEN; g++)
332             {
333                 uint32 g2 = g;
334                 if ((g2 & GREEN_HI_BIT) == 0)
335                     g2 = 0;
336                 else
337                     g2 = (g2 << 1) & MAX_GREEN;
338
339                 if (g2 == 0)
340                     g2 = 1;
341                 for (b = 0; b <= MAX_BLUE; b++)
342                 {
343                     uint32 b2 = b;
344                     if ((b2 & 0x10) == 0)
345                         b2 = 0;
346                     else
347                         b2 = (b2 << 1) & MAX_BLUE;
348
349                     if (b2 == 0)
350                         b2 = 1;
351                     GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
352                     GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
353                 }
354             }
355         }
356 #endif
357
358         // Build a lookup table that if the top bit of the color value is zero
359         // then the value is zero, otherwise its just the value.
360         for (r = 0; r <= MAX_RED; r++)
361         {
362             uint32 r2 = r;
363             if ((r2 & 0x10) == 0)
364                 r2 = 0;
365             else
366                 r2 &= ~0x10;
367
368             for (g = 0; g <= MAX_GREEN; g++)
369             {
370                 uint32 g2 = g;
371                 if ((g2 & GREEN_HI_BIT) == 0)
372                     g2 = 0;
373                 else
374                     g2 &= ~GREEN_HI_BIT;
375                 for (b = 0; b <= MAX_BLUE; b++)
376                 {
377                     uint32 b2 = b;
378                     if ((b2 & 0x10) == 0)
379                         b2 = 0;
380                     else
381                         b2 &= ~0x10;
382
383                     GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
384                     GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
385                 }
386             }
387         }
388     }
389     else
390     {
391         GFX.X2 = NULL;
392         GFX.ZERO_OR_X2 = NULL;
393         GFX.ZERO = NULL;
394     }
395
396     return (TRUE);
397 }
398
399 void S9xGraphicsDeinit (void)
400 {
401     // Free any memory allocated in S9xGraphicsInit
402     if (GFX.X2)
403     {
404         free ((char *) GFX.X2);
405         GFX.X2 = NULL;
406     }
407     if (GFX.ZERO_OR_X2)
408     {
409         free ((char *) GFX.ZERO_OR_X2);
410         GFX.ZERO_OR_X2 = NULL;
411     }
412     if (GFX.ZERO)
413     {
414         free ((char *) GFX.ZERO);
415         GFX.ZERO = NULL;
416     }
417 }
418
419 void S9xBuildDirectColourMaps ()
420 {
421     for (uint32 p = 0; p < 8; p++)
422     {
423         for (uint32 c = 0; c < 256; c++)
424         {
425 // XXX: Brightness
426             DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
427                                                    ((c & 0x38) >> 1) | (p & 2),
428                                                    ((c & 0xc0) >> 3) | (p & 4));
429         }
430     }
431     IPPU.DirectColourMapsNeedRebuild = FALSE;
432 }
433
434 void S9xStartScreenRefresh ()
435 {
436         if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0) {
437                 free(GFX.InfoString);
438                 GFX.InfoString = NULL;
439         }
440
441     if (IPPU.RenderThisFrame)
442     {
443 #ifndef _SNESPPC
444         if (!S9xInitUpdate ())
445         {
446             IPPU.RenderThisFrame = FALSE;
447             return;
448         }
449 #endif
450         IPPU.RenderedFramesCount++;
451         IPPU.PreviousLine = IPPU.CurrentLine = 0;
452         IPPU.MaxBrightness = PPU.Brightness;
453         IPPU.LatchedBlanking = PPU.ForcedBlanking;
454         IPPU.LatchedInterlace = (Memory.FillRAM[0x2133] & 1);
455         IPPU.RenderedScreenWidth = 256;
456         IPPU.RenderedScreenHeight = PPU.ScreenHeight;
457         IPPU.DoubleWidthPixels = FALSE;
458         GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
459         GFX.PPL = GFX.PPLx2 >> 1;
460         PPU.RecomputeClipWindows = TRUE;
461         GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
462         GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
463     }
464     if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0)
465     {
466         IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount;
467         IPPU.RenderedFramesCount = 0;
468         IPPU.FrameCount = 0;
469     }
470 }
471
472 void RenderLine (uint8 C)
473 {
474     if (IPPU.RenderThisFrame)
475     {
476
477         LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
478         LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
479         LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
480         LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
481
482         if (PPU.BGMode == 7)
483         {
484             struct SLineMatrixData *p = &LineMatrixData [C];
485             p->MatrixA = PPU.MatrixA;
486             p->MatrixB = PPU.MatrixB;
487             p->MatrixC = PPU.MatrixC;
488             p->MatrixD = PPU.MatrixD;
489             p->CentreX = PPU.CentreX;
490             p->CentreY = PPU.CentreY;
491         }
492         else
493         {
494 #ifndef RC_OPTIMIZED
495             if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
496                 PPU.BG[2].HOffset == 0xe000)
497             {
498                 LineData[C].BG[2].VOffset = 0xe1;
499                 LineData[C].BG[2].HOffset = 0;
500             }
501             else
502 #endif
503
504             {
505                 LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
506                 LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
507                 LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
508                 LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
509             }
510
511         }
512         IPPU.CurrentLine = C + 1;
513     }
514 }
515
516
517 void S9xEndScreenRefresh()
518 {
519     IPPU.HDMAStarted = FALSE;
520
521 //RC
522     if (IPPU.RenderThisFrame)
523     {
524         FLUSH_REDRAW ();
525         if (IPPU.ColorsChanged)
526         {
527             uint32 saved = PPU.CGDATA[0];
528             if (!Settings.SixteenBit)
529             {
530                         // Hack for Super Mario World - to get its sky blue
531                         // (It uses Fixed colour addition on the backdrop colour)
532                         if (!(Memory.FillRAM [0x2131] & 0x80) &&
533                                 (Memory.FillRAM[0x2131] & 0x20) &&
534                                 (PPU.FixedColourRed || PPU.FixedColourGreen ||
535                                  PPU.FixedColourBlue))
536                         {
537                                 PPU.CGDATA[0] = PPU.FixedColourRed |
538                                                 (PPU.FixedColourGreen << 5) |
539                                                 (PPU.FixedColourBlue << 10);
540                         }
541             }
542             IPPU.ColorsChanged = FALSE;
543                 
544             S9xSetPalette ();
545
546             PPU.CGDATA[0] = saved;
547         }
548             GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
549             GFX.PPL = GFX.PPLx2 >> 1;
550
551         if (Settings.DisplayFrameRate)
552             S9xDisplayFrameRate ();
553         if (GFX.InfoString)
554             S9xDisplayString (GFX.InfoString);
555
556         S9xDeinitUpdate (IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
557                          Settings.SixteenBit);
558     }
559 #ifndef RC_OPTIMIZED
560     S9xApplyCheats ();
561 #endif
562
563
564 #ifdef DEBUGGER
565     if (CPU.Flags & FRAME_ADVANCE_FLAG)
566     {
567         if (ICPU.FrameAdvanceCount)
568         {
569             ICPU.FrameAdvanceCount--;
570             IPPU.RenderThisFrame = TRUE;
571             IPPU.FrameSkip = 0;
572         }
573         else
574         {
575             CPU.Flags &= ~FRAME_ADVANCE_FLAG;
576             CPU.Flags |= DEBUG_MODE_FLAG;
577         }
578     }
579 #endif
580
581     if (CPU.SRAMModified)
582     {
583                 if (!CPU.AutoSaveTimer)
584                 {
585                         if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
586                         CPU.SRAMModified = FALSE;
587                 }
588                 else
589                 {
590                         if (!--CPU.AutoSaveTimer)
591                         {
592                                 S9xAutoSaveSRAM ();
593                                 CPU.SRAMModified = FALSE;
594                         }
595                 }
596     }
597 }
598
599 void S9xSetInfoString (const char * fmt, ...)
600 {
601         va_list ap;
602         va_start(ap, fmt);
603
604         if (vasprintf(&GFX.InfoString, fmt, ap) > 0) {
605                 GFX.InfoStringTimeout = 120;
606         } else {
607                 GFX.InfoString = 0;
608                 GFX.InfoStringTimeout = 0;
609         }
610
611     va_end(ap);
612 }
613
614 INLINE void SelectTileRenderer (bool8_32 normal)
615 {
616     if (normal)
617     {
618         DrawTilePtr = DrawTile16;
619         DrawClippedTilePtr = DrawClippedTile16;
620         DrawLargePixelPtr = DrawLargePixel16;
621     }
622     else
623     {
624         if (GFX.r2131 & 0x80)
625         {
626             if (GFX.r2131 & 0x40)
627             {
628                 if (GFX.r2130 & 2)
629                 {
630                     DrawTilePtr = DrawTile16Sub1_2;
631                     DrawClippedTilePtr = DrawClippedTile16Sub1_2;
632                 }
633                 else
634                 {
635                     // Fixed colour substraction
636                     DrawTilePtr = DrawTile16FixedSub1_2;
637                     DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
638                 }
639                 DrawLargePixelPtr = DrawLargePixel16Sub1_2;
640             }
641             else
642             {
643                 DrawTilePtr = DrawTile16Sub;
644                 DrawClippedTilePtr = DrawClippedTile16Sub;
645                 DrawLargePixelPtr = DrawLargePixel16Sub;
646             }
647         }
648         else
649         {
650             if (GFX.r2131 & 0x40)
651             {
652                 if (GFX.r2130 & 2)
653                 {
654                     DrawTilePtr = DrawTile16Add1_2;
655                     DrawClippedTilePtr = DrawClippedTile16Add1_2;
656                 }
657                 else
658                 {
659                     // Fixed colour addition
660                     DrawTilePtr = DrawTile16FixedAdd1_2;
661                     DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
662                 }
663                 DrawLargePixelPtr = DrawLargePixel16Add1_2;
664             }
665             else
666             {
667                 DrawTilePtr = DrawTile16Add;
668                 DrawClippedTilePtr = DrawClippedTile16Add;
669                 DrawLargePixelPtr = DrawLargePixel16Add;
670             }
671         }
672     }
673 }
674
675 void S9xSetupOBJ ()
676 {
677     int SmallSize;
678     int LargeSize;
679
680     switch (PPU.OBJSizeSelect)
681     {
682     case 0:
683         SmallSize = 8;
684         LargeSize = 16;
685         break;
686     case 1:
687         SmallSize = 8;
688         LargeSize = 32;
689         break;
690     case 2:
691         SmallSize = 8;
692         LargeSize = 64;
693         break;
694     case 3:
695         SmallSize = 16;
696         LargeSize = 32;
697         break;
698     case 4:
699         SmallSize = 16;
700         LargeSize = 64;
701         break;
702     case 5:
703     default:
704         SmallSize = 32;
705         LargeSize = 64;
706         break;
707     }
708
709     int C = 0;
710     
711     int FirstSprite = PPU.FirstSprite & 0x7f;
712     int S = FirstSprite;
713     do
714     {
715         int Size;
716         if (PPU.OBJ [S].Size)
717             Size = LargeSize;
718         else
719             Size = SmallSize;
720
721         long VPos = PPU.OBJ [S].VPos;
722
723         if (VPos >= PPU.ScreenHeight)
724             VPos -= 256;
725         if (PPU.OBJ [S].HPos < 256 && PPU.OBJ [S].HPos > -Size &&
726             VPos < PPU.ScreenHeight && VPos > -Size)
727         {
728             GFX.OBJList [C++] = S;
729             GFX.Sizes[S] = Size;
730             GFX.VPositions[S] = VPos;
731         }
732         S = (S + 1) & 0x7f;
733     } while (S != FirstSprite);
734
735     // Terminate the list
736     GFX.OBJList [C] = -1;
737     IPPU.OBJChanged = FALSE;
738 }
739
740 void DrawOBJS (bool8_32 OnMain = FALSE, uint8 D = 0)
741 {
742         uint32 O;
743     uint32 BaseTile, Tile;
744
745     CHECK_SOUND();
746
747     BG.BitShift = 4;
748     BG.TileShift = 5;
749     BG.TileAddress = PPU.OBJNameBase;
750     BG.StartPalette = 128;
751     BG.PaletteShift = 4;
752     BG.PaletteMask = 7;
753     BG.Buffer = IPPU.TileCache [TILE_4BIT];
754         BG.Buffered = IPPU.TileCached [TILE_4BIT];
755         BG.NameSelect = PPU.OBJNameSelect;
756     BG.DirectColourMode = FALSE;
757
758     GFX.PixSize = 1;
759
760     GFX.Z1 = D + 2;
761
762     int I = 0;
763     for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
764     {
765         int VPos = GFX.VPositions [S];
766         int Size = GFX.Sizes[S];
767         int TileInc = 1;
768         int Offset;
769
770         if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
771             continue;
772
773         if (OnMain && SUB_OR_ADD(4))
774         {
775             SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
776         }
777
778         BaseTile = PPU.OBJ[S].Name | (PPU.OBJ[S].Palette << 10);
779
780         if (PPU.OBJ[S].HFlip)
781         {
782             BaseTile += ((Size >> 3) - 1) | H_FLIP;
783             TileInc = -1;
784         }
785         if (PPU.OBJ[S].VFlip)
786             BaseTile |= V_FLIP;
787
788         int clipcount = GFX.pCurrentClip->Count [4];
789         if (!clipcount)
790             clipcount = 1;
791         
792         GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
793
794         for (int clip = 0; clip < clipcount; clip++)
795         {
796             int Left; 
797             int Right;
798             if (!GFX.pCurrentClip->Count [4])
799             {
800                 Left = 0;
801                 Right = 256;
802             }
803             else
804             {
805                 Left = GFX.pCurrentClip->Left [clip][4];
806                 Right = GFX.pCurrentClip->Right [clip][4];
807             }
808
809             if (Right <= Left || PPU.OBJ[S].HPos + Size <= Left ||
810                 PPU.OBJ[S].HPos >= Right)
811                 continue;
812
813             for (int Y = 0; Y < Size; Y += 8)
814             {
815                 if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
816                 {
817                     int StartLine;
818                     int TileLine;
819                     int LineCount;
820                     int Last;
821                     
822                     if ((StartLine = VPos + Y) < (int) GFX.StartY)
823                     {
824                         StartLine = GFX.StartY - StartLine;
825                         LineCount = 8 - StartLine;
826                     }
827                     else
828                     {
829                         StartLine = 0;
830                         LineCount = 8;
831                     }
832                     if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
833                         if ((LineCount -= Last) <= 0)
834                             break;
835
836                     TileLine = StartLine << 3;
837                     O = (VPos + Y + StartLine) * GFX.PPL;
838                     if (!PPU.OBJ[S].VFlip)
839                         Tile = BaseTile + (Y << 1);
840                     else
841                         Tile = BaseTile + ((Size - Y - 8) << 1);
842
843                     int Middle = Size >> 3;
844                     if (PPU.OBJ[S].HPos < Left)
845                     {
846                         Tile += ((Left - PPU.OBJ[S].HPos) >> 3) * TileInc;
847                         Middle -= (Left - PPU.OBJ[S].HPos) >> 3;
848                         O += Left * GFX.PixSize;
849                         if ((Offset = (Left - PPU.OBJ[S].HPos) & 7))
850                         {
851                             O -= Offset * GFX.PixSize;
852                             int W = 8 - Offset;
853                             int Width = Right - Left;
854                             if (W > Width)
855                                 W = Width;
856                             (*DrawClippedTilePtr) (Tile, O, Offset, W,
857                                                    TileLine, LineCount);
858                             
859                             if (W >= Width)
860                                 continue;
861                             Tile += TileInc;
862                             Middle--;
863                             O += 8 * GFX.PixSize;
864                         }
865                     }
866                     else
867                         O += PPU.OBJ[S].HPos * GFX.PixSize;
868
869                     if (PPU.OBJ[S].HPos + Size >= Right)
870                     {
871                         Middle -= ((PPU.OBJ[S].HPos + Size + 7) -
872                                    Right) >> 3;
873                         Offset = (Right - (PPU.OBJ[S].HPos + Size)) & 7;
874                     }
875                     else
876                         Offset = 0;
877
878                     for (int X = 0; X < Middle; X++, O += 8 * GFX.PixSize,
879                          Tile += TileInc)
880                     {
881                         (*DrawTilePtr) (Tile, O, TileLine, LineCount);
882                     }
883                     if (Offset)
884                     {
885                         (*DrawClippedTilePtr) (Tile, O, 0, Offset,
886                                                TileLine, LineCount);
887                     }
888                 }
889             }
890         }
891     }
892 }
893
894 void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
895 {
896     CHECK_SOUND();
897
898     uint32 Tile;
899     uint16 *SC0;
900     uint16 *SC1;
901     uint16 *SC2;
902     uint16 *SC3;
903     uint8 depths [2] = {Z1, Z2};
904     
905     if (BGMode == 0)
906         BG.StartPalette = bg << 5;
907     else
908         BG.StartPalette = 0;
909
910     SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
911
912     if (PPU.BG[bg].SCSize & 1)
913         SC1 = SC0 + 1024;
914     else
915         SC1 = SC0;
916
917     if (PPU.BG[bg].SCSize & 2)
918         SC2 = SC1 + 1024;
919     else
920         SC2 = SC0;
921
922     if (PPU.BG[bg].SCSize & 1)
923         SC3 = SC2 + 1024;
924     else
925         SC3 = SC2;
926
927     uint32 Lines;
928     uint32 OffsetMask;
929     uint32 OffsetShift;
930
931     if (BG.TileSize == 16)
932     {
933         OffsetMask = 0x3ff;
934         OffsetShift = 4;
935     }
936     else
937     {
938         OffsetMask = 0x1ff;
939         OffsetShift = 3;
940     }
941
942     for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
943     {
944         uint32 VOffset = LineData [Y].BG[bg].VOffset;
945         uint32 HOffset = LineData [Y].BG[bg].HOffset;
946         uint32 MosaicOffset = Y % PPU.Mosaic;
947
948         for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
949             if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
950                 (HOffset != LineData [Y + Lines].BG[bg].HOffset))
951                 break;
952         
953         uint32 MosaicLine = VOffset + Y - MosaicOffset;
954
955         if (Y + Lines > GFX.EndY)
956             Lines = GFX.EndY + 1 - Y;
957         uint32 VirtAlign = (MosaicLine & 7) << 3;
958         
959         uint16 *b1;
960         uint16 *b2;
961
962         uint32 ScreenLine = MosaicLine >> OffsetShift;
963         uint32 Rem16 = MosaicLine & 15;
964
965         if (ScreenLine & 0x20)
966             b1 = SC2, b2 = SC3;
967         else
968             b1 = SC0, b2 = SC1;
969
970         b1 += (ScreenLine & 0x1f) << 5;
971         b2 += (ScreenLine & 0x1f) << 5;
972         uint16 *t;
973         uint32 Left = 0;
974         uint32 Right = 256;
975
976         uint32 ClipCount = GFX.pCurrentClip->Count [bg];
977         uint32 HPos = HOffset;
978         uint32 PixWidth = PPU.Mosaic;
979
980         if (!ClipCount)
981             ClipCount = 1;
982
983         for (uint32 clip = 0; clip < ClipCount; clip++)
984         {
985             if (GFX.pCurrentClip->Count [bg])
986             {
987                 Left = GFX.pCurrentClip->Left [clip][bg];
988                 Right = GFX.pCurrentClip->Right [clip][bg];
989                 uint32 r = Left % PPU.Mosaic;
990                 HPos = HOffset + Left;
991                 PixWidth = PPU.Mosaic - r;
992             }
993             uint32 s = Y * GFX.PPL + Left * GFX.PixSize;
994             for (uint32 x = Left; x < Right; x += PixWidth, 
995                  s += PixWidth * GFX.PixSize,
996                  HPos += PixWidth, PixWidth = PPU.Mosaic)
997             {
998                 uint32 Quot = (HPos & OffsetMask) >> 3;
999
1000                 if (x + PixWidth >= Right)
1001                     PixWidth = Right - x;
1002
1003                 if (BG.TileSize == 8)
1004                 {
1005                     if (Quot > 31)
1006                         t = b2 + (Quot & 0x1f);
1007                     else
1008                         t = b1 + Quot;
1009                 }
1010                 else
1011                 {
1012                     if (Quot > 63)
1013                         t = b2 + ((Quot >> 1) & 0x1f);
1014                     else
1015                         t = b1 + (Quot >> 1);
1016                 }
1017
1018                 Tile = READ_2BYTES (t);
1019                 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1020
1021                 // Draw tile...
1022                 if (BG.TileSize != 8)
1023                 {
1024                     if (Tile & H_FLIP)
1025                     {
1026                         // Horizontal flip, but what about vertical flip ?
1027                         if (Tile & V_FLIP)
1028                         {
1029                             // Both horzontal & vertical flip
1030                             if (Rem16 < 8)
1031                             {
1032                                 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1033                                                       HPos & 7, PixWidth,
1034                                                       VirtAlign, Lines);
1035                             }
1036                             else
1037                             {
1038                                 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1039                                                       HPos & 7, PixWidth,
1040                                                       VirtAlign, Lines);
1041                             }
1042                         }
1043                         else
1044                         {
1045                             // Horizontal flip only
1046                             if (Rem16 > 7)
1047                             {
1048                                 (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
1049                                                       HPos & 7, PixWidth,
1050                                                       VirtAlign, Lines);
1051                             }
1052                             else
1053                             {
1054                                 (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
1055                                                       HPos & 7, PixWidth,
1056                                                       VirtAlign, Lines);
1057                             }
1058                         }
1059                     }
1060                     else
1061                     {
1062                         // No horizontal flip, but is there a vertical flip ?
1063                         if (Tile & V_FLIP)
1064                         {
1065                             // Vertical flip only
1066                             if (Rem16 < 8)
1067                             {
1068                                 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1069                                                       HPos & 7, PixWidth,
1070                                                       VirtAlign, Lines);
1071                             }
1072                             else
1073                             {
1074                                 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1075                                                       HPos & 7, PixWidth,
1076                                                       VirtAlign, Lines);
1077                             }
1078                         }
1079                         else
1080                         {
1081                             // Normal unflipped
1082                             if (Rem16 > 7)
1083                             {
1084                                 (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
1085                                                       HPos & 7, PixWidth,
1086                                                       VirtAlign, Lines);
1087                             }
1088                             else
1089                             {
1090                                 (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
1091                                                       HPos & 7, PixWidth,
1092                                                       VirtAlign, Lines);
1093                             }
1094                         }
1095                     }
1096                 }
1097                 else
1098                     (*DrawLargePixelPtr) (Tile, s, HPos & 7, PixWidth,
1099                                           VirtAlign, Lines);
1100             }
1101         }
1102     }
1103 }
1104
1105 void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1106 {
1107     CHECK_SOUND();
1108
1109     uint32 Tile;
1110     uint16 *SC0;
1111     uint16 *SC1;
1112     uint16 *SC2;
1113     uint16 *SC3;
1114     uint16 *BPS0;
1115     uint16 *BPS1;
1116     uint16 *BPS2;
1117     uint16 *BPS3;
1118     uint32 Width;
1119     int VOffsetOffset = BGMode == 4 ? 0 : 32;
1120     uint8 depths [2] = {Z1, Z2};
1121     
1122     BG.StartPalette = 0;
1123
1124     BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
1125
1126     if (PPU.BG[2].SCSize & 1)
1127         BPS1 = BPS0 + 1024;
1128     else
1129         BPS1 = BPS0;
1130
1131     if (PPU.BG[2].SCSize & 2)
1132         BPS2 = BPS1 + 1024;
1133     else
1134         BPS2 = BPS0;
1135
1136     if (PPU.BG[2].SCSize & 1)
1137         BPS3 = BPS2 + 1024;
1138     else
1139         BPS3 = BPS2;
1140     
1141     SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1142
1143     if (PPU.BG[bg].SCSize & 1)
1144         SC1 = SC0 + 1024;
1145     else
1146         SC1 = SC0;
1147
1148     if (PPU.BG[bg].SCSize & 2)
1149         SC2 = SC1 + 1024;
1150     else
1151         SC2 = SC0;
1152     if (PPU.BG[bg].SCSize & 1)
1153         SC3 = SC2 + 1024;
1154     else
1155         SC3 = SC2;
1156
1157     static const int Lines = 1;
1158     int OffsetMask;
1159     int OffsetShift;
1160     int OffsetEnableMask = 1 << (bg + 13);
1161
1162     if (BG.TileSize == 16)
1163     {
1164         OffsetMask = 0x3ff;
1165         OffsetShift = 4;
1166     }
1167     else
1168     {
1169         OffsetMask = 0x1ff;
1170         OffsetShift = 3;
1171     }
1172
1173     for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
1174     {
1175         uint32 VOff = LineData [Y].BG[2].VOffset;
1176         uint32 HOff = LineData [Y].BG[2].HOffset;
1177         int VirtAlign;
1178         int ScreenLine = VOff >> 3;
1179         int t1;
1180         int t2;
1181         uint16 *s0;
1182         uint16 *s1;
1183         uint16 *s2;
1184
1185         if (ScreenLine & 0x20)
1186             s1 = BPS2, s2 = BPS3;
1187         else
1188             s1 = BPS0, s2 = BPS1;
1189
1190         s1 += (ScreenLine & 0x1f) << 5;
1191         s2 += (ScreenLine & 0x1f) << 5;
1192
1193         int clipcount = GFX.pCurrentClip->Count [bg];
1194         if (!clipcount)
1195             clipcount = 1;
1196
1197         for (int clip = 0; clip < clipcount; clip++)
1198         {
1199             uint32 Left;
1200             uint32 Right;
1201
1202             if (!GFX.pCurrentClip->Count [bg])
1203             {
1204                 Left = 0;
1205                 Right = 256;
1206             }
1207             else
1208             {
1209                 Left = GFX.pCurrentClip->Left [clip][bg];
1210                 Right = GFX.pCurrentClip->Right [clip][bg];
1211
1212                 if (Right <= Left)
1213                     continue;
1214             }
1215
1216             uint32 VOffset;
1217             uint32 HOffset;
1218                         uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
1219             uint32 Offset;
1220             uint32 HPos;
1221             uint32 Quot;
1222             uint32 Count;
1223             uint16 *t;
1224             uint32 Quot2;
1225             uint32 VCellOffset;
1226             uint32 HCellOffset;
1227             uint16 *b1;
1228             uint16 *b2;
1229             uint32 TotalCount = 0;
1230             uint32 MaxCount = 8;
1231
1232             uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1233             bool8_32 left_hand_edge = (Left == 0);
1234             Width = Right - Left;
1235
1236             if (Left & 7)
1237                 MaxCount = 8 - (Left & 7);
1238
1239             while (Left < Right) 
1240             {
1241                 if (left_hand_edge)
1242                 {
1243                     // The SNES offset-per-tile background mode has a
1244                     // hardware limitation that the offsets cannot be set
1245                     // for the tile at the left-hand edge of the screen.
1246                     VOffset = LineData [Y].BG[bg].VOffset;
1247                                         HOffset = LineHOffset;
1248                     left_hand_edge = FALSE;
1249                 }
1250                 else
1251                 {
1252                     // All subsequent offset tile data is shifted left by one,
1253                     // hence the - 1 below.
1254                     Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
1255
1256                     if (Quot2 > 31)
1257                         s0 = s2 + (Quot2 & 0x1f);
1258                     else
1259                         s0 = s1 + Quot2;
1260
1261                     HCellOffset = READ_2BYTES (s0);
1262
1263                     if (BGMode == 4)
1264                     {
1265                         VOffset = LineData [Y].BG[bg].VOffset;
1266                                                 HOffset=LineHOffset;
1267                         if ((HCellOffset & OffsetEnableMask))
1268                         {
1269                             if (HCellOffset & 0x8000)
1270                                 VOffset = HCellOffset + 1;
1271                             else
1272                                 HOffset = HCellOffset;
1273                         }
1274                     }
1275                     else
1276                     {
1277                         VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
1278                         if ((VCellOffset & OffsetEnableMask))
1279                             VOffset = VCellOffset + 1;
1280                         else
1281                             VOffset = LineData [Y].BG[bg].VOffset;
1282
1283                         if ((HCellOffset & OffsetEnableMask))
1284                                                         HOffset = (HCellOffset & ~7)|(LineHOffset&7);
1285                         else
1286                                                         HOffset=LineHOffset;
1287                     }
1288                 }
1289                 VirtAlign = ((Y + VOffset) & 7) << 3;
1290                 ScreenLine = (VOffset + Y) >> OffsetShift;
1291
1292                 if (((VOffset + Y) & 15) > 7)
1293                 {
1294                     t1 = 16;
1295                     t2 = 0;
1296                 }
1297                 else
1298                 {
1299                     t1 = 0;
1300                     t2 = 16;
1301                 }
1302
1303                 if (ScreenLine & 0x20)
1304                     b1 = SC2, b2 = SC3;
1305                 else
1306                     b1 = SC0, b2 = SC1;
1307
1308                 b1 += (ScreenLine & 0x1f) << 5;
1309                 b2 += (ScreenLine & 0x1f) << 5;
1310
1311                 HPos = (HOffset + Left) & OffsetMask;
1312
1313                 Quot = HPos >> 3;
1314
1315                 if (BG.TileSize == 8)
1316                 {
1317                     if (Quot > 31)
1318                         t = b2 + (Quot & 0x1f);
1319                     else
1320                         t = b1 + Quot;
1321                 }
1322                 else
1323                 {
1324                     if (Quot > 63)
1325                         t = b2 + ((Quot >> 1) & 0x1f);
1326                     else
1327                         t = b1 + (Quot >> 1);
1328                 }
1329
1330                 if (MaxCount + TotalCount > Width)
1331                     MaxCount = Width - TotalCount;
1332
1333                 Offset = HPos & 7;
1334
1335                 Count = 8 - Offset;
1336                 if (Count > MaxCount)
1337                     Count = MaxCount;
1338
1339                 s -= Offset * GFX.PixSize;
1340                 Tile = READ_2BYTES(t);
1341                 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1342
1343                 if (BG.TileSize == 8)
1344                     (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines);
1345                 else
1346                 {
1347                     if (!(Tile & (V_FLIP | H_FLIP)))
1348                     {
1349                         // Normal, unflipped
1350                         (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1351                                                s, Offset, Count, VirtAlign, Lines);
1352                     }
1353                     else
1354                     if (Tile & H_FLIP)
1355                     {
1356                         if (Tile & V_FLIP)
1357                         {
1358                             // H & V flip
1359                             (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1360                                                    s, Offset, Count, VirtAlign, Lines);
1361                         }
1362                         else
1363                         {
1364                             // H flip only
1365                             (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1366                                                    s, Offset, Count, VirtAlign, Lines);
1367                         }
1368                     }
1369                     else
1370                     {
1371                         // V flip only
1372                         (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
1373                                                s, Offset, Count, VirtAlign, Lines);
1374                     }
1375                 }
1376
1377                 Left += Count;
1378                 TotalCount += Count;
1379                 s += (Offset + Count) * GFX.PixSize;
1380                 MaxCount = 8;
1381             }
1382         }
1383     }
1384 }
1385
1386 void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
1387 {
1388     CHECK_SOUND();
1389
1390     GFX.Pitch = GFX.RealPitch;
1391     GFX.PPL = GFX.PPLx2 >> 1;
1392     GFX.PixSize = 1;
1393     uint8 depths [2] = {Z1, Z2};
1394
1395     uint32 Tile;
1396     uint16 *SC0;
1397     uint16 *SC1;
1398     uint16 *SC2;
1399     uint16 *SC3;
1400     uint32 Width;
1401     
1402     BG.StartPalette = 0;
1403
1404     SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1405
1406     if ((PPU.BG[bg].SCSize & 1))
1407         SC1 = SC0 + 1024;
1408     else
1409         SC1 = SC0;
1410
1411     if ((PPU.BG[bg].SCSize & 2))
1412         SC2 = SC1 + 1024;
1413     else
1414         SC2 = SC0;
1415
1416     if ((PPU.BG[bg].SCSize & 1))
1417         SC3 = SC2 + 1024;
1418     else
1419         SC3 = SC2;
1420     
1421     int Lines;
1422     int VOffsetMask;
1423     int VOffsetShift;
1424
1425     if (BG.TileSize == 16)
1426     {
1427         VOffsetMask = 0x3ff;
1428         VOffsetShift = 4;
1429     }
1430     else
1431     {
1432         VOffsetMask = 0x1ff;
1433         VOffsetShift = 3;
1434     }
1435     int endy = GFX.EndY;
1436
1437     for (int Y = GFX.StartY; Y <= endy; Y += Lines)
1438     {
1439         int y = Y;
1440         uint32 VOffset = LineData [y].BG[bg].VOffset;
1441         uint32 HOffset = LineData [y].BG[bg].HOffset;
1442         int VirtAlign = (Y + VOffset) & 7;
1443         
1444         for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1445             if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
1446                 (HOffset != LineData [y + Lines].BG[bg].HOffset))
1447                 break;
1448
1449         HOffset <<= 1;
1450         if (Y + Lines > endy)
1451             Lines = endy + 1 - Y;
1452         
1453         int ScreenLine = (VOffset + Y) >> VOffsetShift;
1454         int t1;
1455         int t2;
1456         if (((VOffset + Y) & 15) > 7)
1457         {
1458             t1 = 16;
1459             t2 = 0;
1460         }
1461         else
1462         {
1463             t1 = 0;
1464             t2 = 16;
1465         }
1466         uint16 *b1;
1467         uint16 *b2;
1468
1469         if (ScreenLine & 0x20)
1470             b1 = SC2, b2 = SC3;
1471         else
1472             b1 = SC0, b2 = SC1;
1473
1474         b1 += (ScreenLine & 0x1f) << 5;
1475         b2 += (ScreenLine & 0x1f) << 5;
1476
1477         int clipcount = GFX.pCurrentClip->Count [bg];
1478         if (!clipcount)
1479             clipcount = 1;
1480         for (int clip = 0; clip < clipcount; clip++)
1481         {
1482             int Left;
1483             int Right;
1484
1485             if (!GFX.pCurrentClip->Count [bg])
1486             {
1487                 Left = 0;
1488                 Right = 512;
1489             }
1490             else
1491             {
1492                 Left = GFX.pCurrentClip->Left [clip][bg] * 2;
1493                 Right = GFX.pCurrentClip->Right [clip][bg] * 2;
1494
1495                 if (Right <= Left)
1496                     continue;
1497             }
1498
1499             uint32 s = (Left>>1) * GFX.PixSize + Y * GFX.PPL;
1500             uint32 HPos = (HOffset + Left * GFX.PixSize) & 0x3ff;
1501
1502             uint32 Quot = HPos >> 3;
1503             uint32 Count = 0;
1504             
1505             uint16 *t;
1506             if (Quot > 63)
1507                 t = b2 + ((Quot >> 1) & 0x1f);
1508             else
1509                 t = b1 + (Quot >> 1);
1510
1511             Width = Right - Left;
1512             // Left hand edge clipped tile
1513             if (HPos & 7)
1514             {
1515                 int Offset = (HPos & 7);
1516                 Count = 8 - Offset;
1517                 if (Count > Width)
1518                     Count = Width;
1519                 if (s) // XXX: Workaround for underflow (Secret of MANA)
1520                         s -= (Offset>>1);
1521                 Tile = READ_2BYTES (t);
1522                 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1523
1524                 if (BG.TileSize == 8)
1525                 {
1526                     if (!(Tile & H_FLIP))
1527                     {
1528                         // Normal, unflipped
1529                         (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1530                                                     s, Offset, Count, VirtAlign, Lines);
1531                     }
1532                     else
1533                     {
1534                         // H flip
1535                         (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1536                                                     s, Offset, Count, VirtAlign, Lines);
1537                     }
1538                 }
1539                 else
1540                 {
1541                     if (!(Tile & (V_FLIP | H_FLIP)))
1542                     {
1543                         // Normal, unflipped
1544                         (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1545                                                     s, Offset, Count, VirtAlign, Lines);
1546                     }
1547                     else
1548                     if (Tile & H_FLIP)
1549                     {
1550                         if (Tile & V_FLIP)
1551                         {
1552                             // H & V flip
1553                             (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1554                                                         s, Offset, Count, VirtAlign, Lines);
1555                         }
1556                         else
1557                         {
1558                             // H flip only
1559                             (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1560                                                         s, Offset, Count, VirtAlign, Lines);
1561                         }
1562                     }
1563                     else
1564                     {
1565                         // V flip only
1566                         (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1567                                                     s, Offset, Count, VirtAlign, Lines);
1568                     }
1569                 }
1570
1571                 t += Quot & 1;
1572                 if (Quot == 63)
1573                     t = b2;
1574                 else if (Quot == 127)
1575                     t = b1;
1576                 Quot++;
1577                 s += 4;
1578             }
1579
1580             // Middle, unclipped tiles
1581             Count = Width - Count;
1582             int Middle = Count >> 3;
1583             Count &= 7;
1584             for (int C = Middle; C > 0; s += 4, Quot++, C--)
1585             {
1586                 Tile = READ_2BYTES(t);
1587                 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1588                 if (BG.TileSize == 8)
1589                 {
1590                     if (!(Tile & H_FLIP))
1591                     {
1592                         // Normal, unflipped
1593                         (*DrawHiResTilePtr) (Tile + (Quot & 1),
1594                                              s, VirtAlign, Lines);
1595                     }
1596                     else
1597                     {
1598                         // H flip
1599                         (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1600                                             s, VirtAlign, Lines);
1601                     }
1602                 }
1603                 else
1604                 {
1605                     if (!(Tile & (V_FLIP | H_FLIP)))
1606                     {
1607                         // Normal, unflipped
1608                         (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1609                                              s, VirtAlign, Lines);
1610                     }
1611                     else
1612                     if (Tile & H_FLIP)
1613                     {
1614                         if (Tile & V_FLIP)
1615                         {
1616                             // H & V flip
1617                             (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1618                                                  s, VirtAlign, Lines);
1619                         }
1620                         else
1621                         {
1622                             // H flip only
1623                             (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1624                                                  s, VirtAlign, Lines);
1625                         }
1626                     }
1627                     else
1628                     {
1629                         // V flip only
1630                         (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1631                                              s, VirtAlign, Lines);
1632                     }
1633                 }
1634
1635                 t += Quot & 1;
1636                 if (Quot == 63)
1637                     t = b2;
1638                 else
1639                 if (Quot == 127)
1640                     t = b1;
1641             }
1642
1643             // Right-hand edge clipped tiles
1644             if (Count)
1645             {
1646                 Tile = READ_2BYTES(t);
1647                 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1648                 if (BG.TileSize == 8)
1649                 {
1650                     if (!(Tile & H_FLIP))
1651                     {
1652                         // Normal, unflipped
1653                         (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1654                                                     s, 0, Count, VirtAlign, Lines);
1655                     }
1656                     else
1657                     {
1658                         // H flip
1659                         (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1660                                                     s, 0, Count, VirtAlign, Lines);
1661                     }
1662                 }
1663                 else
1664                 {
1665                     if (!(Tile & (V_FLIP | H_FLIP)))
1666                     {
1667                         // Normal, unflipped
1668                         (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1669                                                     s, 0, Count, VirtAlign, Lines);
1670                     }
1671                     else
1672                     if (Tile & H_FLIP)
1673                     {
1674                         if (Tile & V_FLIP)
1675                         {
1676                             // H & V flip
1677                             (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1678                                                         s, 0, Count, VirtAlign, Lines);
1679                         }
1680                         else
1681                         {
1682                             // H flip only
1683                             (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1684                                                         s, 0, Count, VirtAlign, Lines);
1685                         }
1686                     }
1687                     else
1688                     {
1689                         // V flip only
1690                         (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1691                                                     s, 0, Count, VirtAlign, Lines);
1692                     }
1693                 }
1694             }
1695         }
1696     }
1697 }
1698
1699 void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1700 {
1701     GFX.PixSize = 1;
1702
1703     BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1704     BG.BitShift = BitShifts[BGMode][bg];
1705     BG.TileShift = TileShifts[BGMode][bg];
1706     BG.TileAddress = PPU.BG[bg].NameBase << 1;
1707     BG.NameSelect = 0;
1708         BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1709         BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1710     BG.PaletteShift = PaletteShifts[BGMode][bg];
1711     BG.PaletteMask = PaletteMasks[BGMode][bg];
1712     BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1713                           (GFX.r2130 & 1);
1714
1715     if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1716     {
1717         DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1718         return;
1719
1720     }
1721     switch (BGMode)
1722     {
1723     case 2:
1724         if (Settings.WrestlemaniaArcade)
1725             break;
1726     case 4: // Used by Puzzle Bobble
1727         DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1728         return;
1729
1730     case 5:
1731     case 6: // XXX: is also offset per tile.
1732             DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1733             return;
1734         }
1735
1736
1737
1738                   
1739
1740     CHECK_SOUND();
1741
1742     uint32 Tile;
1743     uint16 *SC0;
1744     uint16 *SC1;
1745     uint16 *SC2;
1746     uint16 *SC3;
1747     uint32 Width;
1748     uint8 depths [2] = {Z1, Z2};
1749     
1750     if (BGMode == 0)
1751         BG.StartPalette = bg << 5;
1752     else
1753         BG.StartPalette = 0;
1754
1755     SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1756
1757     if (PPU.BG[bg].SCSize & 1)
1758         SC1 = SC0 + 1024;
1759     else
1760         SC1 = SC0;
1761
1762     if (PPU.BG[bg].SCSize & 2)
1763         SC2 = SC1 + 1024;
1764     else
1765         SC2 = SC0;
1766
1767     if (PPU.BG[bg].SCSize & 1)
1768         SC3 = SC2 + 1024;
1769     else
1770         SC3 = SC2;
1771     
1772     int Lines;
1773     int OffsetMask;
1774     int OffsetShift;
1775
1776     if (BG.TileSize == 16)
1777     {
1778         OffsetMask = 0x3ff;
1779         OffsetShift = 4;
1780     }
1781     else
1782     {
1783         OffsetMask = 0x1ff;
1784         OffsetShift = 3;
1785     }
1786
1787     for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1788     {
1789                 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1790                 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1791                 int VirtAlign = (Y + VOffset) & 7;
1792                 
1793                 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1794                     if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1795                         (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1796                         break;
1797
1798                 if (Y + Lines > GFX.EndY)
1799                     Lines = GFX.EndY + 1 - Y;
1800
1801                 VirtAlign <<= 3;
1802                 
1803                 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1804                 uint32 t1;
1805                 uint32 t2;
1806                 if (((VOffset + Y) & 15) > 7)
1807                 {
1808                     t1 = 16;
1809                     t2 = 0;
1810                 }
1811                 else
1812                 {
1813                     t1 = 0;
1814                     t2 = 16;
1815                 }
1816                 uint16 *b1;
1817                 uint16 *b2;
1818
1819                 if (ScreenLine & 0x20)
1820                     b1 = SC2, b2 = SC3;
1821                 else
1822                     b1 = SC0, b2 = SC1;
1823
1824                 b1 += (ScreenLine & 0x1f) << 5;
1825                 b2 += (ScreenLine & 0x1f) << 5;
1826
1827                 int clipcount = GFX.pCurrentClip->Count [bg];
1828                 if (!clipcount)
1829                     clipcount = 1;
1830                 for (int clip = 0; clip < clipcount; clip++)
1831                 {
1832                     uint32 Left;
1833                     uint32 Right;
1834
1835                     if (!GFX.pCurrentClip->Count [bg])
1836                     {
1837                         Left = 0;
1838                         Right = 256;
1839                     }
1840                     else
1841                     {
1842                         Left = GFX.pCurrentClip->Left [clip][bg];
1843                         Right = GFX.pCurrentClip->Right [clip][bg];
1844
1845                         if (Right <= Left)
1846                             continue;
1847                     }
1848
1849                     uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1850                     uint32 HPos = (HOffset + Left) & OffsetMask;
1851
1852                     uint32 Quot = HPos >> 3;
1853                     uint32 Count = 0;
1854                     
1855                     uint16 *t;
1856                     if (BG.TileSize == 8)
1857                     {
1858                         if (Quot > 31)
1859                             t = b2 + (Quot & 0x1f);
1860                         else
1861                             t = b1 + Quot;
1862                     }
1863                     else
1864                     {
1865                         if (Quot > 63)
1866                             t = b2 + ((Quot >> 1) & 0x1f);
1867                         else
1868                             t = b1 + (Quot >> 1);
1869                     }
1870
1871                     Width = Right - Left;
1872                     // Left hand edge clipped tile
1873                     if (HPos & 7)
1874                     {
1875                         uint32 Offset = (HPos & 7);
1876                         Count = 8 - Offset;
1877                         if (Count > Width)
1878                             Count = Width;
1879                         s -= Offset * GFX.PixSize;
1880                         Tile = READ_2BYTES(t);
1881                         GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1882
1883                         if (BG.TileSize == 8)
1884                         {
1885                             (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1886                                                    Lines);
1887                         }
1888                         else
1889                         {
1890                             if (!(Tile & (V_FLIP | H_FLIP)))
1891                             {
1892                                         // Normal, unflipped
1893                                         (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1894                                                        s, Offset, Count, VirtAlign, Lines);
1895                             }
1896                             else
1897                             if (Tile & H_FLIP)
1898                             {
1899                                 if (Tile & V_FLIP)
1900                                 {
1901                                     // H & V flip
1902                                     (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1903                                                            s, Offset, Count, VirtAlign, Lines);
1904                                 }
1905                                 else
1906                                 {
1907                                     // H flip only
1908                                     (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1909                                                            s, Offset, Count, VirtAlign, Lines);
1910                                 }
1911                             }
1912                             else
1913                             {
1914                                 // V flip only
1915                                 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s, 
1916                                                        Offset, Count, VirtAlign, Lines);
1917                             }
1918                         }
1919
1920                         if (BG.TileSize == 8)
1921                         {
1922                             t++;
1923                             if (Quot == 31)
1924                                 t = b2;
1925                             else if (Quot == 63)
1926                                 t = b1;
1927                         }
1928                         else
1929                         {
1930                             t += Quot & 1;
1931                             if (Quot == 63)
1932                                 t = b2;
1933                             else if (Quot == 127)
1934                                 t = b1;
1935                         }
1936                         Quot++;
1937                         s += 8 * GFX.PixSize;
1938                     }
1939
1940                     // Middle, unclipped tiles
1941                     Count = Width - Count;
1942                     int Middle = Count >> 3;
1943                     Count &= 7;
1944                     for (int C = Middle; C > 0; s += 8 * GFX.PixSize, Quot++, C--)
1945                     {
1946                         Tile = READ_2BYTES(t);
1947                         GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1948
1949                         if (BG.TileSize != 8)
1950                         {
1951                             if (Tile & H_FLIP)
1952                             {
1953                                 // Horizontal flip, but what about vertical flip ?
1954                                 if (Tile & V_FLIP)
1955                                 {
1956                                     // Both horzontal & vertical flip
1957                                     (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s, 
1958                                                     VirtAlign, Lines);
1959                                 }
1960                                 else
1961                                 {
1962                                     // Horizontal flip only
1963                                     (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s, 
1964                                                     VirtAlign, Lines);
1965                                 }
1966                             }
1967                             else
1968                             {
1969                                 // No horizontal flip, but is there a vertical flip ?
1970                                 if (Tile & V_FLIP)
1971                                 {
1972                                     // Vertical flip only
1973                                     (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
1974                                                     VirtAlign, Lines);
1975                                 }
1976                                 else
1977                                 {
1978                                     // Normal unflipped
1979                                     (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
1980                                                     VirtAlign, Lines);
1981                                 }
1982                             }
1983                         }
1984                         else
1985                         {
1986                             (*DrawTilePtr) (Tile, s, VirtAlign, Lines);
1987                         }
1988
1989                         if (BG.TileSize == 8)
1990                         {
1991                             t++;
1992                             if (Quot == 31)
1993                                 t = b2;
1994                             else
1995                             if (Quot == 63)
1996                                 t = b1;
1997                         }
1998                         else
1999                         {
2000                             t += Quot & 1;
2001                             if (Quot == 63)
2002                                 t = b2;
2003                             else
2004                             if (Quot == 127)
2005                                 t = b1;
2006                         }
2007                     }
2008                     // Right-hand edge clipped tiles
2009                     if (Count)
2010                     {
2011                         Tile = READ_2BYTES(t);
2012                         GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
2013
2014                         if (BG.TileSize == 8)
2015                             (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign, 
2016                                                    Lines);
2017                         else
2018                         {
2019                             if (!(Tile & (V_FLIP | H_FLIP)))
2020                             {
2021                                 // Normal, unflipped
2022                                 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0, 
2023                                                        Count, VirtAlign, Lines);
2024                             }
2025                             else
2026                             if (Tile & H_FLIP)
2027                             {
2028                                 if (Tile & V_FLIP)
2029                                 {
2030                                     // H & V flip
2031                                     (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2032                                                            s, 0, Count, VirtAlign, 
2033                                                            Lines);
2034                                 }
2035                                 else
2036                                 {
2037                                     // H flip only
2038                                     (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2039                                                            s, 0, Count, VirtAlign,
2040                                                            Lines);
2041                                 }
2042                             }
2043                             else
2044                             {
2045                                 // V flip only
2046                                 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
2047                                                        s, 0, Count, VirtAlign, 
2048                                                        Lines);
2049                             }
2050                         }
2051                     }
2052                 }
2053     }
2054 }
2055
2056 #define RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2057         const uint8 bmask = MASK; \
2058         for (int x = startx; x != endx; \
2059                 x += (HFLIP ? -1 : 1), AA += aa, CC += cc, p++, d++) \
2060         { \
2061                 int X = ((AA + BB) >> 8) & 0x3ff; \
2062                 int Y = ((CC + DD) >> 8) & 0x3ff; \
2063                 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2064                 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2065                 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2066                 if (z > *d && b) \
2067                 { \
2068                         *p = (FUNC); \
2069                         *d = z; \
2070                 } \
2071         }
2072
2073 #define RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,CFILT) \
2074         register int AABB = AA + BB; \
2075         register int CCDD = CC + DD; \
2076         const uint8 bmask = MASK; \
2077         for (int x = startx; x != endx; \
2078                 x += (HFLIP ? -1 : 1), AABB += aa, CCDD += cc, p++, d++) \
2079         { \
2080                 register uint16 X = ((AABB) >> 8) CFILT; \
2081                 register uint16 Y = ((CCDD) >> 8) CFILT; \
2082         \
2083                 if (((X | Y) & ~0x3ff) == 0) { \
2084                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2085                         uint8 b = TileData[((Y & 7) << 4) + ((X & 7) << 1)]; \
2086                         uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2087                         if (z > *d && b) { \
2088                                 *p = (FUNC); \
2089                                 *d = z; \
2090                         } \
2091                 } else if (REPEAT == 3) { \
2092                         X = (x + HOffset) & 7; \
2093                         Y = (yy + CentreY) & 7; \
2094                         uint8 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2095                         uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2096                         if (z > *d && b) { \
2097                                 *p = (FUNC); \
2098                                 *d = z; \
2099                         } \
2100                 } \
2101         } \
2102
2103 #define RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,MASK,PRIOMASK) \
2104         for (uint32 clip = 0; clip < ClipCount; clip++) \
2105         { \
2106             if (GFX.pCurrentClip->Count [bg]) \
2107             { \
2108                         Left = GFX.pCurrentClip->Left [clip][bg]; \
2109                         Right = GFX.pCurrentClip->Right [clip][bg]; \
2110                         if (Right <= Left) \
2111                                 continue; \
2112             } \
2113             register TYPE *p = (TYPE *) Screen + Left; \
2114             register uint8 *d = Depth + Left; \
2115 \
2116             if (HFLIP) \
2117             { \
2118                         startx = Right - 1; \
2119                         endx = Left - 1; \
2120                         aa = -l->MatrixA; \
2121                         cc = -l->MatrixC; \
2122             } \
2123             else \
2124             { \
2125                         startx = Left; \
2126                         endx = Right; \
2127                         aa = l->MatrixA; \
2128                         cc = l->MatrixC; \
2129             } \
2130             int xx; \
2131             if (!REPEAT) \
2132                         xx = startx + (HOffset - CentreX) % 1023; \
2133             else \
2134                         xx = startx + HOffset - CentreX; \
2135             int AA = l->MatrixA * xx; \
2136             int CC = l->MatrixC * xx; \
2137 \
2138             if (!REPEAT) \
2139             { \
2140                         RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2141             } else if (DEZAEMON) { \
2142                         RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,& 0x7ff) \
2143                 } else { \
2144                         RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,) \
2145             } \
2146         } \
2147
2148 #ifdef USE_CRAZY_OPTS
2149
2150 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON) \
2151         if (GFX.Mode7PriorityMask) { \
2152                 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0x7f,0x80) \
2153         } else { \
2154                 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0xff,0x00) \
2155         }
2156
2157 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,HFLIP) \
2158         if (Settings.Dezaemon && PPU.Mode7Repeat) { \
2159                 switch (PPU.Mode7Repeat) { \
2160                         case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,1); break; \
2161                         case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,1); break; \
2162                         case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,1); break; \
2163                 } \
2164         } else { \
2165                 switch (PPU.Mode7Repeat) { \
2166                         case 0: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,0,0); break; \
2167                         case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,0); break; \
2168                         case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,0); break; \
2169                         case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,0); break; \
2170                 } \
2171         }
2172
2173 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC) \
2174         if (PPU.Mode7HFlip) { \
2175                 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,1); \
2176         } else { \
2177                 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,0); \
2178         }
2179
2180 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2181         RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC)
2182
2183 #else
2184
2185 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2186         RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,PPU.Mode7HFlip,PPU.Mode7Repeat,Settings.Dezaemon,GFX.Mode7Mask,GFX.Mode7PriorityMask)
2187
2188 #endif
2189
2190 #define RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2191         for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2192     { \
2193         int yy; \
2194 \
2195         int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2196         int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2197 \
2198         int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2199         int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2200 \
2201         if (PPU.Mode7VFlip) \
2202             yy = 261 - (int) Line; \
2203         else \
2204             yy = Line; \
2205 \
2206         if (PPU.Mode7Repeat == 0) \
2207             yy += (VOffset - CentreY) % 1023; \
2208         else \
2209             yy += VOffset - CentreY; \
2210         int BB = l->MatrixB * yy + (CentreX << 8); \
2211         int DD = l->MatrixD * yy + (CentreY << 8); \
2212 \
2213         RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2214     }
2215
2216 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2217     CHECK_SOUND(); \
2218 \
2219     uint8 * const VRAM1 = Memory.VRAM + 1; \
2220     if (GFX.r2130 & 1) \
2221     { \
2222                 if (IPPU.DirectColourMapsNeedRebuild) \
2223                         S9xBuildDirectColourMaps (); \
2224                 GFX.ScreenColors = DirectColourMaps [0]; \
2225     } \
2226     else \
2227                 GFX.ScreenColors = IPPU.ScreenColors; \
2228 \
2229     int aa, cc; \
2230     int startx, endx; \
2231     uint32 Left = 0; \
2232     uint32 Right = 256; \
2233     uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2234 \
2235     if (!ClipCount) \
2236         ClipCount = 1; \
2237 \
2238     Screen += GFX.StartY * GFX.Pitch; \
2239     uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2240     struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2241     RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2242 \
2243
2244
2245 void DrawBGMode7Background (uint8 *Screen, int bg)
2246 {
2247     RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & bmask))
2248 }
2249
2250 void DrawBGMode7Background16 (uint8 *Screen, int bg)
2251 {
2252     RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2253 }
2254
2255 void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2256 {
2257     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2258                                         (*(d + GFX.DepthDelta) != 1 ?
2259                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2260                                                        p [GFX.Delta]) :
2261                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2262                                                        GFX.FixedColour)) :
2263                                          GFX.ScreenColors [b & bmask]);
2264 }
2265
2266 void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2267 {
2268     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2269                                         (*(d + GFX.DepthDelta) != 1 ?
2270                                             COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2271                                                        p [GFX.Delta]) :
2272                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2273                                                        GFX.FixedColour)) :
2274                                          GFX.ScreenColors [b & bmask]);
2275 }
2276
2277 void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2278 {
2279     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2280                                         (*(d + GFX.DepthDelta) != 1 ?
2281                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2282                                                        p [GFX.Delta]) :
2283                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2284                                                        GFX.FixedColour)) :
2285                                          GFX.ScreenColors [b & bmask]);
2286 }
2287
2288 void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2289 {
2290     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2291                                         (*(d + GFX.DepthDelta) != 1 ?
2292                                             COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2293                                                        p [GFX.Delta]) :
2294                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2295                                                        GFX.FixedColour)) :
2296                                          GFX.ScreenColors [b & bmask]);
2297 }
2298
2299 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2300     CHECK_SOUND(); \
2301 \
2302     uint8 *VRAM1 = Memory.VRAM + 1; \
2303     if (GFX.r2130 & 1) \
2304     { \
2305         if (IPPU.DirectColourMapsNeedRebuild) \
2306             S9xBuildDirectColourMaps (); \
2307         GFX.ScreenColors = DirectColourMaps [0]; \
2308     } \
2309     else \
2310         GFX.ScreenColors = IPPU.ScreenColors; \
2311     \
2312     int aa, cc; \
2313     int dir; \
2314     int startx, endx; \
2315     uint32 Left = 0; \
2316     uint32 Right = 256; \
2317     uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2318     \
2319     if (!ClipCount) \
2320         ClipCount = 1; \
2321     \
2322     Screen += GFX.StartY * GFX.Pitch; \
2323     uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2324     struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2325     bool8_32 allowSimpleCase = FALSE; \
2326     if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2327         && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2328         && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2329         ) \
2330         allowSimpleCase = TRUE;  \
2331     \
2332     for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2333     { \
2334         int yy; \
2335         \
2336         int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2337         int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2338         \
2339         int CentreX = ((int) l->CentreX << M7) >> M7; \
2340         int CentreY = ((int) l->CentreY << M7) >> M7; \
2341         \
2342         if (PPU.Mode7VFlip) \
2343             yy = 261 - (int) Line; \
2344         else \
2345             yy = Line; \
2346         \
2347         if (PPU.Mode7Repeat == 0) \
2348             yy += (VOffset - CentreY) % 1023; \
2349         else \
2350             yy += VOffset - CentreY; \
2351         bool8_32 simpleCase = FALSE; \
2352         int BB; \
2353         int DD; \
2354         /* Make a special case for the identity matrix, since it's a common case and */ \
2355         /* can be done much more quickly without special effects */ \
2356         if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2357         { \
2358             BB = CentreX << 8; \
2359             DD = (yy + CentreY) << 8; \
2360             simpleCase = TRUE; \
2361         } \
2362         else \
2363         { \
2364             BB = l->MatrixB * yy + (CentreX << 8); \
2365             DD = l->MatrixD * yy + (CentreY << 8); \
2366         } \
2367         \
2368         for (uint32 clip = 0; clip < ClipCount; clip++) \
2369         { \
2370             if (GFX.pCurrentClip->Count [bg]) \
2371             { \
2372                 Left = GFX.pCurrentClip->Left [clip][bg]; \
2373                 Right = GFX.pCurrentClip->Right [clip][bg]; \
2374                 if (Right <= Left) \
2375                     continue; \
2376             } \
2377             TYPE *p = (TYPE *) Screen + Left; \
2378             uint8 *d = Depth + Left; \
2379             \
2380             if (PPU.Mode7HFlip) \
2381             { \
2382                 startx = Right - 1; \
2383                 endx = Left - 1; \
2384                 dir = -1; \
2385                 aa = -l->MatrixA; \
2386                 cc = -l->MatrixC; \
2387             } \
2388             else \
2389             { \
2390                 startx = Left; \
2391                 endx = Right; \
2392                 dir = 1; \
2393                 aa = l->MatrixA; \
2394                 cc = l->MatrixC; \
2395             } \
2396             int xx; \
2397             if (PPU.Mode7Repeat == 0) \
2398                 xx = startx + (HOffset - CentreX) % 1023; \
2399             else \
2400                 xx = startx + HOffset - CentreX; \
2401             int AA, CC = 0; \
2402             if (simpleCase) \
2403             { \
2404                 AA = xx << 8; \
2405             } \
2406             else \
2407             { \
2408                 AA = l->MatrixA * xx; \
2409                 CC = l->MatrixC * xx; \
2410             } \
2411             if (simpleCase) \
2412             { \
2413                 if (!PPU.Mode7Repeat) \
2414                 { \
2415                     int x = startx; \
2416                     do \
2417                     { \
2418                         int X = ((AA + BB) >> 8) & 0x3ff; \
2419                         int Y = (DD >> 8) & 0x3ff; \
2420                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2421                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2422                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2423                         if (GFX.Z1 > *d && b) \
2424                         { \
2425                             TYPE theColor = COLORFUNC; \
2426                             *p = (FUNC) | ALPHA_BITS_MASK; \
2427                             *d = GFX.Z1; \
2428                         } \
2429                         AA += aa, p++, d++; \
2430                         x += dir; \
2431                     } while (x != endx); \
2432                 } \
2433                 else \
2434                 { \
2435                     int x = startx; \
2436                     do { \
2437                         int X = (AA + BB) >> 8; \
2438                         int Y = DD >> 8; \
2439 \
2440                         if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2441                         { \
2442                             X &= 0x7ff; \
2443                             Y &= 0x7ff; \
2444                         } \
2445 \
2446                         if (((X | Y) & ~0x3ff) == 0) \
2447                         { \
2448                             uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2449                             uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2450                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2451                             if (GFX.Z1 > *d && b) \
2452                             { \
2453                                 TYPE theColor = COLORFUNC; \
2454                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2455                                 *d = GFX.Z1; \
2456                             } \
2457                         } \
2458                         else if (PPU.Mode7Repeat == 3) \
2459                         { \
2460                             X = (x + HOffset) & 7; \
2461                             Y = (yy + CentreY) & 7; \
2462                             uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2463                             uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2464                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2465                             if (GFX.Z1 > *d && b) \
2466                             { \
2467                                 TYPE theColor = COLORFUNC; \
2468                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2469                                 *d = GFX.Z1; \
2470                             } \
2471                         } \
2472                         AA += aa; p++; d++; \
2473                         x += dir; \
2474                     } while (x != endx); \
2475                 } \
2476             } \
2477             else if (!PPU.Mode7Repeat) \
2478             { \
2479                 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2480                 /* the location of one point in the _sampled_ image, and weight them according */ \
2481                 /* to their (city block) distance.  It's very smooth, but blurry with "close up" */ \
2482                 /* points. */ \
2483                 \
2484                 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2485                 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2486                 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2487                 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2488                 /* You can think of this as a kind of mipmapping. */ \
2489                 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2490                 {\
2491                     for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2492                     { \
2493                         uint32 xPos = AA + BB; \
2494                         uint32 xPix = xPos >> 8; \
2495                         uint32 yPos = CC + DD; \
2496                         uint32 yPix = yPos >> 8; \
2497                         uint32 X = xPix & 0x3ff; \
2498                         uint32 Y = yPix & 0x3ff; \
2499                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2500                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2501                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2502                         if (GFX.Z1 > *d && b) \
2503                         { \
2504                             /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2505                             uint32 X10 = (xPix + dir) & 0x3ff; \
2506                             uint32 Y01 = (yPix + dir) & 0x3ff; \
2507                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2508                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2509                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2510                             uint32 p1 = COLORFUNC; \
2511                             p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2512                             b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2513                             uint32 p2 = COLORFUNC; \
2514                             p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2515                             b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2516                             uint32 p4 = COLORFUNC; \
2517                             p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2518                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2519                             uint32 p3 = COLORFUNC; \
2520                             p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2521                             /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2522                             uint32 Xdel = (xPos >> 3) & 0x1F; \
2523                             uint32 Ydel = (yPos >> 3) & 0x1F; \
2524                             uint32 XY = (Xdel*Ydel) >> 5; \
2525                             uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2526                             uint32 area2 = Xdel - XY; \
2527                             uint32 area3 = Ydel - XY; \
2528                             uint32 area4 = XY; \
2529                             uint32 tempColor = ((area1 * p1) + \
2530                                                 (area2 * p2) + \
2531                                                 (area3 * p3) + \
2532                                                 (area4 * p4)) >> 5; \
2533                             TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2534                             *p = (FUNC) | ALPHA_BITS_MASK; \
2535                             *d = GFX.Z1; \
2536                         } \
2537                     } \
2538                 } \
2539                 else \
2540                     /* The oversampling method: get the colors at four corners of a square */ \
2541                     /* in the _displayed_ image, and average them.  It's sharp and clean, but */ \
2542                     /* gives the usual huge pixels when the source image gets "close." */ \
2543                 { \
2544                     /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2545                     uint32 aaDelX = aa >> 1; \
2546                     uint32 ccDelX = cc >> 1; \
2547                     uint32 bbDelY = l->MatrixB >> 1; \
2548                     uint32 ddDelY = l->MatrixD >> 1; \
2549                     /* Offset the location within the source image so that the four sampled points */ \
2550                     /* center around where the single point would otherwise have been drawn. */ \
2551                     BB -= (bbDelY >> 1); \
2552                     DD -= (ddDelY >> 1); \
2553                     AA -= (aaDelX >> 1); \
2554                     CC -= (ccDelX >> 1); \
2555                     uint32 BB10 = BB + aaDelX; \
2556                     uint32 BB01 = BB + bbDelY; \
2557                     uint32 BB11 = BB + aaDelX + bbDelY; \
2558                     uint32 DD10 = DD + ccDelX; \
2559                     uint32 DD01 = DD + ddDelY; \
2560                     uint32 DD11 = DD + ccDelX + ddDelY; \
2561                     for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2562                     { \
2563                         uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2564                         uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2565                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2566                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2567                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2568                         if (GFX.Z1 > *d && b) \
2569                         { \
2570                             /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2571                             /* source image that we're going to examine. */ \
2572                             uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2573                             uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2574                             uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2575                             uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2576                             uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2577                             uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2578                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2579                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2580                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2581                             TYPE p1 = COLORFUNC; \
2582                             b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2583                             TYPE p2 = COLORFUNC; \
2584                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2585                             TYPE p3 = COLORFUNC; \
2586                             b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2587                             TYPE p4 = COLORFUNC; \
2588                             TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2589                             *p = (FUNC) | ALPHA_BITS_MASK; \
2590                             *d = GFX.Z1; \
2591                         } \
2592                     } \
2593                 } \
2594             } \
2595             else \
2596             { \
2597                 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2598                 { \
2599                     uint32 xPos = AA + BB; \
2600                     uint32 xPix = xPos >> 8; \
2601                     uint32 yPos = CC + DD; \
2602                     uint32 yPix = yPos >> 8; \
2603                     uint32 X = xPix; \
2604                     uint32 Y = yPix; \
2605                     \
2606 \
2607                     if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2608                     { \
2609                         X &= 0x7ff; \
2610                         Y &= 0x7ff; \
2611                     } \
2612 \
2613                     if (((X | Y) & ~0x3ff) == 0) \
2614                     { \
2615                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2616                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2617                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2618                         if (GFX.Z1 > *d && b) \
2619                         { \
2620                             /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2621                             uint32 X10 = (xPix + dir) & 0x3ff; \
2622                             uint32 Y01 = (yPix + dir) & 0x3ff; \
2623                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2624                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2625                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2626                             uint32 p1 = COLORFUNC; \
2627                             p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2628                             b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2629                             uint32 p2 = COLORFUNC; \
2630                             p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2631                             b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2632                             uint32 p4 = COLORFUNC; \
2633                             p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2634                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2635                             uint32 p3 = COLORFUNC; \
2636                             p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2637                             /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2638                             uint32 Xdel = (xPos >> 3) & 0x1F; \
2639                             uint32 Ydel = (yPos >> 3) & 0x1F; \
2640                             uint32 XY = (Xdel*Ydel) >> 5; \
2641                             uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2642                             uint32 area2 = Xdel - XY; \
2643                             uint32 area3 = Ydel - XY; \
2644                             uint32 area4 = XY; \
2645                             uint32 tempColor = ((area1 * p1) + \
2646                                                 (area2 * p2) + \
2647                                                 (area3 * p3) + \
2648                                                 (area4 * p4)) >> 5; \
2649                             TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2650                             *p = (FUNC) | ALPHA_BITS_MASK; \
2651                             *d = GFX.Z1; \
2652                         } \
2653                     } \
2654                     else \
2655                     { \
2656                         if (PPU.Mode7Repeat == 3) \
2657                         { \
2658                             X = (x + HOffset) & 7; \
2659                             Y = (yy + CentreY) & 7; \
2660                             uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2661                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2662                             if (GFX.Z1 > *d && b) \
2663                             { \
2664                                 TYPE theColor = COLORFUNC; \
2665                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2666                                 *d = GFX.Z1; \
2667                             } \
2668                         } \
2669                     } \
2670                 } \
2671             } \
2672         } \
2673     }
2674
2675 STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2676 {
2677     register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2678                             ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2679                             ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2680                             ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2681     register uint32 y = (A & TWO_LOW_BITS_MASK) +
2682                             (B & TWO_LOW_BITS_MASK) +
2683                             (C & TWO_LOW_BITS_MASK) +
2684                             (D & TWO_LOW_BITS_MASK);
2685     y = (y>>2) & TWO_LOW_BITS_MASK;
2686     return x+y;
2687 }
2688
2689 void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2690 {
2691     RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2692 }
2693
2694 void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2695 {
2696     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2697                                         (*(d + GFX.DepthDelta) != 1 ?
2698                                             (COLOR_ADD (theColor,
2699                                                        p [GFX.Delta])) :
2700                                             (COLOR_ADD (theColor,
2701                                                        GFX.FixedColour))) :
2702                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2703 }
2704
2705 void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2706 {
2707     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2708                                         (*(d + GFX.DepthDelta) != 1 ?
2709                                             COLOR_ADD1_2 (theColor,
2710                                                           p [GFX.Delta]) :
2711                                             COLOR_ADD (theColor,
2712                                                        GFX.FixedColour)) :
2713                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2714 }
2715
2716 void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2717 {
2718     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2719                                         (*(d + GFX.DepthDelta) != 1 ?
2720                                             COLOR_SUB (theColor,
2721                                                        p [GFX.Delta]) :
2722                                             COLOR_SUB (theColor,
2723                                                        GFX.FixedColour)) :
2724                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2725 }
2726
2727 void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2728 {
2729     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2730                                         (*(d + GFX.DepthDelta) != 1 ?
2731                                             COLOR_SUB1_2 (theColor,
2732                                                        p [GFX.Delta]) :
2733                                             COLOR_SUB (theColor,
2734                                                        GFX.FixedColour)) :
2735                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2736 }
2737
2738 #define _BUILD_SETUP(F) \
2739 GFX.BuildPixel = BuildPixel##F; \
2740 GFX.BuildPixel2 = BuildPixel2##F; \
2741 GFX.DecomposePixel = DecomposePixel##F; \
2742 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2743 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2744 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2745 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2746 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2747 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2748 MAX_RED = MAX_RED_##F; \
2749 MAX_GREEN = MAX_GREEN_##F; \
2750 MAX_BLUE = MAX_BLUE_##F; \
2751 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2752 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2753 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2754                      GREEN_LOW_BIT_MASK_##F | \
2755                      BLUE_LOW_BIT_MASK_##F); \
2756 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2757                     GREEN_HI_BIT_MASK_##F | \
2758                     BLUE_HI_BIT_MASK_##F); \
2759 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2760                        GREEN_HI_BIT_MASK_##F | \
2761                        BLUE_HI_BIT_MASK_##F) << 1); \
2762 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2763 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2764 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2765 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2766 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2767 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2768 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2769 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2770                                 ~TWO_LOW_BITS_MASK ) >> 2);
2771
2772 void RenderScreen (uint8 *Screen, bool8_32 sub, bool8_32 force_no_add, uint8 D)
2773 {
2774     bool8_32 BG0;
2775     bool8_32 BG1;
2776     bool8_32 BG2;
2777     bool8_32 BG3;
2778     bool8_32 OB;
2779
2780     GFX.S = Screen;
2781
2782     if (!sub)
2783     {
2784         GFX.pCurrentClip = &IPPU.Clip [0];
2785         BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2786         BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2787         BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2788         BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2789         OB  = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2790     }
2791     else
2792     {
2793         GFX.pCurrentClip = &IPPU.Clip [1];
2794         BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2795         BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2796         BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2797         BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2798         OB  = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2799     }
2800
2801     sub |= force_no_add;
2802
2803     if (PPU.BGMode <= 1)
2804     {
2805         if (OB)
2806         {
2807             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2808             DrawOBJS (!sub, D);
2809         }
2810         if (BG0)
2811         {
2812             SelectTileRenderer (sub || !SUB_OR_ADD(0));
2813             DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2814         }
2815         if (BG1)
2816         {
2817             SelectTileRenderer (sub || !SUB_OR_ADD(1));
2818             DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2819         }
2820         if (BG2)
2821         {
2822             SelectTileRenderer (sub || !SUB_OR_ADD(2));
2823             DrawBackground (PPU.BGMode, 2, D + 3, 
2824                             (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2825         }
2826         if (BG3 && PPU.BGMode == 0)
2827         {
2828             SelectTileRenderer (sub || !SUB_OR_ADD(3));
2829             DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2830         }
2831     }
2832     else if (PPU.BGMode != 7)
2833     {
2834         if (OB)
2835         {
2836             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2837             DrawOBJS (!sub, D);
2838         }
2839         if (BG0)
2840         {
2841             SelectTileRenderer (sub || !SUB_OR_ADD(0));
2842             DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2843         }
2844         if (PPU.BGMode != 6 && BG1)
2845         {
2846             SelectTileRenderer (sub || !SUB_OR_ADD(1));
2847             DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2848         }
2849     }
2850     else
2851     {
2852         if (OB)
2853         {
2854             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2855             DrawOBJS (!sub, D);
2856         }
2857         if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2858         {
2859             int bg;
2860
2861             if (Memory.FillRAM [0x2133] & 0x40)
2862             {
2863                 GFX.Mode7Mask = 0x7f;
2864                 GFX.Mode7PriorityMask = 0x80;
2865                 Mode7Depths [0] = 5 + D;
2866                 Mode7Depths [1] = 9 + D;
2867                 bg = 1;
2868             }
2869             else
2870             {
2871                 GFX.Mode7Mask = 0xff;
2872                 GFX.Mode7PriorityMask = 0;
2873                 Mode7Depths [0] = 5 + D;
2874                 Mode7Depths [1] = 5 + D;
2875                 bg = 0;
2876             }
2877             if (sub || !SUB_OR_ADD(0))
2878             {
2879                 if (!Settings.Mode7Interpolate)
2880                     DrawBGMode7Background16 (Screen, bg);
2881                 else
2882                     DrawBGMode7Background16_i (Screen, bg);
2883             }
2884             else
2885             {
2886                 if (GFX.r2131 & 0x80)
2887                 {
2888                     if (GFX.r2131 & 0x40)
2889                     {
2890                         if (!Settings.Mode7Interpolate)
2891                             DrawBGMode7Background16Sub1_2 (Screen, bg);
2892                         else
2893                             DrawBGMode7Background16Sub1_2_i (Screen, bg);
2894                     }
2895                     else
2896                     {
2897                         if (!Settings.Mode7Interpolate)
2898                             DrawBGMode7Background16Sub (Screen, bg);
2899                         else
2900                             DrawBGMode7Background16Sub_i (Screen, bg);
2901                     }
2902                 }
2903                 else
2904                 {
2905                     if (GFX.r2131 & 0x40)
2906                     {
2907                         if (!Settings.Mode7Interpolate)
2908                             DrawBGMode7Background16Add1_2 (Screen, bg);
2909                         else
2910                             DrawBGMode7Background16Add1_2_i (Screen, bg);
2911                     }
2912                     else
2913                     {
2914                         if (!Settings.Mode7Interpolate)
2915                             DrawBGMode7Background16Add (Screen, bg);
2916                         else
2917                             DrawBGMode7Background16Add_i (Screen, bg);
2918                     }
2919                 }
2920             }
2921         }
2922     }
2923 }
2924
2925 #include "font.h"
2926
2927 void DisplayChar (uint8 *Screen, uint8 c)
2928 {
2929     int line = (((c & 0x7f) - 32) >> 4) * font_height;
2930     int offset = (((c & 0x7f) - 32) & 15) * font_width;
2931 #ifndef _SNESPPC
2932     if (Settings.SixteenBit)
2933 #endif
2934     {
2935         int h, w;
2936         uint16 *s = (uint16 *) Screen;
2937         for (h = 0; h < font_height; h++, line++,
2938              s += GFX.PPL - font_width)
2939         {
2940             for (w = 0; w < font_width; w++, s++)
2941             {
2942                 uint8 p = font [line][offset + w];
2943
2944                 if (p == '#')
2945                     *s = 0xffff;
2946                 else
2947                 if (p == '.')
2948                     *s = BLACK;
2949             }
2950         }
2951     }
2952 #ifndef _SNESPPC
2953     else
2954     {
2955         int h, w;
2956         uint8 *s = Screen;
2957         for (h = 0; h < font_height; h++, line++,
2958              s += GFX.PPL - font_width)
2959         {
2960             for (w = 0; w < font_width; w++, s++)
2961             {
2962                 uint8 p = font [line][offset + w];
2963
2964                 if (p == '#')
2965                     *s = 255;
2966                 else
2967                 if (p == '.')
2968                     *s = BLACK;
2969             }
2970         }
2971     }
2972 #endif
2973 }
2974
2975 static void S9xDisplayFrameRate ()
2976 {
2977     uint8 *Screen = GFX.Screen + 2 +
2978                     (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch2;
2979     char string [10];
2980     int len = 5;
2981
2982     sprintf (string, "%02d/%02d", IPPU.DisplayedRenderedFrameCount,
2983              (int) Memory.ROMFramesPerSecond);
2984
2985     int i;
2986 #ifdef _SNESPPC
2987     Screen += (font_width - 1) * sizeof(uint16);
2988 #endif
2989     for (i = 0; i < len; i++)
2990     {
2991         DisplayChar (Screen, string [i]);
2992         Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) : 
2993                   (font_width - 1);
2994     }
2995 }
2996
2997 static void S9xDisplayString (const char *string)
2998 {
2999     uint8 *Screen = GFX.Screen + 2 +
3000                     (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch2;
3001     int len = strlen (string);
3002     int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
3003     int char_count = 0;
3004     int i;
3005
3006     for (i = 0; i < len; i++, char_count++)
3007     {
3008         if (char_count >= max_chars || string [i] < 32)
3009         {
3010             Screen -= Settings.SixteenBit ? 
3011                         (font_width - 1) * sizeof (uint16) * max_chars :
3012                         (font_width - 1) * max_chars;
3013             Screen += font_height * GFX.Pitch;
3014             if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
3015                 break;
3016             char_count -= max_chars;
3017         }
3018         if (string [i] < 32)
3019             continue;
3020         DisplayChar (Screen, string [i]);
3021         Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) : 
3022                   (font_width - 1);
3023     }
3024 }
3025
3026 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
3027 {
3028     int32 x2 = 1;
3029
3030     GFX.S = GFX.Screen;
3031
3032         unsigned char *memoryfillram = Memory.FillRAM;
3033
3034         // get local copies of vid registers to be used later
3035     GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN 
3036     GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
3037     GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
3038     GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
3039         
3040         // If external sync is off and
3041         // main screens have not been configured the same as the sub screen and
3042         // color addition and subtraction has been diabled then
3043         // Pseudo is 1
3044         // anything else it is 0
3045         GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
3046                  (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
3047                  (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
3048
3049         // If sprite data has been changed then go through and 
3050         // refresh the sprites.
3051     if (IPPU.OBJChanged)
3052         {       
3053                 S9xSetupOBJ ();
3054         }
3055
3056     if (PPU.RecomputeClipWindows)
3057     {
3058                 ComputeClipWindows ();
3059                 PPU.RecomputeClipWindows = FALSE;
3060     }
3061
3062     GFX.StartY = IPPU.PreviousLine;
3063     if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
3064                 GFX.EndY = PPU.ScreenHeight - 1;
3065
3066     uint32 starty = GFX.StartY;
3067     uint32 endy = GFX.EndY;
3068
3069 #ifndef RC_OPTIMIZED
3070     if (Settings.SupportHiRes &&
3071         (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace))
3072     {
3073                 if (PPU.BGMode == 5 || PPU.BGMode == 6)
3074                 {
3075                     IPPU.RenderedScreenWidth = 512;
3076                     x2 = 2;
3077                 }
3078                 if (IPPU.LatchedInterlace)
3079                 {
3080                     starty = GFX.StartY * 2;
3081                     endy = GFX.EndY * 2 + 1;
3082                 }
3083                 if (!IPPU.DoubleWidthPixels)
3084                 {
3085                     // The game has switched from lo-res to hi-res mode part way down
3086                     // the screen. Scale any existing lo-res pixels on screen
3087 #ifndef _SNESPPC
3088                         if (Settings.SixteenBit)
3089 #endif
3090                     {
3091 #if defined (USE_GLIDE) || defined (USE_OPENGL)
3092                     if (
3093 #ifdef USE_GLIDE
3094                         (Settings.GlideEnable && GFX.Pitch == 512) ||
3095 #endif
3096 #ifdef USE_OPENGL
3097                         (Settings.OpenGLEnable && GFX.Pitch == 512) ||
3098 #endif
3099                             0)
3100                                 {
3101                                     // Have to back out of the speed up hack where the low res.
3102                                     // SNES image was rendered into a 256x239 sized buffer,
3103                                     // ignoring the true, larger size of the buffer.
3104                                     
3105                                     for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
3106                                     {
3107                                                 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3108                                                 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.RealPitch) + 510;
3109                                                 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3110                                                         *q = *(q + 1) = *p;
3111                                     }
3112                                 }
3113                                 else
3114 #endif
3115                                         for (register uint32 y = 0; y < GFX.StartY; y++)
3116                                         {
3117                                             register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3118                                             register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3119                                             for (register int x = 255; x >= 0; x--, p--, q -= 2)
3120                                                 *q = *(q + 1) = *p;
3121                                         }
3122                     }
3123 #ifndef _SNESPPC
3124                     else
3125                     {
3126                                 for (register uint32 y = 0; y < GFX.StartY; y++)
3127                                 {
3128                                         register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3129                                         register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3130                                         for (register int x = 255; x >= 0; x--, p--, q -= 2)
3131                                         *q = *(q + 1) = *p;
3132                                 }
3133                     }
3134 #endif
3135                     IPPU.DoubleWidthPixels = TRUE;
3136                 }
3137     }
3138 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3139
3140     uint32 black = BLACK | (BLACK << 16);
3141
3142         // Are we worrying about transparencies?
3143     if (Settings.Transparency && Settings.SixteenBit)
3144     {
3145                 if (GFX.Pseudo)
3146                 {
3147                         GFX.r2131 = 0x5f;  //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3148                         GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3149                                  Memory.FillRAM [0x212d]) & 15;
3150                         GFX.r212c &= ~GFX.r212d;  // make sure the main BG reg is the reverse of the sub BG reg
3151                         GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3152                 }
3153
3154                 // Check to see if any transparency effects are currently in use
3155                 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3156                         (GFX.r2130 & 0x30) != 0x30 &&
3157                         !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3158                 {
3159                         // transparency effects in use, so lets get busy!
3160                         struct ClipData *pClip;
3161                         uint32 fixedColour;
3162                         GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3163                                                    IPPU.XB [PPU.FixedColourGreen],
3164                                                    IPPU.XB [PPU.FixedColourBlue]);
3165                         fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3166                         // Clear the z-buffer, marking areas 'covered' by the fixed
3167                         // colour as depth 1.
3168                         pClip = &IPPU.Clip [1];
3169
3170                         // Clear the z-buffer
3171                         
3172                     if (pClip->Count [5])
3173                     {
3174
3175                                 // Colour window enabled.
3176
3177 #ifdef RC_OPTIMIZED
3178                                 for (uint32 y = starty; y <= endy; y++)
3179                                 {
3180
3181                         ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3182                                                 IPPU.RenderedScreenWidth);
3183                                         ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3184                                                 IPPU.RenderedScreenWidth);
3185
3186                         if (IPPU.Clip [0].Count [5])
3187                                         {
3188                                                 memset ((GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth);
3189                                         }
3190                                         for (uint32 c = 0; c < pClip->Count [5]; c++)
3191                                         {
3192                                                 if (pClip->Right [c][5] > pClip->Left [c][5])
3193                                                 {
3194                                                         memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3195                                                                 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3196                                                         if (IPPU.Clip [0].Count [5])
3197                                                         {
3198                                                         // Blast, have to clear the sub-screen to the fixed-colour
3199                                                         // because there is a colour window in effect clipping
3200                                                         // the main screen that will allow the sub-screen
3201                                                         // 'underneath' to show through.
3202                                                         memset ((GFX.SubScreen + y * GFX.Pitch2) + pClip->Left [c][5] * x2,
3203                                                                          GFX.FixedColour,
3204                                                                          pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3205                                                         }
3206                                                 }
3207                                         }
3208                                 }
3209
3210 #else // NOT RC_OPTIMIZED
3211                                 // loop around all of the lines being updated
3212                                 for (uint32 y = starty; y <= endy; y++)
3213                                 {
3214                                         // Clear the subZbuffer
3215                                         memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3216                                                 IPPU.RenderedScreenWidth>>2);
3217                                         // Clear the Zbuffer
3218                                         memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3219                                                 IPPU.RenderedScreenWidth>>2);
3220
3221                                         // if there is clipping then clear subscreen to a black color
3222                                         if (IPPU.Clip [0].Count [5])
3223                                         {
3224                                                 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth>>1);
3225                                         }
3226
3227                                         // loop through all window clippings
3228                                         for (uint32 c = 0; c < pClip->Count [5]; c++)
3229                                         {
3230                                                 if (pClip->Right [c][5] > pClip->Left [c][5])
3231                                                 {
3232                                                         memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3233                                                                 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3234                                                         if (IPPU.Clip [0].Count [5])
3235                                                         {
3236                                                         // Blast, have to clear the sub-screen to the fixed-colour
3237                                                         // because there is a colour window in effect clipping
3238                                                         // the main screen that will allow the sub-screen
3239                                                         // 'underneath' to show through.
3240
3241                                                         register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch2);
3242                                                         register uint16 *q = p + pClip->Right [c][5] * x2;
3243                                                         p += pClip->Left [c][5] * x2;
3244
3245                                                         while (p < q)
3246                                                                 *p++ = (uint16) GFX.FixedColour;
3247                                                         }
3248                                                 }
3249                                         }
3250                                 }
3251 #endif
3252 //#undef RC_OPTIMIZED
3253
3254                     }
3255                     else
3256                     {
3257                                 // No windows are clipping the main screen
3258                                 // this simplifies the screen clearing process
3259 #ifdef RC_OPTIMIZED
3260
3261                         if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3262                         {
3263
3264                                 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3265                                 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3266                         }
3267                         else
3268                         {
3269                                 for (uint32 y = starty; y <= endy; y++)
3270                                 {
3271                                         ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3272                                                 IPPU.RenderedScreenWidth);
3273                                         memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3274                                                 IPPU.RenderedScreenWidth);
3275                                 }
3276                         }
3277                         
3278                     if (IPPU.Clip [0].Count [5])
3279                     {
3280                                 // Blast, have to clear the sub-screen to the fixed-colour
3281                                 // because there is a colour window in effect clipping
3282                                 // the main screen that will allow the sub-screen
3283                                 // 'underneath' to show through.
3284                                 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3285                                 {
3286                                         memset ((GFX.SubScreen + starty * GFX.Pitch2), 
3287                                                         GFX.FixedColour | (GFX.FixedColour << 16),
3288                                                         GFX.Pitch2 * (endy - starty - 1));
3289                                 }
3290                                 else
3291                                 {
3292                                         for (uint32 y = starty; y <= endy; y++)
3293                                         {
3294                                                 memset ((GFX.SubScreen + y * GFX.Pitch2), 
3295                                                                 GFX.FixedColour | (GFX.FixedColour << 16),
3296                                                                 IPPU.RenderedScreenWidth);
3297                                         }
3298                                 }
3299                         }
3300
3301 #else // NOT RC_OPTIMIZED
3302                         // loop through all of the lines to be updated
3303                         for (uint32 y = starty; y <= endy; y++)
3304                         {
3305                                 // Clear the Zbuffer
3306                                 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3307                                         IPPU.RenderedScreenWidth>>2);
3308                             // clear the sub Zbuffer to 1
3309                                 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3310                                     IPPU.RenderedScreenWidth>>2);
3311                             if (IPPU.Clip [0].Count [5])
3312                             {
3313                                 // Blast, have to clear the sub-screen to the fixed-colour
3314                                 // because there is a colour window in effect clipping
3315                                 // the main screen that will allow the sub-screen
3316                                 // 'underneath' to show through.
3317
3318
3319                                 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), fixedColour,
3320                                     IPPU.RenderedScreenWidth>>1);
3321                             }
3322                         }
3323 #endif
3324
3325                         }
3326
3327                     if (ANYTHING_ON_SUB)
3328                     {
3329                                 GFX.DB = GFX.SubZBuffer;
3330                                 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3331                     }
3332
3333                     if (IPPU.Clip [0].Count [5])
3334                     {
3335                                         for (uint32 y = starty; y <= endy; y++)
3336                         {
3337                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3338                                         register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3339                                         register uint8 *e = d + SNES_WIDTH;
3340
3341                                         while (d < e)
3342                                 {
3343                                                 if (*d > 1)
3344                                                         *p = *(p + GFX.Delta);
3345                                 else
3346                                                         *p = BLACK;
3347                                                 d++;
3348                                                 p++;
3349                             }
3350                         }
3351                     }
3352
3353                     GFX.DB = GFX.ZBuffer;
3354                     RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3355                     if (SUB_OR_ADD(5))
3356                     {
3357                         uint32 back = IPPU.ScreenColors [0];
3358                         uint32 Left = 0;
3359                         uint32 Right = 256;
3360                         uint32 Count;
3361
3362                         pClip = &IPPU.Clip [0];
3363
3364                         for (uint32 y = starty; y <= endy; y++)
3365                         {
3366                             if (!(Count = pClip->Count [5]))
3367                             {
3368                                 Left = 0;
3369                                 Right = 256 * x2;
3370                                 Count = 1;
3371                             }
3372
3373                             for (uint32 b = 0; b < Count; b++)
3374                             {
3375                                 if (pClip->Count [5])
3376                                 {
3377                                     Left = pClip->Left [b][5] * x2;
3378                                     Right = pClip->Right [b][5] * x2;
3379                                     if (Right <= Left)
3380                                         continue;
3381                                 }
3382
3383                                 if (GFX.r2131 & 0x80)
3384                                 {
3385                                     if (GFX.r2131 & 0x40)
3386                                     {
3387                                         // Subtract, halving the result.
3388                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3389                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3390                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3391                                         register uint8 *e = d + Right;
3392                                         uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3393
3394                                         d += Left;
3395                                         while (d < e)
3396                                         {
3397                                             if (*d == 0)
3398                                             {
3399                                                 if (*s)
3400                                                 {
3401                                                     if (*s != 1)
3402                                                         *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3403                                                     else
3404                                                         *p = back_fixed;
3405                                                 }
3406                                                 else
3407                                                     *p = (uint16) back;
3408                                             }
3409                                             d++;
3410                                             p++;
3411                                             s++;
3412                                         }
3413                                     }
3414                                     else
3415                                     {
3416                                         // Subtract
3417                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3418                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3419                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3420                                         register uint8 *e = d + Right;
3421                                         uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3422
3423                                         d += Left;
3424                                         while (d < e)
3425                                         {
3426                                             if (*d == 0)
3427                                             {
3428                                                 if (*s)
3429                                                 {
3430                                                     if (*s != 1)
3431                                                         *p = COLOR_SUB (back, *(p + GFX.Delta));
3432                                                     else
3433                                                         *p = back_fixed;
3434                                                 }
3435                                                 else
3436                                                     *p = (uint16) back;
3437                                             }
3438                                             d++;
3439                                             p++;
3440                                             s++;
3441                                         }
3442                                     }
3443                                 }
3444                                 else
3445                                 if (GFX.r2131 & 0x40)
3446                                 {
3447                                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3448                                     register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3449                                     register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3450                                     register uint8 *e = d + Right;
3451                                     uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3452                                     d += Left;
3453                                     while (d < e)
3454                                     {
3455                                         if (*d == 0)
3456                                         {
3457                                             if (*s)
3458                                             {
3459                                                 if (*s != 1)
3460                                                     *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3461                                                 else
3462                                                     *p = back_fixed;
3463                                             }
3464                                             else
3465                                                 *p = (uint16) back;
3466                                         }
3467                                         d++;
3468                                         p++;
3469                                         s++;
3470                                     }
3471                                 }
3472                                 else
3473                                 if (back != 0)
3474                                 {
3475                                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3476                                     register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3477                                     register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3478                                     register uint8 *e = d + Right;
3479                                     uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3480                                     d += Left;
3481                                     while (d < e)
3482                                     {
3483                                         if (*d == 0)
3484                                         {
3485                                             if (*s)
3486                                             {
3487                                                 if (*s != 1)
3488                                                     *p = COLOR_ADD (back, *(p + GFX.Delta));
3489                                                 else    
3490                                                     *p = back_fixed;
3491                                             }
3492                                             else
3493                                                 *p = (uint16) back;
3494                                         }
3495                                         d++;
3496                                         p++;
3497                                         s++;
3498                                     }
3499                                 }
3500                                 else
3501                                 {
3502                                     if (!pClip->Count [5])
3503                                     {
3504                                         // The backdrop has not been cleared yet - so
3505                                         // copy the sub-screen to the main screen
3506                                         // or fill it with the back-drop colour if the
3507                                         // sub-screen is clear.
3508                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3509                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3510                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3511                                         register uint8 *e = d + Right;
3512                                         d += Left;
3513                                         while (d < e)
3514                                         {
3515                                             if (*d == 0)
3516                                             {
3517                                                         if (*s)
3518                                                         {
3519                                                                 if (*s != 1)
3520                                                                         *p = *(p + GFX.Delta);
3521                                                                 else    
3522                                                                         *p = GFX.FixedColour;
3523                                                         }
3524                                                         else
3525                                                                 *p = (uint16) back;
3526                                             }
3527                                             d++;
3528                                             p++;
3529                                             s++;
3530                                         }
3531                                    }
3532                                 }
3533                             }
3534                         }
3535
3536                     }
3537                     else
3538                     {
3539                                 // Subscreen not being added to back
3540                                 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3541                                 pClip = &IPPU.Clip [0];
3542
3543                                 if (pClip->Count [5])
3544                                 {
3545                                         for (uint32 y = starty; y <= endy; y++)
3546                                         {
3547                                                 for (uint32 b = 0; b < pClip->Count [5]; b++)
3548                                                 {
3549                                                         uint32 Left = pClip->Left [b][5] * x2;
3550                                                         uint32 Right = pClip->Right [b][5] * x2;
3551                                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3552                                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3553                                                         register uint8 *e = d + Right;
3554                                                         d += Left;
3555
3556                                                         while (d < e)
3557                                                         {
3558                                                                 if (*d++ == 0)
3559                                                                         *p = (int16) back;
3560                                                                 p++;
3561                                                         }
3562                                                 }
3563                                         }
3564                                 }
3565                                 else
3566                                 {
3567                                         for (uint32 y = starty; y <= endy; y++)
3568                                         {
3569                                                 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3570                                                 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3571                                                 register uint8 *e = d + 256 * x2;
3572
3573                                                 while (d < e)
3574                                                 {
3575                                                         if (*d == 0)
3576 #ifdef RC_OPTIMIZED
3577                                                                 *p++ = back;
3578                                                         d++;
3579 #else
3580                                                         *p = (int16) back;
3581                                                         d++;
3582                                                         p++;
3583 #endif
3584                                                 }
3585                                         }
3586                                 }
3587                     }
3588                 }       
3589                 else
3590                 {
3591                     // 16bit and transparency but currently no transparency effects in
3592                     // operation.
3593
3594                     // get the back colour of the current screen
3595                         uint32 back = IPPU.ScreenColors [0] | 
3596                                  (IPPU.ScreenColors [0] << 16);
3597
3598                     // if forceblanking in use then use black instead of the back color
3599                         if (PPU.ForcedBlanking)
3600                                 back = black;
3601                         
3602                         // not sure what Clip is used for yet
3603                         // could be a check to see if there is any clipping present?
3604                     if (IPPU.Clip [0].Count[5])
3605                     {
3606
3607 #ifdef RC_OPTIMIZED
3608                                 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3609                                 {
3610                                         memset (GFX.Screen + starty * GFX.Pitch2, black,
3611                                                         GFX.Pitch2 * (endy - starty - 1));
3612                                 }
3613                                 else
3614                                 {
3615                                         for (uint32 y = starty; y <= endy; y++)
3616                                         {
3617                                                 memset (GFX.Screen + y * GFX.Pitch2, black,
3618                                                                 GFX.Pitch2);
3619                                         }
3620                                 }
3621                                 for (uint32 y = starty; y <= endy; y++)
3622                                 {
3623                                         for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3624                                         {
3625                                                 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3626                                                 {
3627
3628                                                         memset ((GFX.Screen + y * GFX.Pitch2) + IPPU.Clip [0].Left [c][5] * x2,
3629                                                                         back,
3630                                                                         IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3631                                                 }
3632                                         }
3633                                 }
3634 #else
3635                                 // loop through all of the lines that are going to be updated as part of this screen update
3636                                 for (uint32 y = starty; y <= endy; y++)
3637                                 {
3638                                         memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), black,
3639                                                 IPPU.RenderedScreenWidth>>1);
3640
3641                                         if (black!=back)
3642                                         {
3643                                         for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3644                                         {
3645                                                 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3646                                                 {
3647                                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2); // get pointer to current line in screen buffer
3648                                                         register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3649                                                         p += IPPU.Clip [0].Left [c][5] * x2;
3650
3651                                                         while (p < q)
3652                                                         *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3653                                                 }
3654                                         }
3655                                 }
3656                                 }
3657 #endif
3658                     }
3659                     else
3660                     {
3661 #ifdef RC_OPTIMIZED
3662                                 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3663                                 {
3664                                         memset (GFX.Screen + starty * GFX.Pitch2, back,
3665                                                         GFX.Pitch2 * (endy - starty - 1));
3666                                 }
3667                                 else
3668                                 {
3669                                         for (uint32 y = starty; y <= endy; y++)
3670                                         {
3671                                                 memset (GFX.Screen + y * GFX.Pitch2, back,
3672                                                                 GFX.Pitch2);
3673                                         }
3674                                 }
3675 #else
3676                                 // there is no clipping to worry about so just fill with the back colour
3677                                 for (uint32 y = starty; y <= endy; y++)
3678                                 {
3679                                         memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3680                                                 IPPU.RenderedScreenWidth>>1);
3681                                 }
3682 #endif
3683                     }
3684                         
3685                         // If Forced blanking is not in effect
3686                     if (!PPU.ForcedBlanking)
3687                     {
3688 #ifdef RC_OPTIMIZED
3689                                 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3690                                 {
3691                                         memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3692                                                         GFX.ZPitch * (endy - starty - 1));
3693                                 }
3694                                 else
3695                                 {
3696                                         for (uint32 y = starty; y <= endy; y++)
3697                                         {
3698                                                 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3699                                                                 GFX.ZPitch);
3700                                         }
3701                                 }
3702 #else
3703                                 // Clear the Zbuffer for each of the lines which are going to be updated
3704                                 for (uint32 y = starty; y <= endy; y++)
3705                                 {
3706                                         memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3707                                                 GFX.ZPitch>>2);
3708                                 }
3709 #endif
3710                                 GFX.DB = GFX.ZBuffer;  // save pointer to Zbuffer in GFX object
3711                                 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3712                     }
3713                 }
3714     }
3715     else // Transparencys are disabled, ahh lovely ... nice and easy.
3716         {
3717 #ifndef _SNESPPC
3718                 if (Settings.SixteenBit)
3719 #endif
3720                 {
3721                     // get back colour to be used in clearing the screen
3722                         register uint32 back;
3723                         if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3724                                         (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3725                         {
3726                                 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3727                                            (IPPU.XB[PPU.FixedColourGreen] << 6) | 
3728                                            (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3729                                 back = (back << 16) | back;
3730                         }
3731                         else
3732                         {
3733                                 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3734                         }
3735     
3736                     // if Forcedblanking in use then back colour becomes black
3737                         if (PPU.ForcedBlanking)
3738                                 back = black;
3739                     else
3740                         {
3741                                 SelectTileRenderer (TRUE);  //selects the tile renderers to be used
3742                                                                                         // TRUE means to use the default
3743                                                                                         // FALSE means use best renderer based on current
3744                                                                                         // graphics register settings
3745                         }
3746                     
3747                         // now clear all graphics lines which are being updated using the back colour
3748                         for (register uint32 y = starty; y <= endy; y++)
3749                     {
3750                                 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3751                                         IPPU.RenderedScreenWidth>>1);
3752                     }
3753                 }
3754 #ifndef _SNESPPC
3755                 else // Settings.SixteenBit == false
3756                 {
3757                     // because we are in 8 bit we can just use 0 to clear the screen
3758                         // this means we can use the Zero Memory function
3759                         
3760                         // Loop through all lines being updated and clear the pixels to 0
3761                         for (uint32 y = starty; y <= endy; y++)
3762                     {
3763                         ZeroMemory (GFX.Screen + y * GFX.Pitch2,
3764                                     IPPU.RenderedScreenWidth);
3765                     }
3766                 }
3767 #endif
3768                 if (!PPU.ForcedBlanking)
3769                 {
3770                         // Loop through all lines being updated and clear the
3771                         // zbuffer for each of the lines
3772                         for (uint32 y = starty; y <= endy; y++)
3773                     {
3774                                 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3775                                         IPPU.RenderedScreenWidth>>2);
3776                     }
3777                     GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3778                     GFX.pCurrentClip = &IPPU.Clip [0];
3779
3780 // Define an inline function to handle clipping
3781 #define FIXCLIP(n) \
3782 if (GFX.r212c & (1 << (n))) \
3783         GFX.pCurrentClip = &IPPU.Clip [0]; \
3784 else \
3785         GFX.pCurrentClip = &IPPU.Clip [1]
3786
3787 // Define an inline function to handle which BGs are being displayed
3788 #define DISPLAY(n) \
3789         ( \
3790                 (!(PPU.BG_Forced & n) && (GFX.r212c & n)) || \
3791                 (((GFX.r212d & n) && subadd)) \
3792         )
3793
3794                     uint8 subadd = GFX.r2131 & 0x3f;
3795
3796                         // go through all BGS are check if they need to be displayed
3797                     bool BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3798                     bool BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3799                     bool BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3800                     bool BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3801                     bool OB  = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3802
3803                     if (PPU.BGMode <= 1)
3804                     {
3805                                 // screen modes 0 and 1
3806                                 if (OB)
3807                                 {
3808                                     FIXCLIP(4);
3809                                     DrawOBJS ();
3810                                 }
3811                                 if (BG0)
3812                                 {
3813                                     FIXCLIP(0);
3814                                     DrawBackground (PPU.BGMode, 0, 10, 14);
3815                                 }
3816                                 if (BG1)
3817                                 {
3818                                     FIXCLIP(1);
3819                                     DrawBackground (PPU.BGMode, 1, 9, 13);
3820                                 }
3821                                 if (BG2)
3822                                 {
3823                                     FIXCLIP(2);
3824                                     DrawBackground (PPU.BGMode, 2, 3,
3825                                                     (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3826                                 }
3827                                 if (BG3 && PPU.BGMode == 0)
3828                                 {
3829                                     FIXCLIP(3);
3830                                     DrawBackground (PPU.BGMode, 3, 2, 5);
3831                                 }
3832                     }
3833                     else if (PPU.BGMode != 7)
3834                     {
3835                                 // screen modes 2 and up but not mode 7
3836                                 if (OB)
3837                                 {
3838                                     FIXCLIP(4);
3839                                     DrawOBJS ();
3840                                 }
3841                                 if (BG0)
3842                                 {
3843                                     FIXCLIP(0);
3844                                     DrawBackground (PPU.BGMode, 0, 5, 13);
3845                                 }
3846                                 if (BG1 && PPU.BGMode != 6)
3847                                 {
3848                                     FIXCLIP(1);
3849                                     DrawBackground (PPU.BGMode, 1, 2, 9);
3850                                 }
3851                     }
3852                     else 
3853                     {
3854                                 // screen mode 7
3855                                 if (OB)
3856                                 {
3857                                     FIXCLIP(4);
3858                                     DrawOBJS ();
3859                                 }
3860                                 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3861                                 {
3862                                     int bg;
3863                                     FIXCLIP(0);
3864                                     if (Memory.FillRAM [0x2133] & 0x40)
3865                                     {
3866                                         GFX.Mode7Mask = 0x7f;
3867                                         GFX.Mode7PriorityMask = 0x80;
3868                                         Mode7Depths [0] = 5;
3869                                         Mode7Depths [1] = 9;
3870                                         bg = 1;
3871                                     }
3872                                     else
3873                                     {
3874                                         GFX.Mode7Mask = 0xff;
3875                                         GFX.Mode7PriorityMask = 0;
3876                                         Mode7Depths [0] = 5;
3877                                         Mode7Depths [1] = 5;
3878                                         bg = 0;
3879                                     }
3880
3881 #ifndef _SNESPPC
3882                                     if (!Settings.SixteenBit)
3883                                         DrawBGMode7Background (GFX.Screen, bg);
3884                                     else
3885 #endif
3886                                     {
3887                                         if (!Settings.Mode7Interpolate)
3888                                         {       
3889                                             DrawBGMode7Background16 (GFX.Screen, bg);
3890                                         }
3891                                         else
3892                                         {       
3893                                             DrawBGMode7Background16_i (GFX.Screen, bg);
3894                                         }
3895                                   }
3896                                 }
3897                     }
3898                 }
3899         }
3900 #ifndef RC_OPTIMIZE // no hi res
3901     if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3902     {
3903         if (IPPU.DoubleWidthPixels)
3904         {
3905             // Mixure of background modes used on screen - scale width
3906             // of all non-mode 5 and 6 pixels.
3907 #ifndef _SNESPPC
3908                 if (Settings.SixteenBit)
3909 #endif
3910             {
3911                 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3912                 {
3913                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3914                     register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3915                     for (register int x = 255; x >= 0; x--, p--, q -= 2)
3916                         *q = *(q + 1) = *p;
3917                 }
3918             }
3919 #ifndef _SNESPPC
3920             else
3921             {
3922                 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3923                 {
3924                     register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3925                     register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3926                     for (register int x = 255; x >= 0; x--, p--, q -= 2)
3927                         *q = *(q + 1) = *p;
3928                 }
3929             }
3930 #endif
3931         }
3932
3933         if (IPPU.LatchedInterlace)
3934         {
3935             // Interlace is enabled - double the height of all non-mode 5 and 6
3936             // pixels.
3937             for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3938             {
3939                 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch2),
3940                          (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch2),
3941                          GFX.Pitch2>>2);
3942             }
3943         }
3944     }
3945 #endif
3946     IPPU.PreviousLine = IPPU.CurrentLine;
3947 }
3948
3949 #ifdef GFX_MULTI_FORMAT
3950
3951 #define _BUILD_PIXEL(F) \
3952 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
3953 { \
3954     return (BUILD_PIXEL_##F(R,G,B)); \
3955 }\
3956 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
3957 { \
3958     return (BUILD_PIXEL2_##F(R,G,B)); \
3959 } \
3960 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
3961 { \
3962     DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
3963 }
3964
3965 _BUILD_PIXEL(RGB565)
3966 _BUILD_PIXEL(RGB555)
3967 _BUILD_PIXEL(BGR565)
3968 _BUILD_PIXEL(BGR555)
3969 _BUILD_PIXEL(GBR565)
3970 _BUILD_PIXEL(GBR555)
3971 _BUILD_PIXEL(RGB5551)
3972
3973 bool8_32 S9xSetRenderPixelFormat (int format)
3974 {
3975     extern uint32 current_graphic_format;
3976
3977     current_graphic_format = format;
3978
3979     switch (format)
3980     {
3981     case RGB565:
3982         _BUILD_SETUP(RGB565)
3983         return (TRUE);
3984     case RGB555:
3985         _BUILD_SETUP(RGB555)
3986         return (TRUE);
3987     case BGR565:
3988         _BUILD_SETUP(BGR565)
3989         return (TRUE);
3990     case BGR555:
3991         _BUILD_SETUP(BGR555)
3992         return (TRUE);
3993     case GBR565:
3994         _BUILD_SETUP(GBR565)
3995         return (TRUE);
3996     case GBR555:
3997         _BUILD_SETUP(GBR555)
3998         return (TRUE);
3999     case RGB5551:
4000         _BUILD_SETUP(RGB5551)
4001         return (TRUE);
4002     default:
4003         break;
4004     }
4005     return (FALSE);
4006 }
4007
4008 #endif
4009