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