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