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