workaround a problem with the harmattan gcc
[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 static inline void SelectTileRenderer (bool 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 static void DrawOBJS (bool 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 static 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 static 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             bool 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 static 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 static 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 static void DrawBGMode7Background16 (uint8 *Screen, int bg)
2181 {
2182     RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2183 }
2184
2185 static void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2186 {
2187     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2188                                         (*(d + GFX.DepthDelta) != 1 ?
2189                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2190                                                        p [GFX.Delta]) :
2191                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2192                                                        GFX.FixedColour)) :
2193                                          GFX.ScreenColors [b & bmask]);
2194 }
2195
2196 static void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2197 {
2198     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2199                                         (*(d + GFX.DepthDelta) != 1 ?
2200                                             COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2201                                                        p [GFX.Delta]) :
2202                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2203                                                        GFX.FixedColour)) :
2204                                          GFX.ScreenColors [b & bmask]);
2205 }
2206
2207 static void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2208 {
2209     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2210                                         (*(d + GFX.DepthDelta) != 1 ?
2211                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2212                                                        p [GFX.Delta]) :
2213                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2214                                                        GFX.FixedColour)) :
2215                                          GFX.ScreenColors [b & bmask]);
2216 }
2217
2218 static void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2219 {
2220     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2221                                         (*(d + GFX.DepthDelta) != 1 ?
2222                                             COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2223                                                        p [GFX.Delta]) :
2224                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2225                                                        GFX.FixedColour)) :
2226                                          GFX.ScreenColors [b & bmask]);
2227 }
2228
2229 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2230     CHECK_SOUND(); \
2231 \
2232     uint8 *VRAM1 = Memory.VRAM + 1; \
2233     if (GFX.r2130 & 1) \
2234     { \
2235         if (IPPU.DirectColourMapsNeedRebuild) \
2236             S9xBuildDirectColourMaps (); \
2237         GFX.ScreenColors = DirectColourMaps [0]; \
2238     } \
2239     else \
2240         GFX.ScreenColors = IPPU.ScreenColors; \
2241     \
2242     int aa, cc; \
2243     int dir; \
2244     int startx, endx; \
2245     uint32 Left = 0; \
2246     uint32 Right = 256; \
2247     uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2248     \
2249     if (!ClipCount) \
2250         ClipCount = 1; \
2251     \
2252     Screen += GFX.StartY * GFX.Pitch; \
2253     uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2254     struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2255     bool allowSimpleCase = false; \
2256     if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2257         && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2258         && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2259         ) \
2260         allowSimpleCase = true;  \
2261     \
2262     for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2263     { \
2264         int yy; \
2265         \
2266         int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2267         int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2268         \
2269         int CentreX = ((int) l->CentreX << M7) >> M7; \
2270         int CentreY = ((int) l->CentreY << M7) >> M7; \
2271         \
2272         if (PPU.Mode7VFlip) \
2273             yy = 261 - (int) Line; \
2274         else \
2275             yy = Line; \
2276         \
2277         if (PPU.Mode7Repeat == 0) \
2278             yy += (VOffset - CentreY) % 1023; \
2279         else \
2280             yy += VOffset - CentreY; \
2281         bool simpleCase = false; \
2282         int BB; \
2283         int DD; \
2284         /* Make a special case for the identity matrix, since it's a common case and */ \
2285         /* can be done much more quickly without special effects */ \
2286         if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2287         { \
2288             BB = CentreX << 8; \
2289             DD = (yy + CentreY) << 8; \
2290             simpleCase = true; \
2291         } \
2292         else \
2293         { \
2294             BB = l->MatrixB * yy + (CentreX << 8); \
2295             DD = l->MatrixD * yy + (CentreY << 8); \
2296         } \
2297         \
2298         for (uint32 clip = 0; clip < ClipCount; clip++) \
2299         { \
2300             if (GFX.pCurrentClip->Count [bg]) \
2301             { \
2302                 Left = GFX.pCurrentClip->Left [clip][bg]; \
2303                 Right = GFX.pCurrentClip->Right [clip][bg]; \
2304                 if (Right <= Left) \
2305                     continue; \
2306             } \
2307             TYPE *p = (TYPE *) Screen + Left; \
2308             uint8 *d = Depth + Left; \
2309             \
2310             if (PPU.Mode7HFlip) \
2311             { \
2312                 startx = Right - 1; \
2313                 endx = Left - 1; \
2314                 dir = -1; \
2315                 aa = -l->MatrixA; \
2316                 cc = -l->MatrixC; \
2317             } \
2318             else \
2319             { \
2320                 startx = Left; \
2321                 endx = Right; \
2322                 dir = 1; \
2323                 aa = l->MatrixA; \
2324                 cc = l->MatrixC; \
2325             } \
2326             int xx; \
2327             if (PPU.Mode7Repeat == 0) \
2328                 xx = startx + (HOffset - CentreX) % 1023; \
2329             else \
2330                 xx = startx + HOffset - CentreX; \
2331             int AA, CC = 0; \
2332             if (simpleCase) \
2333             { \
2334                 AA = xx << 8; \
2335             } \
2336             else \
2337             { \
2338                 AA = l->MatrixA * xx; \
2339                 CC = l->MatrixC * xx; \
2340             } \
2341             if (simpleCase) \
2342             { \
2343                 if (!PPU.Mode7Repeat) \
2344                 { \
2345                     int x = startx; \
2346                     do \
2347                     { \
2348                         int X = ((AA + BB) >> 8) & 0x3ff; \
2349                         int Y = (DD >> 8) & 0x3ff; \
2350                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2351                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2352                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2353                         if (GFX.Z1 > *d && b) \
2354                         { \
2355                             TYPE theColor = COLORFUNC; \
2356                             *p = (FUNC) | ALPHA_BITS_MASK; \
2357                             *d = GFX.Z1; \
2358                         } \
2359                         AA += aa, p++, d++; \
2360                         x += dir; \
2361                     } while (x != endx); \
2362                 } \
2363                 else \
2364                 { \
2365                     int x = startx; \
2366                     do { \
2367                         int X = (AA + BB) >> 8; \
2368                         int Y = DD >> 8; \
2369 \
2370                         if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2371                         { \
2372                             X &= 0x7ff; \
2373                             Y &= 0x7ff; \
2374                         } \
2375 \
2376                         if (((X | Y) & ~0x3ff) == 0) \
2377                         { \
2378                             uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2379                             uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2380                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2381                             if (GFX.Z1 > *d && b) \
2382                             { \
2383                                 TYPE theColor = COLORFUNC; \
2384                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2385                                 *d = GFX.Z1; \
2386                             } \
2387                         } \
2388                         else if (PPU.Mode7Repeat == 3) \
2389                         { \
2390                             X = (x + HOffset) & 7; \
2391                             Y = (yy + CentreY) & 7; \
2392                             uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2393                             uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2394                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2395                             if (GFX.Z1 > *d && b) \
2396                             { \
2397                                 TYPE theColor = COLORFUNC; \
2398                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2399                                 *d = GFX.Z1; \
2400                             } \
2401                         } \
2402                         AA += aa; p++; d++; \
2403                         x += dir; \
2404                     } while (x != endx); \
2405                 } \
2406             } \
2407             else if (!PPU.Mode7Repeat) \
2408             { \
2409                 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2410                 /* the location of one point in the _sampled_ image, and weight them according */ \
2411                 /* to their (city block) distance.  It's very smooth, but blurry with "close up" */ \
2412                 /* points. */ \
2413                 \
2414                 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2415                 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2416                 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2417                 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2418                 /* You can think of this as a kind of mipmapping. */ \
2419                 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2420                 {\
2421                     for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2422                     { \
2423                         uint32 xPos = AA + BB; \
2424                         uint32 xPix = xPos >> 8; \
2425                         uint32 yPos = CC + DD; \
2426                         uint32 yPix = yPos >> 8; \
2427                         uint32 X = xPix & 0x3ff; \
2428                         uint32 Y = yPix & 0x3ff; \
2429                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2430                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2431                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2432                         if (GFX.Z1 > *d && b) \
2433                         { \
2434                             /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2435                             uint32 X10 = (xPix + dir) & 0x3ff; \
2436                             uint32 Y01 = (yPix + dir) & 0x3ff; \
2437                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2438                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2439                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2440                             uint32 p1 = COLORFUNC; \
2441                             p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2442                             b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2443                             uint32 p2 = COLORFUNC; \
2444                             p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2445                             b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2446                             uint32 p4 = COLORFUNC; \
2447                             p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2448                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2449                             uint32 p3 = COLORFUNC; \
2450                             p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2451                             /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2452                             uint32 Xdel = (xPos >> 3) & 0x1F; \
2453                             uint32 Ydel = (yPos >> 3) & 0x1F; \
2454                             uint32 XY = (Xdel*Ydel) >> 5; \
2455                             uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2456                             uint32 area2 = Xdel - XY; \
2457                             uint32 area3 = Ydel - XY; \
2458                             uint32 area4 = XY; \
2459                             uint32 tempColor = ((area1 * p1) + \
2460                                                 (area2 * p2) + \
2461                                                 (area3 * p3) + \
2462                                                 (area4 * p4)) >> 5; \
2463                             TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2464                             *p = (FUNC) | ALPHA_BITS_MASK; \
2465                             *d = GFX.Z1; \
2466                         } \
2467                     } \
2468                 } \
2469                 else \
2470                     /* The oversampling method: get the colors at four corners of a square */ \
2471                     /* in the _displayed_ image, and average them.  It's sharp and clean, but */ \
2472                     /* gives the usual huge pixels when the source image gets "close." */ \
2473                 { \
2474                     /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2475                     uint32 aaDelX = aa >> 1; \
2476                     uint32 ccDelX = cc >> 1; \
2477                     uint32 bbDelY = l->MatrixB >> 1; \
2478                     uint32 ddDelY = l->MatrixD >> 1; \
2479                     /* Offset the location within the source image so that the four sampled points */ \
2480                     /* center around where the single point would otherwise have been drawn. */ \
2481                     BB -= (bbDelY >> 1); \
2482                     DD -= (ddDelY >> 1); \
2483                     AA -= (aaDelX >> 1); \
2484                     CC -= (ccDelX >> 1); \
2485                     uint32 BB10 = BB + aaDelX; \
2486                     uint32 BB01 = BB + bbDelY; \
2487                     uint32 BB11 = BB + aaDelX + bbDelY; \
2488                     uint32 DD10 = DD + ccDelX; \
2489                     uint32 DD01 = DD + ddDelY; \
2490                     uint32 DD11 = DD + ccDelX + ddDelY; \
2491                     for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2492                     { \
2493                         uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2494                         uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2495                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2496                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2497                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2498                         if (GFX.Z1 > *d && b) \
2499                         { \
2500                             /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2501                             /* source image that we're going to examine. */ \
2502                             uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2503                             uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2504                             uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2505                             uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2506                             uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2507                             uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2508                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2509                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2510                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2511                             TYPE p1 = COLORFUNC; \
2512                             b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2513                             TYPE p2 = COLORFUNC; \
2514                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2515                             TYPE p3 = COLORFUNC; \
2516                             b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2517                             TYPE p4 = COLORFUNC; \
2518                             TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2519                             *p = (FUNC) | ALPHA_BITS_MASK; \
2520                             *d = GFX.Z1; \
2521                         } \
2522                     } \
2523                 } \
2524             } \
2525             else \
2526             { \
2527                 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2528                 { \
2529                     uint32 xPos = AA + BB; \
2530                     uint32 xPix = xPos >> 8; \
2531                     uint32 yPos = CC + DD; \
2532                     uint32 yPix = yPos >> 8; \
2533                     uint32 X = xPix; \
2534                     uint32 Y = yPix; \
2535                     \
2536 \
2537                     if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2538                     { \
2539                         X &= 0x7ff; \
2540                         Y &= 0x7ff; \
2541                     } \
2542 \
2543                     if (((X | Y) & ~0x3ff) == 0) \
2544                     { \
2545                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2546                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2547                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2548                         if (GFX.Z1 > *d && b) \
2549                         { \
2550                             /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2551                             uint32 X10 = (xPix + dir) & 0x3ff; \
2552                             uint32 Y01 = (yPix + dir) & 0x3ff; \
2553                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2554                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2555                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2556                             uint32 p1 = COLORFUNC; \
2557                             p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2558                             b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2559                             uint32 p2 = COLORFUNC; \
2560                             p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2561                             b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2562                             uint32 p4 = COLORFUNC; \
2563                             p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2564                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2565                             uint32 p3 = COLORFUNC; \
2566                             p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2567                             /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2568                             uint32 Xdel = (xPos >> 3) & 0x1F; \
2569                             uint32 Ydel = (yPos >> 3) & 0x1F; \
2570                             uint32 XY = (Xdel*Ydel) >> 5; \
2571                             uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2572                             uint32 area2 = Xdel - XY; \
2573                             uint32 area3 = Ydel - XY; \
2574                             uint32 area4 = XY; \
2575                             uint32 tempColor = ((area1 * p1) + \
2576                                                 (area2 * p2) + \
2577                                                 (area3 * p3) + \
2578                                                 (area4 * p4)) >> 5; \
2579                             TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2580                             *p = (FUNC) | ALPHA_BITS_MASK; \
2581                             *d = GFX.Z1; \
2582                         } \
2583                     } \
2584                     else \
2585                     { \
2586                         if (PPU.Mode7Repeat == 3) \
2587                         { \
2588                             X = (x + HOffset) & 7; \
2589                             Y = (yy + CentreY) & 7; \
2590                             uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2591                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2592                             if (GFX.Z1 > *d && b) \
2593                             { \
2594                                 TYPE theColor = COLORFUNC; \
2595                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2596                                 *d = GFX.Z1; \
2597                             } \
2598                         } \
2599                     } \
2600                 } \
2601             } \
2602         } \
2603     }
2604
2605 static inline uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2606 {
2607     register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2608                             ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2609                             ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2610                             ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2611     register uint32 y = (A & TWO_LOW_BITS_MASK) +
2612                             (B & TWO_LOW_BITS_MASK) +
2613                             (C & TWO_LOW_BITS_MASK) +
2614                             (D & TWO_LOW_BITS_MASK);
2615     y = (y>>2) & TWO_LOW_BITS_MASK;
2616     return x+y;
2617 }
2618
2619 static void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2620 {
2621     RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2622 }
2623
2624 static void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2625 {
2626     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2627                                         (*(d + GFX.DepthDelta) != 1 ?
2628                                             (COLOR_ADD (theColor,
2629                                                        p [GFX.Delta])) :
2630                                             (COLOR_ADD (theColor,
2631                                                        GFX.FixedColour))) :
2632                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2633 }
2634
2635 static void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2636 {
2637     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2638                                         (*(d + GFX.DepthDelta) != 1 ?
2639                                             COLOR_ADD1_2 (theColor,
2640                                                           p [GFX.Delta]) :
2641                                             COLOR_ADD (theColor,
2642                                                        GFX.FixedColour)) :
2643                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2644 }
2645
2646 static void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2647 {
2648     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2649                                         (*(d + GFX.DepthDelta) != 1 ?
2650                                             COLOR_SUB (theColor,
2651                                                        p [GFX.Delta]) :
2652                                             COLOR_SUB (theColor,
2653                                                        GFX.FixedColour)) :
2654                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2655 }
2656
2657 static void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2658 {
2659     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2660                                         (*(d + GFX.DepthDelta) != 1 ?
2661                                             COLOR_SUB1_2 (theColor,
2662                                                        p [GFX.Delta]) :
2663                                             COLOR_SUB (theColor,
2664                                                        GFX.FixedColour)) :
2665                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2666 }
2667
2668 #define _BUILD_SETUP(F) \
2669 GFX.BuildPixel = BuildPixel##F; \
2670 GFX.BuildPixel2 = BuildPixel2##F; \
2671 GFX.DecomposePixel = DecomposePixel##F; \
2672 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2673 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2674 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2675 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2676 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2677 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2678 MAX_RED = MAX_RED_##F; \
2679 MAX_GREEN = MAX_GREEN_##F; \
2680 MAX_BLUE = MAX_BLUE_##F; \
2681 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2682 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2683 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2684                      GREEN_LOW_BIT_MASK_##F | \
2685                      BLUE_LOW_BIT_MASK_##F); \
2686 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2687                     GREEN_HI_BIT_MASK_##F | \
2688                     BLUE_HI_BIT_MASK_##F); \
2689 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2690                        GREEN_HI_BIT_MASK_##F | \
2691                        BLUE_HI_BIT_MASK_##F) << 1); \
2692 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2693 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2694 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2695 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2696 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2697 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2698 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2699 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2700                                 ~TWO_LOW_BITS_MASK ) >> 2);
2701
2702 static void RenderScreen(uint8 *Screen, bool sub, bool force_no_add, uint8 D)
2703 {
2704     bool BG0, BG1, BG2, BG3, OB;
2705
2706     GFX.S = Screen;
2707
2708     if (!sub)
2709     {
2710         GFX.pCurrentClip = &IPPU.Clip [0];
2711         BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2712         BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2713         BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2714         BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2715         OB  = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2716     }
2717     else
2718     {
2719         GFX.pCurrentClip = &IPPU.Clip [1];
2720         BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2721         BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2722         BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2723         BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2724         OB  = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2725     }
2726
2727     sub |= force_no_add;
2728
2729     if (PPU.BGMode <= 1)
2730     {
2731         if (OB)
2732         {
2733             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2734             DrawOBJS (!sub, D);
2735         }
2736         if (BG0)
2737         {
2738             SelectTileRenderer (sub || !SUB_OR_ADD(0));
2739             DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2740         }
2741         if (BG1)
2742         {
2743             SelectTileRenderer (sub || !SUB_OR_ADD(1));
2744             DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2745         }
2746         if (BG2)
2747         {
2748             SelectTileRenderer (sub || !SUB_OR_ADD(2));
2749             DrawBackground (PPU.BGMode, 2, D + 3, 
2750                             (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2751         }
2752         if (BG3 && PPU.BGMode == 0)
2753         {
2754             SelectTileRenderer (sub || !SUB_OR_ADD(3));
2755             DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2756         }
2757     }
2758     else if (PPU.BGMode != 7)
2759     {
2760         if (OB)
2761         {
2762             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2763             DrawOBJS (!sub, D);
2764         }
2765         if (BG0)
2766         {
2767             SelectTileRenderer (sub || !SUB_OR_ADD(0));
2768             DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2769         }
2770         if (PPU.BGMode != 6 && BG1)
2771         {
2772             SelectTileRenderer (sub || !SUB_OR_ADD(1));
2773             DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2774         }
2775     }
2776     else
2777     {
2778         if (OB)
2779         {
2780             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2781             DrawOBJS (!sub, D);
2782         }
2783         if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2784         {
2785             int bg;
2786
2787             if (Memory.FillRAM [0x2133] & 0x40)
2788             {
2789                 GFX.Mode7Mask = 0x7f;
2790                 GFX.Mode7PriorityMask = 0x80;
2791                 Mode7Depths [0] = 5 + D;
2792                 Mode7Depths [1] = 9 + D;
2793                 bg = 1;
2794             }
2795             else
2796             {
2797                 GFX.Mode7Mask = 0xff;
2798                 GFX.Mode7PriorityMask = 0;
2799                 Mode7Depths [0] = 5 + D;
2800                 Mode7Depths [1] = 5 + D;
2801                 bg = 0;
2802             }
2803             if (sub || !SUB_OR_ADD(0))
2804             {
2805                 if (!Settings.Mode7Interpolate)
2806                     DrawBGMode7Background16 (Screen, bg);
2807                 else
2808                     DrawBGMode7Background16_i (Screen, bg);
2809             }
2810             else
2811             {
2812                 if (GFX.r2131 & 0x80)
2813                 {
2814                     if (GFX.r2131 & 0x40)
2815                     {
2816                         if (!Settings.Mode7Interpolate)
2817                             DrawBGMode7Background16Sub1_2 (Screen, bg);
2818                         else
2819                             DrawBGMode7Background16Sub1_2_i (Screen, bg);
2820                     }
2821                     else
2822                     {
2823                         if (!Settings.Mode7Interpolate)
2824                             DrawBGMode7Background16Sub (Screen, bg);
2825                         else
2826                             DrawBGMode7Background16Sub_i (Screen, bg);
2827                     }
2828                 }
2829                 else
2830                 {
2831                     if (GFX.r2131 & 0x40)
2832                     {
2833                         if (!Settings.Mode7Interpolate)
2834                             DrawBGMode7Background16Add1_2 (Screen, bg);
2835                         else
2836                             DrawBGMode7Background16Add1_2_i (Screen, bg);
2837                     }
2838                     else
2839                     {
2840                         if (!Settings.Mode7Interpolate)
2841                             DrawBGMode7Background16Add (Screen, bg);
2842                         else
2843                             DrawBGMode7Background16Add_i (Screen, bg);
2844                     }
2845                 }
2846             }
2847         }
2848     }
2849 }
2850
2851 #include "font.h"
2852
2853 static void DisplayChar(uint8 *Screen, uint8 c)
2854 {
2855     int line = (((c & 0x7f) - 32) >> 4) * font_height;
2856     int offset = (((c & 0x7f) - 32) & 15) * font_width;
2857
2858         int h, w;
2859         uint16 *s = (uint16 *) Screen;
2860         for (h = 0; h < font_height; h++, line++,
2861              s += GFX.PPL - font_width)
2862         {
2863             for (w = 0; w < font_width; w++, s++)
2864             {
2865                 uint8 p = font [line][offset + w];
2866
2867                 if (p == '#')
2868                     *s = 0xffff;
2869                 else
2870                 if (p == '.')
2871                     *s = BLACK;
2872             }
2873         }
2874 }
2875
2876 static void S9xDisplayFrameRate()
2877 {
2878     const unsigned int char_width = (font_width - 1) * sizeof (uint16);
2879         uint8 *Screen = GFX.Screen + 2 +
2880                 (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch;
2881         char string[12];
2882     int len;
2883
2884         if (Settings.TurboMode) {
2885                 len = sprintf(string, "%u",
2886                         IPPU.DisplayedRenderedFrameCount);
2887         } else {
2888                 len = sprintf(string, "%2u/%02u",
2889                         IPPU.DisplayedRenderedFrameCount,
2890                         (unsigned int) Memory.ROMFramesPerSecond);
2891         }
2892
2893         for (int i = 0; i < len; i++) {
2894                 DisplayChar(Screen, string[i]);
2895                 Screen += char_width;
2896         }
2897 }
2898
2899 static void S9xDisplayString(const char *string)
2900 {
2901     const unsigned int char_width = (font_width - 1) * sizeof (uint16);
2902     uint8 *Screen = GFX.Screen + 2 +
2903                     (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch;
2904     int len = strlen (string);
2905     int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
2906     int char_count = 0;
2907     int i;
2908
2909     for (i = 0; i < len; i++, char_count++)
2910     {
2911         if (char_count >= max_chars || string [i] < 32)
2912         {
2913             Screen -= char_width * max_chars;
2914             Screen += font_height * GFX.Pitch;
2915             if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
2916                 break;
2917             char_count -= max_chars;
2918         }
2919         if (string [i] < 32)
2920             continue;
2921         DisplayChar (Screen, string [i]);
2922         Screen += char_width;
2923     }
2924 }
2925
2926 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
2927 {
2928     int32 x2 = 1;
2929
2930     GFX.S = GFX.Screen;
2931
2932         unsigned char *memoryfillram = Memory.FillRAM;
2933
2934         // get local copies of vid registers to be used later
2935     GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN 
2936     GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
2937     GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
2938     GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
2939         
2940         // If external sync is off and
2941         // main screens have not been configured the same as the sub screen and
2942         // color addition and subtraction has been diabled then
2943         // Pseudo is 1
2944         // anything else it is 0
2945         GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
2946                  (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
2947                  (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
2948
2949         // If sprite data has been changed then go through and 
2950         // refresh the sprites.
2951     if (IPPU.OBJChanged)
2952         {       
2953                 S9xSetupOBJ ();
2954         }
2955
2956     if (PPU.RecomputeClipWindows)
2957     {
2958                 ComputeClipWindows ();
2959                 PPU.RecomputeClipWindows = FALSE;
2960     }
2961
2962     GFX.StartY = IPPU.PreviousLine;
2963     if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
2964                 GFX.EndY = PPU.ScreenHeight - 1;
2965
2966     uint32 starty = GFX.StartY;
2967     uint32 endy = GFX.EndY;
2968
2969 #ifndef RC_OPTIMIZED
2970         if (Settings.SupportHiRes &&
2971           (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace)) {
2972                 if (PPU.BGMode == 5 || PPU.BGMode == 6) {
2973                     IPPU.RenderedScreenWidth = 512;
2974                     x2 = 2;
2975                 }
2976
2977                 if (IPPU.LatchedInterlace) {
2978                         starty = GFX.StartY * 2;
2979                         endy = GFX.EndY * 2 + 1;
2980                 }
2981
2982                 if (!IPPU.DoubleWidthPixels) {
2983                         // The game has switched from lo-res to hi-res mode part way down
2984                         // the screen. Scale any existing lo-res pixels on screen
2985                         for (register uint32 y = 0; y < GFX.StartY; y++) {
2986                                 register uint16 *p =
2987                                         (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
2988                                 register uint16 *q =
2989                                         (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
2990                                 for (register int x = 255; x >= 0; x--, p--, q -= 2) {
2991                                         *q = *(q + 1) = *p;
2992                                 }
2993                         }
2994
2995                         IPPU.DoubleWidthPixels = TRUE;
2996                 }
2997         }
2998 #endif //RC_OPTIMIZED (DONT DO ABOVE)
2999
3000     uint32 black = BLACK | (BLACK << 16);
3001
3002         // Are we worrying about transparencies?
3003     if (Settings.Transparency)
3004     {
3005                 if (GFX.Pseudo)
3006                 {
3007                         GFX.r2131 = 0x5f;  //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3008                         GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3009                                  Memory.FillRAM [0x212d]) & 15;
3010                         GFX.r212c &= ~GFX.r212d;  // make sure the main BG reg is the reverse of the sub BG reg
3011                         GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3012                 }
3013
3014                 // Check to see if any transparency effects are currently in use
3015                 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3016                         (GFX.r2130 & 0x30) != 0x30 &&
3017                         !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3018                 {
3019                         // transparency effects in use, so lets get busy!
3020                         struct ClipData *pClip;
3021                         uint32 fixedColour;
3022                         GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3023                                                    IPPU.XB [PPU.FixedColourGreen],
3024                                                    IPPU.XB [PPU.FixedColourBlue]);
3025                         fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3026                         // Clear the z-buffer, marking areas 'covered' by the fixed
3027                         // colour as depth 1.
3028                         pClip = &IPPU.Clip [1];
3029
3030                         // Clear the z-buffer
3031                         
3032                     if (pClip->Count [5])
3033                     {
3034
3035                                 // Colour window enabled.
3036 #ifdef RC_OPTIMIZED
3037                                 for (uint32 y = starty; y <= endy; y++)
3038                                 {
3039                         ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3040                                                 IPPU.RenderedScreenWidth);
3041                                         ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3042                                                 IPPU.RenderedScreenWidth);
3043
3044                         if (IPPU.Clip [0].Count [5])
3045                                         {
3046                                                 memset ((GFX.SubScreen + y * GFX.Pitch), black, IPPU.RenderedScreenWidth);
3047                                         }
3048                                         for (uint32 c = 0; c < pClip->Count [5]; c++)
3049                                         {
3050                                                 if (pClip->Right [c][5] > pClip->Left [c][5])
3051                                                 {
3052                                                         memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3053                                                                 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3054                                                         if (IPPU.Clip [0].Count [5])
3055                                                         {
3056                                                         // Blast, have to clear the sub-screen to the fixed-colour
3057                                                         // because there is a colour window in effect clipping
3058                                                         // the main screen that will allow the sub-screen
3059                                                         // 'underneath' to show through.
3060                                                         memset ((GFX.SubScreen + y * GFX.Pitch) + pClip->Left [c][5] * x2,
3061                                                                          GFX.FixedColour,
3062                                                                          pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3063                                                         }
3064                                                 }
3065                                         }
3066                                 }
3067
3068 #else // NOT RC_OPTIMIZED
3069                                 // loop around all of the lines being updated
3070                                 for (uint32 y = starty; y <= endy; y++)
3071                                 {
3072                                         // Clear the subZbuffer
3073                                         memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3074                                                 IPPU.RenderedScreenWidth>>2);
3075                                         // Clear the Zbuffer
3076                                         memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3077                                                 IPPU.RenderedScreenWidth>>2);
3078
3079                                         // if there is clipping then clear subscreen to a black color
3080                                         if (IPPU.Clip [0].Count [5])
3081                                         {
3082                                                 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch), black, IPPU.RenderedScreenWidth>>1);
3083                                         }
3084
3085                                         // loop through all window clippings
3086                                         for (uint32 c = 0; c < pClip->Count [5]; c++)
3087                                         {
3088                                                 if (pClip->Right [c][5] > pClip->Left [c][5])
3089                                                 {
3090                                                         memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3091                                                                 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3092                                                         if (IPPU.Clip [0].Count [5])
3093                                                         {
3094                                                         // Blast, have to clear the sub-screen to the fixed-colour
3095                                                         // because there is a colour window in effect clipping
3096                                                         // the main screen that will allow the sub-screen
3097                                                         // 'underneath' to show through.
3098
3099                                                         register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch);
3100                                                         register uint16 *q = p + pClip->Right [c][5] * x2;
3101                                                         p += pClip->Left [c][5] * x2;
3102
3103                                                         while (p < q)
3104                                                                 *p++ = (uint16) GFX.FixedColour;
3105                                                         }
3106                                                 }
3107                                         }
3108                                 }
3109 #endif
3110
3111                     }
3112                     else
3113                     {
3114                                 // No windows are clipping the main screen
3115                                 // this simplifies the screen clearing process
3116 #ifdef RC_OPTIMIZED
3117
3118                         if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3119                         {
3120
3121                                 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3122                                 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3123                         }
3124                         else
3125                         {
3126                                 for (uint32 y = starty; y <= endy; y++)
3127                                 {
3128                                         ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3129                                                 IPPU.RenderedScreenWidth);
3130                                         memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3131                                                 IPPU.RenderedScreenWidth);
3132                                 }
3133                         }
3134                         
3135                     if (IPPU.Clip [0].Count [5])
3136                     {
3137                                 // Blast, have to clear the sub-screen to the fixed-colour
3138                                 // because there is a colour window in effect clipping
3139                                 // the main screen that will allow the sub-screen
3140                                 // 'underneath' to show through.
3141                                 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3142                                 {
3143                                         memset ((GFX.SubScreen + starty * GFX.Pitch), 
3144                                                         GFX.FixedColour | (GFX.FixedColour << 16),
3145                                                         GFX.Pitch * (endy - starty - 1));
3146                                 }
3147                                 else
3148                                 {
3149                                         for (uint32 y = starty; y <= endy; y++)
3150                                         {
3151                                                 memset ((GFX.SubScreen + y * GFX.Pitch), 
3152                                                                 GFX.FixedColour | (GFX.FixedColour << 16),
3153                                                                 IPPU.RenderedScreenWidth);
3154                                         }
3155                                 }
3156                         }
3157
3158 #else // NOT RC_OPTIMIZED
3159                         // loop through all of the lines to be updated
3160                         for (uint32 y = starty; y <= endy; y++)
3161                         {
3162                                 // Clear the Zbuffer
3163                                 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3164                                         IPPU.RenderedScreenWidth>>2);
3165                             // clear the sub Zbuffer to 1
3166                                 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3167                                     IPPU.RenderedScreenWidth>>2);
3168                             if (IPPU.Clip [0].Count [5])
3169                             {
3170                                 // Blast, have to clear the sub-screen to the fixed-colour
3171                                 // because there is a colour window in effect clipping
3172                                 // the main screen that will allow the sub-screen
3173                                 // 'underneath' to show through.
3174
3175
3176                                 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch), fixedColour,
3177                                     IPPU.RenderedScreenWidth>>1);
3178                             }
3179                         }
3180 #endif
3181
3182                         }
3183
3184                     if (ANYTHING_ON_SUB)
3185                     {
3186                                 GFX.DB = GFX.SubZBuffer;
3187                                 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3188                     }
3189
3190                     if (IPPU.Clip [0].Count [5])
3191                     {
3192                                         for (uint32 y = starty; y <= endy; y++)
3193                         {
3194                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch);
3195                                         register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3196                                         register uint8 *e = d + SNES_WIDTH;
3197
3198                                         while (d < e)
3199                                 {
3200                                                 if (*d > 1)
3201                                                         *p = *(p + GFX.Delta);
3202                                 else
3203                                                         *p = BLACK;
3204                                                 d++;
3205                                                 p++;
3206                             }
3207                         }
3208                     }
3209
3210                     GFX.DB = GFX.ZBuffer;
3211                     RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3212                     if (SUB_OR_ADD(5))
3213                     {
3214                         uint32 back = IPPU.ScreenColors [0];
3215                         uint32 Left = 0;
3216                         uint32 Right = 256;
3217                         uint32 Count;
3218
3219                         pClip = &IPPU.Clip [0];
3220
3221                         for (uint32 y = starty; y <= endy; y++)
3222                         {
3223                             if (!(Count = pClip->Count [5]))
3224                             {
3225                                 Left = 0;
3226                                 Right = 256 * x2;
3227                                 Count = 1;
3228                             }
3229
3230                             for (uint32 b = 0; b < Count; b++)
3231                             {
3232                                 if (pClip->Count [5])
3233                                 {
3234                                     Left = pClip->Left [b][5] * x2;
3235                                     Right = pClip->Right [b][5] * x2;
3236                                     if (Right <= Left)
3237                                         continue;
3238                                 }
3239
3240                                 if (GFX.r2131 & 0x80)
3241                                 {
3242                                     if (GFX.r2131 & 0x40)
3243                                     {
3244                                         // Subtract, halving the result.
3245                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3246                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3247                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3248                                         register uint8 *e = d + Right;
3249                                         uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3250
3251                                         d += Left;
3252                                         while (d < e)
3253                                         {
3254                                             if (*d == 0)
3255                                             {
3256                                                 if (*s)
3257                                                 {
3258                                                     if (*s != 1)
3259                                                         *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3260                                                     else
3261                                                         *p = back_fixed;
3262                                                 }
3263                                                 else
3264                                                     *p = (uint16) back;
3265                                             }
3266                                             d++;
3267                                             p++;
3268                                             s++;
3269                                         }
3270                                     }
3271                                     else
3272                                     {
3273                                         // Subtract
3274                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3275                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3276                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3277                                         register uint8 *e = d + Right;
3278                                         uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3279
3280                                         d += Left;
3281                                         while (d < e)
3282                                         {
3283                                             if (*d == 0)
3284                                             {
3285                                                 if (*s)
3286                                                 {
3287                                                     if (*s != 1)
3288                                                         *p = COLOR_SUB (back, *(p + GFX.Delta));
3289                                                     else
3290                                                         *p = back_fixed;
3291                                                 }
3292                                                 else
3293                                                     *p = (uint16) back;
3294                                             }
3295                                             d++;
3296                                             p++;
3297                                             s++;
3298                                         }
3299                                     }
3300                                 }
3301                                 else
3302                                 if (GFX.r2131 & 0x40)
3303                                 {
3304                                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3305                                     register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3306                                     register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3307                                     register uint8 *e = d + Right;
3308                                     uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3309                                     d += Left;
3310                                     while (d < e)
3311                                     {
3312                                         if (*d == 0)
3313                                         {
3314                                             if (*s)
3315                                             {
3316                                                 if (*s != 1)
3317                                                     *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3318                                                 else
3319                                                     *p = back_fixed;
3320                                             }
3321                                             else
3322                                                 *p = (uint16) back;
3323                                         }
3324                                         d++;
3325                                         p++;
3326                                         s++;
3327                                     }
3328                                 }
3329                                 else
3330                                 if (back != 0)
3331                                 {
3332                                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3333                                     register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3334                                     register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3335                                     register uint8 *e = d + Right;
3336                                     uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3337                                     d += Left;
3338                                     while (d < e)
3339                                     {
3340                                         if (*d == 0)
3341                                         {
3342                                             if (*s)
3343                                             {
3344                                                 if (*s != 1)
3345                                                     *p = COLOR_ADD (back, *(p + GFX.Delta));
3346                                                 else    
3347                                                     *p = back_fixed;
3348                                             }
3349                                             else
3350                                                 *p = (uint16) back;
3351                                         }
3352                                         d++;
3353                                         p++;
3354                                         s++;
3355                                     }
3356                                 }
3357                                 else
3358                                 {
3359                                     if (!pClip->Count [5])
3360                                     {
3361                                         // The backdrop has not been cleared yet - so
3362                                         // copy the sub-screen to the main screen
3363                                         // or fill it with the back-drop colour if the
3364                                         // sub-screen is clear.
3365                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3366                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3367                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3368                                         register uint8 *e = d + Right;
3369                                         d += Left;
3370                                         while (d < e)
3371                                         {
3372                                             if (*d == 0)
3373                                             {
3374                                                         if (*s)
3375                                                         {
3376                                                                 if (*s != 1)
3377                                                                         *p = *(p + GFX.Delta);
3378                                                                 else    
3379                                                                         *p = GFX.FixedColour;
3380                                                         }
3381                                                         else
3382                                                                 *p = (uint16) back;
3383                                             }
3384                                             d++;
3385                                             p++;
3386                                             s++;
3387                                         }
3388                                    }
3389                                 }
3390                             }
3391                         }
3392
3393                     }
3394                     else
3395                     {
3396                                 // Subscreen not being added to back
3397                                 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3398                                 pClip = &IPPU.Clip [0];
3399
3400                                 if (pClip->Count [5])
3401                                 {
3402                                         for (uint32 y = starty; y <= endy; y++)
3403                                         {
3404                                                 for (uint32 b = 0; b < pClip->Count [5]; b++)
3405                                                 {
3406                                                         uint32 Left = pClip->Left [b][5] * x2;
3407                                                         uint32 Right = pClip->Right [b][5] * x2;
3408                                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + Left;
3409                                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3410                                                         register uint8 *e = d + Right;
3411                                                         d += Left;
3412
3413                                                         while (d < e)
3414                                                         {
3415                                                                 if (*d++ == 0)
3416                                                                         *p = (int16) back;
3417                                                                 p++;
3418                                                         }
3419                                                 }
3420                                         }
3421                                 }
3422                                 else
3423                                 {
3424                                         for (uint32 y = starty; y <= endy; y++)
3425                                         {
3426                                                 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch);
3427                                                 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3428                                                 register uint8 *e = d + 256 * x2;
3429
3430                                                 while (d < e)
3431                                                 {
3432                                                         if (*d == 0)
3433 #ifdef RC_OPTIMIZED
3434                                                                 *p++ = back;
3435                                                         d++;
3436 #else
3437                                                         *p = (int16) back;
3438                                                         d++;
3439                                                         p++;
3440 #endif
3441                                                 }
3442                                         }
3443                                 }
3444                     }
3445                 }       
3446                 else
3447                 {
3448                     // 16bit and transparency but currently no transparency effects in
3449                     // operation.
3450
3451                     // get the back colour of the current screen
3452                         uint32 back = IPPU.ScreenColors [0] | 
3453                                  (IPPU.ScreenColors [0] << 16);
3454
3455                     // if forceblanking in use then use black instead of the back color
3456                         if (PPU.ForcedBlanking)
3457                                 back = black;
3458                         
3459                         // not sure what Clip is used for yet
3460                         // could be a check to see if there is any clipping present?
3461                     if (IPPU.Clip [0].Count[5])
3462                     {
3463
3464 #ifdef RC_OPTIMIZED
3465                                 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3466                                 {
3467                                         memset (GFX.Screen + starty * GFX.Pitch, black,
3468                                                         GFX.Pitch * (endy - starty - 1));
3469                                 }
3470                                 else
3471                                 {
3472                                         for (uint32 y = starty; y <= endy; y++)
3473                                         {
3474                                                 memset (GFX.Screen + y * GFX.Pitch, black,
3475                                                                 GFX.Pitch);
3476                                         }
3477                                 }
3478                                 for (uint32 y = starty; y <= endy; y++)
3479                                 {
3480                                         for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3481                                         {
3482                                                 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3483                                                 {
3484
3485                                                         memset ((GFX.Screen + y * GFX.Pitch) + IPPU.Clip [0].Left [c][5] * x2,
3486                                                                         back,
3487                                                                         IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3488                                                 }
3489                                         }
3490                                 }
3491 #else
3492                                 // loop through all of the lines that are going to be updated as part of this screen update
3493                                 for (uint32 y = starty; y <= endy; y++)
3494                                 {
3495                                         memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), black,
3496                                                 IPPU.RenderedScreenWidth>>1);
3497
3498                                         if (black!=back)
3499                                         {
3500                                         for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3501                                         {
3502                                                 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3503                                                 {
3504                                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch); // get pointer to current line in screen buffer
3505                                                         register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3506                                                         p += IPPU.Clip [0].Left [c][5] * x2;
3507
3508                                                         while (p < q)
3509                                                         *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3510                                                 }
3511                                         }
3512                                 }
3513                                 }
3514 #endif
3515                     }
3516                     else
3517                     {
3518 #ifdef RC_OPTIMIZED
3519                                 if (GFX.Pitch == (uint32)IPPU.RenderedScreenWidth)
3520                                 {
3521                                         memset (GFX.Screen + starty * GFX.Pitch, back,
3522                                                         GFX.Pitch * (endy - starty - 1));
3523                                 }
3524                                 else
3525                                 {
3526                                         for (uint32 y = starty; y <= endy; y++)
3527                                         {
3528                                                 memset (GFX.Screen + y * GFX.Pitch, back,
3529                                                                 GFX.Pitch);
3530                                         }
3531                                 }
3532 #else
3533                                 // there is no clipping to worry about so just fill with the back colour
3534                                 for (uint32 y = starty; y <= endy; y++)
3535                                 {
3536                                         memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), back,
3537                                                 IPPU.RenderedScreenWidth>>1);
3538                                 }
3539 #endif
3540                     }
3541                         
3542                         // If Forced blanking is not in effect
3543                     if (!PPU.ForcedBlanking)
3544                     {
3545 #ifdef RC_OPTIMIZED
3546                                 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3547                                 {
3548                                         memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3549                                                         GFX.ZPitch * (endy - starty - 1));
3550                                 }
3551                                 else
3552                                 {
3553                                         for (uint32 y = starty; y <= endy; y++)
3554                                         {
3555                                                 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3556                                                                 GFX.ZPitch);
3557                                         }
3558                                 }
3559 #else
3560                                 // Clear the Zbuffer for each of the lines which are going to be updated
3561                                 for (uint32 y = starty; y <= endy; y++)
3562                                 {
3563                                         memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3564                                                 GFX.ZPitch>>2);
3565                                 }
3566 #endif
3567                                 GFX.DB = GFX.ZBuffer;  // save pointer to Zbuffer in GFX object
3568                                 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3569                     }
3570                 }
3571     }
3572     else // Transparencys are disabled, ahh lovely ... nice and easy.
3573         {
3574             // get back colour to be used in clearing the screen
3575                 register uint32 back;
3576                 if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3577                                 (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3578                 {
3579                         back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3580                                    (IPPU.XB[PPU.FixedColourGreen] << 6) |
3581                                    (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3582                         back = (back << 16) | back;
3583                 }
3584                 else
3585                 {
3586                         back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3587                 }
3588
3589                 // if Forcedblanking in use then back colour becomes black
3590                 if (PPU.ForcedBlanking)
3591                         back = black;
3592                 else
3593                 {
3594                         SelectTileRenderer (TRUE);  //selects the tile renderers to be used
3595                                                                                 // TRUE means to use the default
3596                                                                                 // FALSE means use best renderer based on current
3597                                                                                 // graphics register settings
3598                 }
3599
3600                 // now clear all graphics lines which are being updated using the back colour
3601                 for (register uint32 y = starty; y <= endy; y++)
3602                 {
3603                         memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch), back,
3604                                 IPPU.RenderedScreenWidth>>1);
3605                 }
3606
3607                 if (!PPU.ForcedBlanking)
3608                 {
3609                         // Loop through all lines being updated and clear the
3610                         // zbuffer for each of the lines
3611                         for (uint32 y = starty; y <= endy; y++)
3612                     {
3613                                 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3614                                         IPPU.RenderedScreenWidth>>2);
3615                     }
3616                     GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3617                     GFX.pCurrentClip = &IPPU.Clip [0];
3618
3619 // Define an inline function to handle clipping
3620 #define FIXCLIP(n) \
3621 if (GFX.r212c & (1 << (n))) \
3622         GFX.pCurrentClip = &IPPU.Clip [0]; \
3623 else \
3624         GFX.pCurrentClip = &IPPU.Clip [1]
3625
3626 // Define an inline function to handle which BGs are being displayed
3627 #define DISPLAY(n) \
3628         ( \
3629                 (!(PPU.BG_Forced & n) && (GFX.r212c & n)) || \
3630                 (((GFX.r212d & n) && subadd)) \
3631         )
3632
3633                     uint8 subadd = GFX.r2131 & 0x3f;
3634
3635                         // go through all BGS are check if they need to be displayed
3636                     bool BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3637                     bool BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3638                     bool BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3639                     bool BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3640                     bool OB  = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3641
3642                     if (PPU.BGMode <= 1)
3643                     {
3644                                 // screen modes 0 and 1
3645                                 if (OB)
3646                                 {
3647                                     FIXCLIP(4);
3648                                     DrawOBJS ();
3649                                 }
3650                                 if (BG0)
3651                                 {
3652                                     FIXCLIP(0);
3653                                     DrawBackground (PPU.BGMode, 0, 10, 14);
3654                                 }
3655                                 if (BG1)
3656                                 {
3657                                     FIXCLIP(1);
3658                                     DrawBackground (PPU.BGMode, 1, 9, 13);
3659                                 }
3660                                 if (BG2)
3661                                 {
3662                                     FIXCLIP(2);
3663                                     DrawBackground (PPU.BGMode, 2, 3,
3664                                                     (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3665                                 }
3666                                 if (BG3 && PPU.BGMode == 0)
3667                                 {
3668                                     FIXCLIP(3);
3669                                     DrawBackground (PPU.BGMode, 3, 2, 5);
3670                                 }
3671                     }
3672                     else if (PPU.BGMode != 7)
3673                     {
3674                                 // screen modes 2 and up but not mode 7
3675                                 if (OB)
3676                                 {
3677                                     FIXCLIP(4);
3678                                     DrawOBJS ();
3679                                 }
3680                                 if (BG0)
3681                                 {
3682                                     FIXCLIP(0);
3683                                     DrawBackground (PPU.BGMode, 0, 5, 13);
3684                                 }
3685                                 if (BG1 && PPU.BGMode != 6)
3686                                 {
3687                                     FIXCLIP(1);
3688                                     DrawBackground (PPU.BGMode, 1, 2, 9);
3689                                 }
3690                     }
3691                     else 
3692                     {
3693                                 // screen mode 7
3694                                 if (OB)
3695                                 {
3696                                     FIXCLIP(4);
3697                                     DrawOBJS ();
3698                                 }
3699                                 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3700                                 {
3701                                     int bg;
3702                                     FIXCLIP(0);
3703                                     if (Memory.FillRAM [0x2133] & 0x40)
3704                                     {
3705                                         GFX.Mode7Mask = 0x7f;
3706                                         GFX.Mode7PriorityMask = 0x80;
3707                                         Mode7Depths [0] = 5;
3708                                         Mode7Depths [1] = 9;
3709                                         bg = 1;
3710                                     }
3711                                     else
3712                                     {
3713                                         GFX.Mode7Mask = 0xff;
3714                                         GFX.Mode7PriorityMask = 0;
3715                                         Mode7Depths [0] = 5;
3716                                         Mode7Depths [1] = 5;
3717                                         bg = 0;
3718                                     }
3719
3720                                         if (!Settings.Mode7Interpolate)
3721                                         {       
3722                                             DrawBGMode7Background16 (GFX.Screen, bg);
3723                                         }
3724                                         else
3725                                         {       
3726                                             DrawBGMode7Background16_i (GFX.Screen, bg);
3727                                         }
3728                                 }
3729                     }
3730                 }
3731         }
3732 #ifndef RC_OPTIMIZE // no hi res
3733     if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3734     {
3735         if (IPPU.DoubleWidthPixels)
3736         {
3737             // Mixure of background modes used on screen - scale width
3738             // of all non-mode 5 and 6 pixels.
3739                 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3740                 {
3741                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3742                     register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3743                     for (register int x = 255; x >= 0; x--, p--, q -= 2)
3744                         *q = *(q + 1) = *p;
3745                 }
3746         }
3747
3748         if (IPPU.LatchedInterlace)
3749         {
3750             // Interlace is enabled - double the height of all non-mode 5 and 6
3751             // pixels.
3752             for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3753             {
3754                 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch),
3755                          (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch),
3756                          GFX.Pitch>>2);
3757             }
3758         }
3759     }
3760 #endif
3761     IPPU.PreviousLine = IPPU.CurrentLine;
3762 }
3763
3764 #ifdef GFX_MULTI_FORMAT
3765
3766 #define _BUILD_PIXEL(F) \
3767 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
3768 { \
3769     return (BUILD_PIXEL_##F(R,G,B)); \
3770 }\
3771 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
3772 { \
3773     return (BUILD_PIXEL2_##F(R,G,B)); \
3774 } \
3775 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
3776 { \
3777     DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
3778 }
3779
3780 _BUILD_PIXEL(RGB565)
3781 _BUILD_PIXEL(RGB555)
3782 _BUILD_PIXEL(BGR565)
3783 _BUILD_PIXEL(BGR555)
3784 _BUILD_PIXEL(GBR565)
3785 _BUILD_PIXEL(GBR555)
3786 _BUILD_PIXEL(RGB5551)
3787
3788 bool8 S9xSetRenderPixelFormat (int format)
3789 {
3790     extern uint32 current_graphic_format;
3791
3792     current_graphic_format = format;
3793
3794     switch (format)
3795     {
3796     case RGB565:
3797         _BUILD_SETUP(RGB565)
3798         return (TRUE);
3799     case RGB555:
3800         _BUILD_SETUP(RGB555)
3801         return (TRUE);
3802     case BGR565:
3803         _BUILD_SETUP(BGR565)
3804         return (TRUE);
3805     case BGR555:
3806         _BUILD_SETUP(BGR555)
3807         return (TRUE);
3808     case GBR565:
3809         _BUILD_SETUP(GBR565)
3810         return (TRUE);
3811     case GBR555:
3812         _BUILD_SETUP(GBR555)
3813         return (TRUE);
3814     case RGB5551:
3815         _BUILD_SETUP(RGB5551)
3816         return (TRUE);
3817     default:
3818         break;
3819     }
3820     return (FALSE);
3821 }
3822
3823 #endif
3824