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