new build system; package can be built in i386
[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                 if (s) // XXX: Workaround for underflow (Secret of MANA)
1506                         s -= (Offset>>1);
1507                 Tile = READ_2BYTES (t);
1508                 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1509
1510                 if (BG.TileSize == 8)
1511                 {
1512                     if (!(Tile & H_FLIP))
1513                     {
1514                         // Normal, unflipped
1515                         (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1516                                                     s, Offset, Count, VirtAlign, Lines);
1517                     }
1518                     else
1519                     {
1520                         // H flip
1521                         (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1522                                                     s, Offset, Count, VirtAlign, Lines);
1523                     }
1524                 }
1525                 else
1526                 {
1527                     if (!(Tile & (V_FLIP | H_FLIP)))
1528                     {
1529                         // Normal, unflipped
1530                         (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1531                                                     s, Offset, Count, VirtAlign, Lines);
1532                     }
1533                     else
1534                     if (Tile & H_FLIP)
1535                     {
1536                         if (Tile & V_FLIP)
1537                         {
1538                             // H & V flip
1539                             (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1540                                                         s, Offset, Count, VirtAlign, Lines);
1541                         }
1542                         else
1543                         {
1544                             // H flip only
1545                             (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1546                                                         s, Offset, Count, VirtAlign, Lines);
1547                         }
1548                     }
1549                     else
1550                     {
1551                         // V flip only
1552                         (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1553                                                     s, Offset, Count, VirtAlign, Lines);
1554                     }
1555                 }
1556
1557                 t += Quot & 1;
1558                 if (Quot == 63)
1559                     t = b2;
1560                 else if (Quot == 127)
1561                     t = b1;
1562                 Quot++;
1563                 s += 4;
1564             }
1565
1566             // Middle, unclipped tiles
1567             Count = Width - Count;
1568             int Middle = Count >> 3;
1569             Count &= 7;
1570             for (int C = Middle; C > 0; s += 4, Quot++, C--)
1571             {
1572                 Tile = READ_2BYTES(t);
1573                 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1574                 if (BG.TileSize == 8)
1575                 {
1576                     if (!(Tile & H_FLIP))
1577                     {
1578                         // Normal, unflipped
1579                         (*DrawHiResTilePtr) (Tile + (Quot & 1),
1580                                              s, VirtAlign, Lines);
1581                     }
1582                     else
1583                     {
1584                         // H flip
1585                         (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
1586                                             s, VirtAlign, Lines);
1587                     }
1588                 }
1589                 else
1590                 {
1591                     if (!(Tile & (V_FLIP | H_FLIP)))
1592                     {
1593                         // Normal, unflipped
1594                         (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
1595                                              s, VirtAlign, Lines);
1596                     }
1597                     else
1598                     if (Tile & H_FLIP)
1599                     {
1600                         if (Tile & V_FLIP)
1601                         {
1602                             // H & V flip
1603                             (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
1604                                                  s, VirtAlign, Lines);
1605                         }
1606                         else
1607                         {
1608                             // H flip only
1609                             (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
1610                                                  s, VirtAlign, Lines);
1611                         }
1612                     }
1613                     else
1614                     {
1615                         // V flip only
1616                         (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
1617                                              s, VirtAlign, Lines);
1618                     }
1619                 }
1620
1621                 t += Quot & 1;
1622                 if (Quot == 63)
1623                     t = b2;
1624                 else
1625                 if (Quot == 127)
1626                     t = b1;
1627             }
1628
1629             // Right-hand edge clipped tiles
1630             if (Count)
1631             {
1632                 Tile = READ_2BYTES(t);
1633                 GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1634                 if (BG.TileSize == 8)
1635                 {
1636                     if (!(Tile & H_FLIP))
1637                     {
1638                         // Normal, unflipped
1639                         (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
1640                                                     s, 0, Count, VirtAlign, Lines);
1641                     }
1642                     else
1643                     {
1644                         // H flip
1645                         (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
1646                                                     s, 0, Count, VirtAlign, Lines);
1647                     }
1648                 }
1649                 else
1650                 {
1651                     if (!(Tile & (V_FLIP | H_FLIP)))
1652                     {
1653                         // Normal, unflipped
1654                         (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
1655                                                     s, 0, Count, VirtAlign, Lines);
1656                     }
1657                     else
1658                     if (Tile & H_FLIP)
1659                     {
1660                         if (Tile & V_FLIP)
1661                         {
1662                             // H & V flip
1663                             (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1664                                                         s, 0, Count, VirtAlign, Lines);
1665                         }
1666                         else
1667                         {
1668                             // H flip only
1669                             (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1670                                                         s, 0, Count, VirtAlign, Lines);
1671                         }
1672                     }
1673                     else
1674                     {
1675                         // V flip only
1676                         (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
1677                                                     s, 0, Count, VirtAlign, Lines);
1678                     }
1679                 }
1680             }
1681         }
1682     }
1683 }
1684
1685 void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
1686 {
1687     GFX.PixSize = 1;
1688
1689     BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
1690     BG.BitShift = BitShifts[BGMode][bg];
1691     BG.TileShift = TileShifts[BGMode][bg];
1692     BG.TileAddress = PPU.BG[bg].NameBase << 1;
1693     BG.NameSelect = 0;
1694         BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
1695         BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
1696     BG.PaletteShift = PaletteShifts[BGMode][bg];
1697     BG.PaletteMask = PaletteMasks[BGMode][bg];
1698     BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
1699                           (GFX.r2130 & 1);
1700
1701     if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
1702     {
1703         DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
1704         return;
1705
1706     }
1707     switch (BGMode)
1708     {
1709     case 2:
1710         if (Settings.WrestlemaniaArcade)
1711             break;
1712     case 4: // Used by Puzzle Bobble
1713         DrawBackgroundOffset (BGMode, bg, Z1, Z2);
1714         return;
1715
1716     case 5:
1717     case 6: // XXX: is also offset per tile.
1718             DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
1719             return;
1720         }
1721
1722
1723
1724                   
1725
1726     CHECK_SOUND();
1727
1728     uint32 Tile;
1729     uint16 *SC0;
1730     uint16 *SC1;
1731     uint16 *SC2;
1732     uint16 *SC3;
1733     uint32 Width;
1734     uint8 depths [2] = {Z1, Z2};
1735     
1736     if (BGMode == 0)
1737         BG.StartPalette = bg << 5;
1738     else
1739         BG.StartPalette = 0;
1740
1741     SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
1742
1743     if (PPU.BG[bg].SCSize & 1)
1744         SC1 = SC0 + 1024;
1745     else
1746         SC1 = SC0;
1747
1748     if (PPU.BG[bg].SCSize & 2)
1749         SC2 = SC1 + 1024;
1750     else
1751         SC2 = SC0;
1752
1753     if (PPU.BG[bg].SCSize & 1)
1754         SC3 = SC2 + 1024;
1755     else
1756         SC3 = SC2;
1757     
1758     int Lines;
1759     int OffsetMask;
1760     int OffsetShift;
1761
1762     if (BG.TileSize == 16)
1763     {
1764         OffsetMask = 0x3ff;
1765         OffsetShift = 4;
1766     }
1767     else
1768     {
1769         OffsetMask = 0x1ff;
1770         OffsetShift = 3;
1771     }
1772
1773     for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
1774     {
1775                 uint32 VOffset = LineData [Y].BG[bg].VOffset;
1776                 uint32 HOffset = LineData [Y].BG[bg].HOffset;
1777                 int VirtAlign = (Y + VOffset) & 7;
1778                 
1779                 for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
1780                     if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
1781                         (HOffset != LineData [Y + Lines].BG[bg].HOffset))
1782                         break;
1783
1784                 if (Y + Lines > GFX.EndY)
1785                     Lines = GFX.EndY + 1 - Y;
1786
1787                 VirtAlign <<= 3;
1788                 
1789                 uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
1790                 uint32 t1;
1791                 uint32 t2;
1792                 if (((VOffset + Y) & 15) > 7)
1793                 {
1794                     t1 = 16;
1795                     t2 = 0;
1796                 }
1797                 else
1798                 {
1799                     t1 = 0;
1800                     t2 = 16;
1801                 }
1802                 uint16 *b1;
1803                 uint16 *b2;
1804
1805                 if (ScreenLine & 0x20)
1806                     b1 = SC2, b2 = SC3;
1807                 else
1808                     b1 = SC0, b2 = SC1;
1809
1810                 b1 += (ScreenLine & 0x1f) << 5;
1811                 b2 += (ScreenLine & 0x1f) << 5;
1812
1813                 int clipcount = GFX.pCurrentClip->Count [bg];
1814                 if (!clipcount)
1815                     clipcount = 1;
1816                 for (int clip = 0; clip < clipcount; clip++)
1817                 {
1818                     uint32 Left;
1819                     uint32 Right;
1820
1821                     if (!GFX.pCurrentClip->Count [bg])
1822                     {
1823                         Left = 0;
1824                         Right = 256;
1825                     }
1826                     else
1827                     {
1828                         Left = GFX.pCurrentClip->Left [clip][bg];
1829                         Right = GFX.pCurrentClip->Right [clip][bg];
1830
1831                         if (Right <= Left)
1832                             continue;
1833                     }
1834
1835                     uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
1836                     uint32 HPos = (HOffset + Left) & OffsetMask;
1837
1838                     uint32 Quot = HPos >> 3;
1839                     uint32 Count = 0;
1840                     
1841                     uint16 *t;
1842                     if (BG.TileSize == 8)
1843                     {
1844                         if (Quot > 31)
1845                             t = b2 + (Quot & 0x1f);
1846                         else
1847                             t = b1 + Quot;
1848                     }
1849                     else
1850                     {
1851                         if (Quot > 63)
1852                             t = b2 + ((Quot >> 1) & 0x1f);
1853                         else
1854                             t = b1 + (Quot >> 1);
1855                     }
1856
1857                     Width = Right - Left;
1858                     // Left hand edge clipped tile
1859                     if (HPos & 7)
1860                     {
1861                         uint32 Offset = (HPos & 7);
1862                         Count = 8 - Offset;
1863                         if (Count > Width)
1864                             Count = Width;
1865                         s -= Offset * GFX.PixSize;
1866                         Tile = READ_2BYTES(t);
1867                         GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1868
1869                         if (BG.TileSize == 8)
1870                         {
1871                             (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
1872                                                    Lines);
1873                         }
1874                         else
1875                         {
1876                             if (!(Tile & (V_FLIP | H_FLIP)))
1877                             {
1878                                         // Normal, unflipped
1879                                         (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
1880                                                        s, Offset, Count, VirtAlign, Lines);
1881                             }
1882                             else
1883                             if (Tile & H_FLIP)
1884                             {
1885                                 if (Tile & V_FLIP)
1886                                 {
1887                                     // H & V flip
1888                                     (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
1889                                                            s, Offset, Count, VirtAlign, Lines);
1890                                 }
1891                                 else
1892                                 {
1893                                     // H flip only
1894                                     (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
1895                                                            s, Offset, Count, VirtAlign, Lines);
1896                                 }
1897                             }
1898                             else
1899                             {
1900                                 // V flip only
1901                                 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s, 
1902                                                        Offset, Count, VirtAlign, Lines);
1903                             }
1904                         }
1905
1906                         if (BG.TileSize == 8)
1907                         {
1908                             t++;
1909                             if (Quot == 31)
1910                                 t = b2;
1911                             else if (Quot == 63)
1912                                 t = b1;
1913                         }
1914                         else
1915                         {
1916                             t += Quot & 1;
1917                             if (Quot == 63)
1918                                 t = b2;
1919                             else if (Quot == 127)
1920                                 t = b1;
1921                         }
1922                         Quot++;
1923                         s += 8 * GFX.PixSize;
1924                     }
1925
1926                     // Middle, unclipped tiles
1927                     Count = Width - Count;
1928                     int Middle = Count >> 3;
1929                     Count &= 7;
1930                     for (int C = Middle; C > 0; s += 8 * GFX.PixSize, Quot++, C--)
1931                     {
1932                         Tile = READ_2BYTES(t);
1933                         GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1934
1935                         if (BG.TileSize != 8)
1936                         {
1937                             if (Tile & H_FLIP)
1938                             {
1939                                 // Horizontal flip, but what about vertical flip ?
1940                                 if (Tile & V_FLIP)
1941                                 {
1942                                     // Both horzontal & vertical flip
1943                                     (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s, 
1944                                                     VirtAlign, Lines);
1945                                 }
1946                                 else
1947                                 {
1948                                     // Horizontal flip only
1949                                     (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s, 
1950                                                     VirtAlign, Lines);
1951                                 }
1952                             }
1953                             else
1954                             {
1955                                 // No horizontal flip, but is there a vertical flip ?
1956                                 if (Tile & V_FLIP)
1957                                 {
1958                                     // Vertical flip only
1959                                     (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
1960                                                     VirtAlign, Lines);
1961                                 }
1962                                 else
1963                                 {
1964                                     // Normal unflipped
1965                                     (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
1966                                                     VirtAlign, Lines);
1967                                 }
1968                             }
1969                         }
1970                         else
1971                         {
1972                             (*DrawTilePtr) (Tile, s, VirtAlign, Lines);
1973                         }
1974
1975                         if (BG.TileSize == 8)
1976                         {
1977                             t++;
1978                             if (Quot == 31)
1979                                 t = b2;
1980                             else
1981                             if (Quot == 63)
1982                                 t = b1;
1983                         }
1984                         else
1985                         {
1986                             t += Quot & 1;
1987                             if (Quot == 63)
1988                                 t = b2;
1989                             else
1990                             if (Quot == 127)
1991                                 t = b1;
1992                         }
1993                     }
1994                     // Right-hand edge clipped tiles
1995                     if (Count)
1996                     {
1997                         Tile = READ_2BYTES(t);
1998                         GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
1999
2000                         if (BG.TileSize == 8)
2001                             (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign, 
2002                                                    Lines);
2003                         else
2004                         {
2005                             if (!(Tile & (V_FLIP | H_FLIP)))
2006                             {
2007                                 // Normal, unflipped
2008                                 (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0, 
2009                                                        Count, VirtAlign, Lines);
2010                             }
2011                             else
2012                             if (Tile & H_FLIP)
2013                             {
2014                                 if (Tile & V_FLIP)
2015                                 {
2016                                     // H & V flip
2017                                     (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
2018                                                            s, 0, Count, VirtAlign, 
2019                                                            Lines);
2020                                 }
2021                                 else
2022                                 {
2023                                     // H flip only
2024                                     (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
2025                                                            s, 0, Count, VirtAlign,
2026                                                            Lines);
2027                                 }
2028                             }
2029                             else
2030                             {
2031                                 // V flip only
2032                                 (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
2033                                                        s, 0, Count, VirtAlign, 
2034                                                        Lines);
2035                             }
2036                         }
2037                     }
2038                 }
2039     }
2040 }
2041
2042 #define RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2043         const uint8 bmask = MASK; \
2044         for (int x = startx; x != endx; \
2045                 x += (HFLIP ? -1 : 1), AA += aa, CC += cc, p++, d++) \
2046         { \
2047                 int X = ((AA + BB) >> 8) & 0x3ff; \
2048                 int Y = ((CC + DD) >> 8) & 0x3ff; \
2049                 uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2050                 uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2051                 uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2052                 if (z > *d && b) \
2053                 { \
2054                         *p = (FUNC); \
2055                         *d = z; \
2056                 } \
2057         }
2058
2059 #define RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,CFILT) \
2060         register int AABB = AA + BB; \
2061         register int CCDD = CC + DD; \
2062         const uint8 bmask = MASK; \
2063         for (int x = startx; x != endx; \
2064                 x += (HFLIP ? -1 : 1), AABB += aa, CCDD += cc, p++, d++) \
2065         { \
2066                 register uint16 X = ((AABB) >> 8) CFILT; \
2067                 register uint16 Y = ((CCDD) >> 8) CFILT; \
2068         \
2069                 if (((X | Y) & ~0x3ff) == 0) { \
2070                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2071                         uint8 b = TileData[((Y & 7) << 4) + ((X & 7) << 1)]; \
2072                         uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2073                         if (z > *d && b) { \
2074                                 *p = (FUNC); \
2075                                 *d = z; \
2076                         } \
2077                 } else if (REPEAT == 3) { \
2078                         X = (x + HOffset) & 7; \
2079                         Y = (yy + CentreY) & 7; \
2080                         uint8 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2081                         uint8 z = Mode7Depths [(b & PRIOMASK) >> 7]; \
2082                         if (z > *d && b) { \
2083                                 *p = (FUNC); \
2084                                 *d = z; \
2085                         } \
2086                 } \
2087         } \
2088
2089 #define RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,MASK,PRIOMASK) \
2090         for (uint32 clip = 0; clip < ClipCount; clip++) \
2091         { \
2092             if (GFX.pCurrentClip->Count [bg]) \
2093             { \
2094                         Left = GFX.pCurrentClip->Left [clip][bg]; \
2095                         Right = GFX.pCurrentClip->Right [clip][bg]; \
2096                         if (Right <= Left) \
2097                                 continue; \
2098             } \
2099             register TYPE *p = (TYPE *) Screen + Left; \
2100             register uint8 *d = Depth + Left; \
2101 \
2102             if (HFLIP) \
2103             { \
2104                         startx = Right - 1; \
2105                         endx = Left - 1; \
2106                         aa = -l->MatrixA; \
2107                         cc = -l->MatrixC; \
2108             } \
2109             else \
2110             { \
2111                         startx = Left; \
2112                         endx = Right; \
2113                         aa = l->MatrixA; \
2114                         cc = l->MatrixC; \
2115             } \
2116             int xx; \
2117             if (!REPEAT) \
2118                         xx = startx + (HOffset - CentreX) % 1023; \
2119             else \
2120                         xx = startx + HOffset - CentreX; \
2121             int AA = l->MatrixA * xx; \
2122             int CC = l->MatrixC * xx; \
2123 \
2124             if (!REPEAT) \
2125             { \
2126                         RENDER_BACKGROUND_MODE7_PIXEL_NOREPEAT(FUNC,HFLIP,REPEAT,MASK,PRIOMASK) \
2127             } else if (DEZAEMON) { \
2128                         RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,& 0x7ff) \
2129                 } else { \
2130                         RENDER_BACKGROUND_MODE7_PIXEL(FUNC,HFLIP,REPEAT,MASK,PRIOMASK,) \
2131             } \
2132         } \
2133
2134 #ifdef USE_CRAZY_OPTS
2135
2136 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON) \
2137         if (GFX.Mode7PriorityMask) { \
2138                 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0x7f,0x80) \
2139         } else { \
2140                 RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,HFLIP,REPEAT,DEZAEMON,0xff,0x00) \
2141         }
2142
2143 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,HFLIP) \
2144         if (Settings.Dezaemon && PPU.Mode7Repeat) { \
2145                 switch (PPU.Mode7Repeat) { \
2146                         case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,1); break; \
2147                         case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,1); break; \
2148                         case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,1); break; \
2149                 } \
2150         } else { \
2151                 switch (PPU.Mode7Repeat) { \
2152                         case 0: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,0,0); break; \
2153                         case 1: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,1,0); break; \
2154                         case 2: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,2,0); break; \
2155                         case 3: RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_MASK(TYPE,FUNC,HFLIP,3,0); break; \
2156                 } \
2157         }
2158
2159 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC) \
2160         if (PPU.Mode7HFlip) { \
2161                 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,1); \
2162         } else { \
2163                 RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_REPEAT_DEZAEMON(TYPE,FUNC,0); \
2164         }
2165
2166 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2167         RENDER_BACKGROUND_MODE7_CLIP_CHOOSE_HFLIP(TYPE,FUNC)
2168
2169 #else
2170
2171 #define RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2172         RENDER_BACKGROUND_MODE7_CLIP(TYPE,FUNC,PPU.Mode7HFlip,PPU.Mode7Repeat,Settings.Dezaemon,GFX.Mode7Mask,GFX.Mode7PriorityMask)
2173
2174 #endif
2175
2176 #define RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2177         for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2178     { \
2179         int yy; \
2180 \
2181         int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
2182         int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
2183 \
2184         int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
2185         int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
2186 \
2187         if (PPU.Mode7VFlip) \
2188             yy = 261 - (int) Line; \
2189         else \
2190             yy = Line; \
2191 \
2192         if (PPU.Mode7Repeat == 0) \
2193             yy += (VOffset - CentreY) % 1023; \
2194         else \
2195             yy += VOffset - CentreY; \
2196         int BB = l->MatrixB * yy + (CentreX << 8); \
2197         int DD = l->MatrixD * yy + (CentreY << 8); \
2198 \
2199         RENDER_BACKGROUND_MODE7_CLIP_CHOOSE(TYPE,FUNC) \
2200     }
2201
2202 #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
2203     CHECK_SOUND(); \
2204 \
2205     uint8 * const VRAM1 = Memory.VRAM + 1; \
2206     if (GFX.r2130 & 1) \
2207     { \
2208                 if (IPPU.DirectColourMapsNeedRebuild) \
2209                         S9xBuildDirectColourMaps (); \
2210                 GFX.ScreenColors = DirectColourMaps [0]; \
2211     } \
2212     else \
2213                 GFX.ScreenColors = IPPU.ScreenColors; \
2214 \
2215     int aa, cc; \
2216     int startx, endx; \
2217     uint32 Left = 0; \
2218     uint32 Right = 256; \
2219     uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2220 \
2221     if (!ClipCount) \
2222         ClipCount = 1; \
2223 \
2224     Screen += GFX.StartY * GFX.Pitch; \
2225     uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2226     struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2227     RENDER_BACKGROUND_MODE7_LINE(TYPE,FUNC) \
2228 \
2229
2230
2231 void DrawBGMode7Background (uint8 *Screen, int bg)
2232 {
2233     RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & bmask))
2234 }
2235
2236 void DrawBGMode7Background16 (uint8 *Screen, int bg)
2237 {
2238     RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & bmask]);
2239 }
2240
2241 void DrawBGMode7Background16Add (uint8 *Screen, int bg)
2242 {
2243     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2244                                         (*(d + GFX.DepthDelta) != 1 ?
2245                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2246                                                        p [GFX.Delta]) :
2247                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2248                                                        GFX.FixedColour)) :
2249                                          GFX.ScreenColors [b & bmask]);
2250 }
2251
2252 void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
2253 {
2254     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2255                                         (*(d + GFX.DepthDelta) != 1 ?
2256                                             COLOR_ADD1_2 (GFX.ScreenColors [b & bmask],
2257                                                        p [GFX.Delta]) :
2258                                             COLOR_ADD (GFX.ScreenColors [b & bmask],
2259                                                        GFX.FixedColour)) :
2260                                          GFX.ScreenColors [b & bmask]);
2261 }
2262
2263 void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
2264 {
2265     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2266                                         (*(d + GFX.DepthDelta) != 1 ?
2267                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2268                                                        p [GFX.Delta]) :
2269                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2270                                                        GFX.FixedColour)) :
2271                                          GFX.ScreenColors [b & bmask]);
2272 }
2273
2274 void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
2275 {
2276     RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
2277                                         (*(d + GFX.DepthDelta) != 1 ?
2278                                             COLOR_SUB1_2 (GFX.ScreenColors [b & bmask],
2279                                                        p [GFX.Delta]) :
2280                                             COLOR_SUB (GFX.ScreenColors [b & bmask],
2281                                                        GFX.FixedColour)) :
2282                                          GFX.ScreenColors [b & bmask]);
2283 }
2284
2285 #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
2286     CHECK_SOUND(); \
2287 \
2288     uint8 *VRAM1 = Memory.VRAM + 1; \
2289     if (GFX.r2130 & 1) \
2290     { \
2291         if (IPPU.DirectColourMapsNeedRebuild) \
2292             S9xBuildDirectColourMaps (); \
2293         GFX.ScreenColors = DirectColourMaps [0]; \
2294     } \
2295     else \
2296         GFX.ScreenColors = IPPU.ScreenColors; \
2297     \
2298     int aa, cc; \
2299     int dir; \
2300     int startx, endx; \
2301     uint32 Left = 0; \
2302     uint32 Right = 256; \
2303     uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
2304     \
2305     if (!ClipCount) \
2306         ClipCount = 1; \
2307     \
2308     Screen += GFX.StartY * GFX.Pitch; \
2309     uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
2310     struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
2311     bool8_32 allowSimpleCase = FALSE; \
2312     if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
2313         && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
2314         && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
2315         ) \
2316         allowSimpleCase = TRUE;  \
2317     \
2318     for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
2319     { \
2320         int yy; \
2321         \
2322         int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
2323         int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
2324         \
2325         int CentreX = ((int) l->CentreX << M7) >> M7; \
2326         int CentreY = ((int) l->CentreY << M7) >> M7; \
2327         \
2328         if (PPU.Mode7VFlip) \
2329             yy = 261 - (int) Line; \
2330         else \
2331             yy = Line; \
2332         \
2333         if (PPU.Mode7Repeat == 0) \
2334             yy += (VOffset - CentreY) % 1023; \
2335         else \
2336             yy += VOffset - CentreY; \
2337         bool8_32 simpleCase = FALSE; \
2338         int BB; \
2339         int DD; \
2340         /* Make a special case for the identity matrix, since it's a common case and */ \
2341         /* can be done much more quickly without special effects */ \
2342         if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
2343         { \
2344             BB = CentreX << 8; \
2345             DD = (yy + CentreY) << 8; \
2346             simpleCase = TRUE; \
2347         } \
2348         else \
2349         { \
2350             BB = l->MatrixB * yy + (CentreX << 8); \
2351             DD = l->MatrixD * yy + (CentreY << 8); \
2352         } \
2353         \
2354         for (uint32 clip = 0; clip < ClipCount; clip++) \
2355         { \
2356             if (GFX.pCurrentClip->Count [bg]) \
2357             { \
2358                 Left = GFX.pCurrentClip->Left [clip][bg]; \
2359                 Right = GFX.pCurrentClip->Right [clip][bg]; \
2360                 if (Right <= Left) \
2361                     continue; \
2362             } \
2363             TYPE *p = (TYPE *) Screen + Left; \
2364             uint8 *d = Depth + Left; \
2365             \
2366             if (PPU.Mode7HFlip) \
2367             { \
2368                 startx = Right - 1; \
2369                 endx = Left - 1; \
2370                 dir = -1; \
2371                 aa = -l->MatrixA; \
2372                 cc = -l->MatrixC; \
2373             } \
2374             else \
2375             { \
2376                 startx = Left; \
2377                 endx = Right; \
2378                 dir = 1; \
2379                 aa = l->MatrixA; \
2380                 cc = l->MatrixC; \
2381             } \
2382             int xx; \
2383             if (PPU.Mode7Repeat == 0) \
2384                 xx = startx + (HOffset - CentreX) % 1023; \
2385             else \
2386                 xx = startx + HOffset - CentreX; \
2387             int AA, CC = 0; \
2388             if (simpleCase) \
2389             { \
2390                 AA = xx << 8; \
2391             } \
2392             else \
2393             { \
2394                 AA = l->MatrixA * xx; \
2395                 CC = l->MatrixC * xx; \
2396             } \
2397             if (simpleCase) \
2398             { \
2399                 if (!PPU.Mode7Repeat) \
2400                 { \
2401                     int x = startx; \
2402                     do \
2403                     { \
2404                         int X = ((AA + BB) >> 8) & 0x3ff; \
2405                         int Y = (DD >> 8) & 0x3ff; \
2406                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2407                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2408                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2409                         if (GFX.Z1 > *d && b) \
2410                         { \
2411                             TYPE theColor = COLORFUNC; \
2412                             *p = (FUNC) | ALPHA_BITS_MASK; \
2413                             *d = GFX.Z1; \
2414                         } \
2415                         AA += aa, p++, d++; \
2416                         x += dir; \
2417                     } while (x != endx); \
2418                 } \
2419                 else \
2420                 { \
2421                     int x = startx; \
2422                     do { \
2423                         int X = (AA + BB) >> 8; \
2424                         int Y = DD >> 8; \
2425 \
2426                         if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2427                         { \
2428                             X &= 0x7ff; \
2429                             Y &= 0x7ff; \
2430                         } \
2431 \
2432                         if (((X | Y) & ~0x3ff) == 0) \
2433                         { \
2434                             uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2435                             uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2436                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2437                             if (GFX.Z1 > *d && b) \
2438                             { \
2439                                 TYPE theColor = COLORFUNC; \
2440                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2441                                 *d = GFX.Z1; \
2442                             } \
2443                         } \
2444                         else if (PPU.Mode7Repeat == 3) \
2445                         { \
2446                             X = (x + HOffset) & 7; \
2447                             Y = (yy + CentreY) & 7; \
2448                             uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2449                             uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2450                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2451                             if (GFX.Z1 > *d && b) \
2452                             { \
2453                                 TYPE theColor = COLORFUNC; \
2454                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2455                                 *d = GFX.Z1; \
2456                             } \
2457                         } \
2458                         AA += aa; p++; d++; \
2459                         x += dir; \
2460                     } while (x != endx); \
2461                 } \
2462             } \
2463             else if (!PPU.Mode7Repeat) \
2464             { \
2465                 /* The bilinear interpolator: get the colors at the four points surrounding */ \
2466                 /* the location of one point in the _sampled_ image, and weight them according */ \
2467                 /* to their (city block) distance.  It's very smooth, but blurry with "close up" */ \
2468                 /* points. */ \
2469                 \
2470                 /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
2471                 /* guess for where bilinear filtering will become a poor method for averaging. */ \
2472                 /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
2473                 /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
2474                 /* You can think of this as a kind of mipmapping. */ \
2475                 if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
2476                 {\
2477                     for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2478                     { \
2479                         uint32 xPos = AA + BB; \
2480                         uint32 xPix = xPos >> 8; \
2481                         uint32 yPos = CC + DD; \
2482                         uint32 yPix = yPos >> 8; \
2483                         uint32 X = xPix & 0x3ff; \
2484                         uint32 Y = yPix & 0x3ff; \
2485                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2486                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2487                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2488                         if (GFX.Z1 > *d && b) \
2489                         { \
2490                             /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2491                             uint32 X10 = (xPix + dir) & 0x3ff; \
2492                             uint32 Y01 = (yPix + dir) & 0x3ff; \
2493                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2494                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2495                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2496                             uint32 p1 = COLORFUNC; \
2497                             p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2498                             b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2499                             uint32 p2 = COLORFUNC; \
2500                             p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2501                             b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2502                             uint32 p4 = COLORFUNC; \
2503                             p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2504                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2505                             uint32 p3 = COLORFUNC; \
2506                             p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2507                             /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2508                             uint32 Xdel = (xPos >> 3) & 0x1F; \
2509                             uint32 Ydel = (yPos >> 3) & 0x1F; \
2510                             uint32 XY = (Xdel*Ydel) >> 5; \
2511                             uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2512                             uint32 area2 = Xdel - XY; \
2513                             uint32 area3 = Ydel - XY; \
2514                             uint32 area4 = XY; \
2515                             uint32 tempColor = ((area1 * p1) + \
2516                                                 (area2 * p2) + \
2517                                                 (area3 * p3) + \
2518                                                 (area4 * p4)) >> 5; \
2519                             TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2520                             *p = (FUNC) | ALPHA_BITS_MASK; \
2521                             *d = GFX.Z1; \
2522                         } \
2523                     } \
2524                 } \
2525                 else \
2526                     /* The oversampling method: get the colors at four corners of a square */ \
2527                     /* in the _displayed_ image, and average them.  It's sharp and clean, but */ \
2528                     /* gives the usual huge pixels when the source image gets "close." */ \
2529                 { \
2530                     /* Find the dimensions of the square in the source image whose corners will be examined. */ \
2531                     uint32 aaDelX = aa >> 1; \
2532                     uint32 ccDelX = cc >> 1; \
2533                     uint32 bbDelY = l->MatrixB >> 1; \
2534                     uint32 ddDelY = l->MatrixD >> 1; \
2535                     /* Offset the location within the source image so that the four sampled points */ \
2536                     /* center around where the single point would otherwise have been drawn. */ \
2537                     BB -= (bbDelY >> 1); \
2538                     DD -= (ddDelY >> 1); \
2539                     AA -= (aaDelX >> 1); \
2540                     CC -= (ccDelX >> 1); \
2541                     uint32 BB10 = BB + aaDelX; \
2542                     uint32 BB01 = BB + bbDelY; \
2543                     uint32 BB11 = BB + aaDelX + bbDelY; \
2544                     uint32 DD10 = DD + ccDelX; \
2545                     uint32 DD01 = DD + ddDelY; \
2546                     uint32 DD11 = DD + ccDelX + ddDelY; \
2547                     for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2548                     { \
2549                         uint32 X = ((AA + BB) >> 8) & 0x3ff; \
2550                         uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
2551                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2552                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2553                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2554                         if (GFX.Z1 > *d && b) \
2555                         { \
2556                             /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
2557                             /* source image that we're going to examine. */ \
2558                             uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
2559                             uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
2560                             uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
2561                             uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
2562                             uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
2563                             uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
2564                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2565                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
2566                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
2567                             TYPE p1 = COLORFUNC; \
2568                             b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
2569                             TYPE p2 = COLORFUNC; \
2570                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
2571                             TYPE p3 = COLORFUNC; \
2572                             b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
2573                             TYPE p4 = COLORFUNC; \
2574                             TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
2575                             *p = (FUNC) | ALPHA_BITS_MASK; \
2576                             *d = GFX.Z1; \
2577                         } \
2578                     } \
2579                 } \
2580             } \
2581             else \
2582             { \
2583                 for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
2584                 { \
2585                     uint32 xPos = AA + BB; \
2586                     uint32 xPix = xPos >> 8; \
2587                     uint32 yPos = CC + DD; \
2588                     uint32 yPix = yPos >> 8; \
2589                     uint32 X = xPix; \
2590                     uint32 Y = yPix; \
2591                     \
2592 \
2593                     if(Settings.Dezaemon && PPU.Mode7Repeat == 2) \
2594                     { \
2595                         X &= 0x7ff; \
2596                         Y &= 0x7ff; \
2597                     } \
2598 \
2599                     if (((X | Y) & ~0x3ff) == 0) \
2600                     { \
2601                         uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2602                         uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
2603                         GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2604                         if (GFX.Z1 > *d && b) \
2605                         { \
2606                             /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
2607                             uint32 X10 = (xPix + dir) & 0x3ff; \
2608                             uint32 Y01 = (yPix + dir) & 0x3ff; \
2609                             uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2610                             uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
2611                             uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
2612                             uint32 p1 = COLORFUNC; \
2613                             p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
2614                             b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
2615                             uint32 p2 = COLORFUNC; \
2616                             p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
2617                             b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
2618                             uint32 p4 = COLORFUNC; \
2619                             p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
2620                             b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
2621                             uint32 p3 = COLORFUNC; \
2622                             p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
2623                             /* Xdel, Ydel: position (in 1/32nds) between the points */ \
2624                             uint32 Xdel = (xPos >> 3) & 0x1F; \
2625                             uint32 Ydel = (yPos >> 3) & 0x1F; \
2626                             uint32 XY = (Xdel*Ydel) >> 5; \
2627                             uint32 area1 = 0x20 + XY - Xdel - Ydel; \
2628                             uint32 area2 = Xdel - XY; \
2629                             uint32 area3 = Ydel - XY; \
2630                             uint32 area4 = XY; \
2631                             uint32 tempColor = ((area1 * p1) + \
2632                                                 (area2 * p2) + \
2633                                                 (area3 * p3) + \
2634                                                 (area4 * p4)) >> 5; \
2635                             TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
2636                             *p = (FUNC) | ALPHA_BITS_MASK; \
2637                             *d = GFX.Z1; \
2638                         } \
2639                     } \
2640                     else \
2641                     { \
2642                         if (PPU.Mode7Repeat == 3) \
2643                         { \
2644                             X = (x + HOffset) & 7; \
2645                             Y = (yy + CentreY) & 7; \
2646                             uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
2647                             GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
2648                             if (GFX.Z1 > *d && b) \
2649                             { \
2650                                 TYPE theColor = COLORFUNC; \
2651                                 *p = (FUNC) | ALPHA_BITS_MASK; \
2652                                 *d = GFX.Z1; \
2653                             } \
2654                         } \
2655                     } \
2656                 } \
2657             } \
2658         } \
2659     }
2660
2661 STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2662 {
2663     register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2664                             ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2665                             ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
2666                             ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
2667     register uint32 y = (A & TWO_LOW_BITS_MASK) +
2668                             (B & TWO_LOW_BITS_MASK) +
2669                             (C & TWO_LOW_BITS_MASK) +
2670                             (D & TWO_LOW_BITS_MASK);
2671     y = (y>>2) & TWO_LOW_BITS_MASK;
2672     return x+y;
2673 }
2674
2675 void DrawBGMode7Background16_i (uint8 *Screen, int bg)
2676 {
2677     RENDER_BACKGROUND_MODE7_i (uint16, theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2678 }
2679
2680 void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
2681 {
2682     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2683                                         (*(d + GFX.DepthDelta) != 1 ?
2684                                             (COLOR_ADD (theColor,
2685                                                        p [GFX.Delta])) :
2686                                             (COLOR_ADD (theColor,
2687                                                        GFX.FixedColour))) :
2688                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2689 }
2690
2691 void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
2692 {
2693     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2694                                         (*(d + GFX.DepthDelta) != 1 ?
2695                                             COLOR_ADD1_2 (theColor,
2696                                                           p [GFX.Delta]) :
2697                                             COLOR_ADD (theColor,
2698                                                        GFX.FixedColour)) :
2699                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2700 }
2701
2702 void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
2703 {
2704     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2705                                         (*(d + GFX.DepthDelta) != 1 ?
2706                                             COLOR_SUB (theColor,
2707                                                        p [GFX.Delta]) :
2708                                             COLOR_SUB (theColor,
2709                                                        GFX.FixedColour)) :
2710                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2711 }
2712
2713 void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
2714 {
2715     RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
2716                                         (*(d + GFX.DepthDelta) != 1 ?
2717                                             COLOR_SUB1_2 (theColor,
2718                                                        p [GFX.Delta]) :
2719                                             COLOR_SUB (theColor,
2720                                                        GFX.FixedColour)) :
2721                                          theColor, (GFX.ScreenColors[b & GFX.Mode7Mask]));
2722 }
2723
2724 #define _BUILD_SETUP(F) \
2725 GFX.BuildPixel = BuildPixel##F; \
2726 GFX.BuildPixel2 = BuildPixel2##F; \
2727 GFX.DecomposePixel = DecomposePixel##F; \
2728 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
2729 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
2730 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
2731 RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
2732 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
2733 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
2734 MAX_RED = MAX_RED_##F; \
2735 MAX_GREEN = MAX_GREEN_##F; \
2736 MAX_BLUE = MAX_BLUE_##F; \
2737 GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
2738 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
2739 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
2740                      GREEN_LOW_BIT_MASK_##F | \
2741                      BLUE_LOW_BIT_MASK_##F); \
2742 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
2743                     GREEN_HI_BIT_MASK_##F | \
2744                     BLUE_HI_BIT_MASK_##F); \
2745 RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
2746                        GREEN_HI_BIT_MASK_##F | \
2747                        BLUE_HI_BIT_MASK_##F) << 1); \
2748 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
2749 FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
2750 SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
2751 THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
2752 ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
2753 FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
2754 TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
2755 HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
2756                                 ~TWO_LOW_BITS_MASK ) >> 2);
2757
2758 void RenderScreen (uint8 *Screen, bool8_32 sub, bool8_32 force_no_add, uint8 D)
2759 {
2760     bool8_32 BG0;
2761     bool8_32 BG1;
2762     bool8_32 BG2;
2763     bool8_32 BG3;
2764     bool8_32 OB;
2765
2766     GFX.S = Screen;
2767
2768     if (!sub)
2769     {
2770         GFX.pCurrentClip = &IPPU.Clip [0];
2771         BG0 = ON_MAIN (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2772         BG1 = ON_MAIN (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2773         BG2 = ON_MAIN (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2774         BG3 = ON_MAIN (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2775         OB  = ON_MAIN (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2776     }
2777     else
2778     {
2779         GFX.pCurrentClip = &IPPU.Clip [1];
2780         BG0 = ON_SUB (0) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
2781         BG1 = ON_SUB (1) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
2782         BG2 = ON_SUB (2) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
2783         BG3 = ON_SUB (3) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
2784         OB  = ON_SUB (4) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
2785     }
2786
2787     sub |= force_no_add;
2788
2789     if (PPU.BGMode <= 1)
2790     {
2791         if (OB)
2792         {
2793             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2794             DrawOBJS (!sub, D);
2795         }
2796         if (BG0)
2797         {
2798             SelectTileRenderer (sub || !SUB_OR_ADD(0));
2799             DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
2800         }
2801         if (BG1)
2802         {
2803             SelectTileRenderer (sub || !SUB_OR_ADD(1));
2804             DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
2805         }
2806         if (BG2)
2807         {
2808             SelectTileRenderer (sub || !SUB_OR_ADD(2));
2809             DrawBackground (PPU.BGMode, 2, D + 3, 
2810                             (Memory.FillRAM [0x2105] & 8) == 0 ? D + 6 : D + 17);
2811         }
2812         if (BG3 && PPU.BGMode == 0)
2813         {
2814             SelectTileRenderer (sub || !SUB_OR_ADD(3));
2815             DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
2816         }
2817     }
2818     else if (PPU.BGMode != 7)
2819     {
2820         if (OB)
2821         {
2822             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2823             DrawOBJS (!sub, D);
2824         }
2825         if (BG0)
2826         {
2827             SelectTileRenderer (sub || !SUB_OR_ADD(0));
2828             DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
2829         }
2830         if (PPU.BGMode != 6 && BG1)
2831         {
2832             SelectTileRenderer (sub || !SUB_OR_ADD(1));
2833             DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
2834         }
2835     }
2836     else
2837     {
2838         if (OB)
2839         {
2840             SelectTileRenderer (sub || !SUB_OR_ADD(4));
2841             DrawOBJS (!sub, D);
2842         }
2843         if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
2844         {
2845             int bg;
2846
2847             if (Memory.FillRAM [0x2133] & 0x40)
2848             {
2849                 GFX.Mode7Mask = 0x7f;
2850                 GFX.Mode7PriorityMask = 0x80;
2851                 Mode7Depths [0] = 5 + D;
2852                 Mode7Depths [1] = 9 + D;
2853                 bg = 1;
2854             }
2855             else
2856             {
2857                 GFX.Mode7Mask = 0xff;
2858                 GFX.Mode7PriorityMask = 0;
2859                 Mode7Depths [0] = 5 + D;
2860                 Mode7Depths [1] = 5 + D;
2861                 bg = 0;
2862             }
2863             if (sub || !SUB_OR_ADD(0))
2864             {
2865                 if (!Settings.Mode7Interpolate)
2866                     DrawBGMode7Background16 (Screen, bg);
2867                 else
2868                     DrawBGMode7Background16_i (Screen, bg);
2869             }
2870             else
2871             {
2872                 if (GFX.r2131 & 0x80)
2873                 {
2874                     if (GFX.r2131 & 0x40)
2875                     {
2876                         if (!Settings.Mode7Interpolate)
2877                             DrawBGMode7Background16Sub1_2 (Screen, bg);
2878                         else
2879                             DrawBGMode7Background16Sub1_2_i (Screen, bg);
2880                     }
2881                     else
2882                     {
2883                         if (!Settings.Mode7Interpolate)
2884                             DrawBGMode7Background16Sub (Screen, bg);
2885                         else
2886                             DrawBGMode7Background16Sub_i (Screen, bg);
2887                     }
2888                 }
2889                 else
2890                 {
2891                     if (GFX.r2131 & 0x40)
2892                     {
2893                         if (!Settings.Mode7Interpolate)
2894                             DrawBGMode7Background16Add1_2 (Screen, bg);
2895                         else
2896                             DrawBGMode7Background16Add1_2_i (Screen, bg);
2897                     }
2898                     else
2899                     {
2900                         if (!Settings.Mode7Interpolate)
2901                             DrawBGMode7Background16Add (Screen, bg);
2902                         else
2903                             DrawBGMode7Background16Add_i (Screen, bg);
2904                     }
2905                 }
2906             }
2907         }
2908     }
2909 }
2910
2911 #include "font.h"
2912
2913 void DisplayChar (uint8 *Screen, uint8 c)
2914 {
2915     int line = (((c & 0x7f) - 32) >> 4) * font_height;
2916     int offset = (((c & 0x7f) - 32) & 15) * font_width;
2917 #ifndef _SNESPPC
2918     if (Settings.SixteenBit)
2919 #endif
2920     {
2921         int h, w;
2922         uint16 *s = (uint16 *) Screen;
2923         for (h = 0; h < font_height; h++, line++,
2924              s += GFX.PPL - font_width)
2925         {
2926             for (w = 0; w < font_width; w++, s++)
2927             {
2928                 uint8 p = font [line][offset + w];
2929
2930                 if (p == '#')
2931                     *s = 0xffff;
2932                 else
2933                 if (p == '.')
2934                     *s = BLACK;
2935             }
2936         }
2937     }
2938 #ifndef _SNESPPC
2939     else
2940     {
2941         int h, w;
2942         uint8 *s = Screen;
2943         for (h = 0; h < font_height; h++, line++,
2944              s += GFX.PPL - font_width)
2945         {
2946             for (w = 0; w < font_width; w++, s++)
2947             {
2948                 uint8 p = font [line][offset + w];
2949
2950                 if (p == '#')
2951                     *s = 255;
2952                 else
2953                 if (p == '.')
2954                     *s = BLACK;
2955             }
2956         }
2957     }
2958 #endif
2959 }
2960
2961 static void S9xDisplayFrameRate ()
2962 {
2963     uint8 *Screen = GFX.Screen + 2 +
2964                     (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch2;
2965     char string [10];
2966     int len = 5;
2967
2968     sprintf (string, "%02d/%02d", IPPU.DisplayedRenderedFrameCount,
2969              (int) Memory.ROMFramesPerSecond);
2970
2971     int i;
2972 #ifdef _SNESPPC
2973     Screen += (font_width - 1) * sizeof(uint16);
2974 #endif
2975     for (i = 0; i < len; i++)
2976     {
2977         DisplayChar (Screen, string [i]);
2978         Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) : 
2979                   (font_width - 1);
2980     }
2981 }
2982
2983 static void S9xDisplayString (const char *string)
2984 {
2985     uint8 *Screen = GFX.Screen + 2 +
2986                     (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch2;
2987     int len = strlen (string);
2988     int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
2989     int char_count = 0;
2990     int i;
2991
2992     for (i = 0; i < len; i++, char_count++)
2993     {
2994         if (char_count >= max_chars || string [i] < 32)
2995         {
2996             Screen -= Settings.SixteenBit ? 
2997                         (font_width - 1) * sizeof (uint16) * max_chars :
2998                         (font_width - 1) * max_chars;
2999             Screen += font_height * GFX.Pitch;
3000             if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
3001                 break;
3002             char_count -= max_chars;
3003         }
3004         if (string [i] < 32)
3005             continue;
3006         DisplayChar (Screen, string [i]);
3007         Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) : 
3008                   (font_width - 1);
3009     }
3010 }
3011
3012 void S9xUpdateScreen () // ~30-50ms! (called from FLUSH_REDRAW())
3013 {
3014     int32 x2 = 1;
3015
3016     GFX.S = GFX.Screen;
3017
3018         unsigned char *memoryfillram = Memory.FillRAM;
3019
3020         // get local copies of vid registers to be used later
3021     GFX.r2131 = memoryfillram [0x2131]; // ADDITION/SUBTRACTION & SUBTRACTION DESIGNATION FOR EACH SCREEN 
3022     GFX.r212c = memoryfillram [0x212c]; // MAIN SCREEN, DESIGNATION - used to enable BGS
3023     GFX.r212d = memoryfillram [0x212d]; // SUB SCREEN DESIGNATION - used to enable sub BGS
3024     GFX.r2130 = memoryfillram [0x2130]; // INITIAL SETTINGS FOR FIXED COLOR ADDITION OR SCREEN ADDITION
3025         
3026         // If external sync is off and
3027         // main screens have not been configured the same as the sub screen and
3028         // color addition and subtraction has been diabled then
3029         // Pseudo is 1
3030         // anything else it is 0
3031         GFX.Pseudo = (memoryfillram [0x2133] & 8) != 0 && // Use EXTERNAL SYNCHRONIZATION?
3032                  (GFX.r212c & 15) != (GFX.r212d & 15) && // Are the main screens different from the sub screens?
3033                  (GFX.r2131 & 0x3f) == 0; // Is colour data addition/subtraction disabled on all BGS?
3034
3035         // If sprite data has been changed then go through and 
3036         // refresh the sprites.
3037     if (IPPU.OBJChanged)
3038         {       
3039                 S9xSetupOBJ ();
3040         }
3041
3042     if (PPU.RecomputeClipWindows)
3043     {
3044                 ComputeClipWindows ();
3045                 PPU.RecomputeClipWindows = FALSE;
3046     }
3047
3048     GFX.StartY = IPPU.PreviousLine;
3049     if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
3050                 GFX.EndY = PPU.ScreenHeight - 1;
3051
3052     uint32 starty = GFX.StartY;
3053     uint32 endy = GFX.EndY;
3054
3055 #ifndef RC_OPTIMIZED
3056     if (Settings.SupportHiRes &&
3057         (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.LatchedInterlace))
3058     {
3059                 if (PPU.BGMode == 5 || PPU.BGMode == 6)
3060                 {
3061                     IPPU.RenderedScreenWidth = 512;
3062                     x2 = 2;
3063                 }
3064                 if (IPPU.LatchedInterlace)
3065                 {
3066                     starty = GFX.StartY * 2;
3067                     endy = GFX.EndY * 2 + 1;
3068                 }
3069                 if (!IPPU.DoubleWidthPixels)
3070                 {
3071                     // The game has switched from lo-res to hi-res mode part way down
3072                     // the screen. Scale any existing lo-res pixels on screen
3073 #ifndef _SNESPPC
3074                         if (Settings.SixteenBit)
3075 #endif
3076                     {
3077 #if defined (USE_GLIDE) || defined (USE_OPENGL)
3078                     if (
3079 #ifdef USE_GLIDE
3080                         (Settings.GlideEnable && GFX.Pitch == 512) ||
3081 #endif
3082 #ifdef USE_OPENGL
3083                         (Settings.OpenGLEnable && GFX.Pitch == 512) ||
3084 #endif
3085                             0)
3086                                 {
3087                                     // Have to back out of the speed up hack where the low res.
3088                                     // SNES image was rendered into a 256x239 sized buffer,
3089                                     // ignoring the true, larger size of the buffer.
3090                                     
3091                                     for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
3092                                     {
3093                                                 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3094                                                 register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.RealPitch) + 510;
3095                                                 for (register int x = 255; x >= 0; x--, p--, q -= 2)
3096                                                         *q = *(q + 1) = *p;
3097                                     }
3098                                 }
3099                                 else
3100 #endif
3101                                         for (register uint32 y = 0; y < GFX.StartY; y++)
3102                                         {
3103                                             register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3104                                             register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3105                                             for (register int x = 255; x >= 0; x--, p--, q -= 2)
3106                                                 *q = *(q + 1) = *p;
3107                                         }
3108                     }
3109 #ifndef _SNESPPC
3110                     else
3111                     {
3112                                 for (register uint32 y = 0; y < GFX.StartY; y++)
3113                                 {
3114                                         register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3115                                         register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3116                                         for (register int x = 255; x >= 0; x--, p--, q -= 2)
3117                                         *q = *(q + 1) = *p;
3118                                 }
3119                     }
3120 #endif
3121                     IPPU.DoubleWidthPixels = TRUE;
3122                 }
3123     }
3124 #endif //RC_OPTIMIZED (DONT DO ABOVE)
3125
3126     uint32 black = BLACK | (BLACK << 16);
3127
3128         // Are we worrying about transparencies?
3129     if (Settings.Transparency && Settings.SixteenBit)
3130     {
3131                 if (GFX.Pseudo)
3132                 {
3133                         GFX.r2131 = 0x5f;  //0101 1111 - enable addition/subtraction on all BGS and sprites and "1/2 OF COLOR DATA" DESIGNATION
3134                         GFX.r212d = (Memory.FillRAM [0x212c] ^ // any BGS which are set as main and as sub then switch off the sub
3135                                  Memory.FillRAM [0x212d]) & 15;
3136                         GFX.r212c &= ~GFX.r212d;  // make sure the main BG reg is the reverse of the sub BG reg
3137                         GFX.r2130 |= 2; // enable ADDITION/SUBTRACTION FOR SUB SCREEN
3138                 }
3139
3140                 // Check to see if any transparency effects are currently in use
3141                 if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
3142                         (GFX.r2130 & 0x30) != 0x30 &&
3143                         !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
3144                 {
3145                         // transparency effects in use, so lets get busy!
3146                         struct ClipData *pClip;
3147                         uint32 fixedColour;
3148                         GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
3149                                                    IPPU.XB [PPU.FixedColourGreen],
3150                                                    IPPU.XB [PPU.FixedColourBlue]);
3151                         fixedColour = (GFX.FixedColour<<16|GFX.FixedColour);
3152                         // Clear the z-buffer, marking areas 'covered' by the fixed
3153                         // colour as depth 1.
3154                         pClip = &IPPU.Clip [1];
3155
3156                         // Clear the z-buffer
3157                         
3158                     if (pClip->Count [5])
3159                     {
3160
3161                                 // Colour window enabled.
3162
3163 #ifdef RC_OPTIMIZED
3164                                 for (uint32 y = starty; y <= endy; y++)
3165                                 {
3166
3167                         ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch,
3168                                                 IPPU.RenderedScreenWidth);
3169                                         ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3170                                                 IPPU.RenderedScreenWidth);
3171
3172                         if (IPPU.Clip [0].Count [5])
3173                                         {
3174                                                 memset ((GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth);
3175                                         }
3176                                         for (uint32 c = 0; c < pClip->Count [5]; c++)
3177                                         {
3178                                                 if (pClip->Right [c][5] > pClip->Left [c][5])
3179                                                 {
3180                                                         memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3181                                                                 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3182                                                         if (IPPU.Clip [0].Count [5])
3183                                                         {
3184                                                         // Blast, have to clear the sub-screen to the fixed-colour
3185                                                         // because there is a colour window in effect clipping
3186                                                         // the main screen that will allow the sub-screen
3187                                                         // 'underneath' to show through.
3188                                                         memset ((GFX.SubScreen + y * GFX.Pitch2) + pClip->Left [c][5] * x2,
3189                                                                          GFX.FixedColour,
3190                                                                          pClip->Right[c][5]*x2 - pClip->Left [c][5] * x2);
3191                                                         }
3192                                                 }
3193                                         }
3194                                 }
3195
3196 #else // NOT RC_OPTIMIZED
3197                                 // loop around all of the lines being updated
3198                                 for (uint32 y = starty; y <= endy; y++)
3199                                 {
3200                                         // Clear the subZbuffer
3201                                         memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch),0,
3202                                                 IPPU.RenderedScreenWidth>>2);
3203                                         // Clear the Zbuffer
3204                                         memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3205                                                 IPPU.RenderedScreenWidth>>2);
3206
3207                                         // if there is clipping then clear subscreen to a black color
3208                                         if (IPPU.Clip [0].Count [5])
3209                                         {
3210                                                 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), black, IPPU.RenderedScreenWidth>>1);
3211                                         }
3212
3213                                         // loop through all window clippings
3214                                         for (uint32 c = 0; c < pClip->Count [5]; c++)
3215                                         {
3216                                                 if (pClip->Right [c][5] > pClip->Left [c][5])
3217                                                 {
3218                                                         memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
3219                                                                 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
3220                                                         if (IPPU.Clip [0].Count [5])
3221                                                         {
3222                                                         // Blast, have to clear the sub-screen to the fixed-colour
3223                                                         // because there is a colour window in effect clipping
3224                                                         // the main screen that will allow the sub-screen
3225                                                         // 'underneath' to show through.
3226
3227                                                         register uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch2);
3228                                                         register uint16 *q = p + pClip->Right [c][5] * x2;
3229                                                         p += pClip->Left [c][5] * x2;
3230
3231                                                         while (p < q)
3232                                                                 *p++ = (uint16) GFX.FixedColour;
3233                                                         }
3234                                                 }
3235                                         }
3236                                 }
3237 #endif
3238 //#undef RC_OPTIMIZED
3239
3240                     }
3241                     else
3242                     {
3243                                 // No windows are clipping the main screen
3244                                 // this simplifies the screen clearing process
3245 #ifdef RC_OPTIMIZED
3246
3247                         if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3248                         {
3249
3250                                 memset (GFX.ZBuffer + starty * GFX.ZPitch, 0, GFX.ZPitch * (endy - starty - 1));
3251                                 memset (GFX.SubZBuffer + starty * GFX.ZPitch, 1, GFX.ZPitch * (endy - starty - 1));
3252                         }
3253                         else
3254                         {
3255                                 for (uint32 y = starty; y <= endy; y++)
3256                                 {
3257                                         ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
3258                                                 IPPU.RenderedScreenWidth);
3259                                         memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
3260                                                 IPPU.RenderedScreenWidth);
3261                                 }
3262                         }
3263                         
3264                     if (IPPU.Clip [0].Count [5])
3265                     {
3266                                 // Blast, have to clear the sub-screen to the fixed-colour
3267                                 // because there is a colour window in effect clipping
3268                                 // the main screen that will allow the sub-screen
3269                                 // 'underneath' to show through.
3270                                 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3271                                 {
3272                                         memset ((GFX.SubScreen + starty * GFX.Pitch2), 
3273                                                         GFX.FixedColour | (GFX.FixedColour << 16),
3274                                                         GFX.Pitch2 * (endy - starty - 1));
3275                                 }
3276                                 else
3277                                 {
3278                                         for (uint32 y = starty; y <= endy; y++)
3279                                         {
3280                                                 memset ((GFX.SubScreen + y * GFX.Pitch2), 
3281                                                                 GFX.FixedColour | (GFX.FixedColour << 16),
3282                                                                 IPPU.RenderedScreenWidth);
3283                                         }
3284                                 }
3285                         }
3286
3287 #else // NOT RC_OPTIMIZED
3288                         // loop through all of the lines to be updated
3289                         for (uint32 y = starty; y <= endy; y++)
3290                         {
3291                                 // Clear the Zbuffer
3292                                 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch),0,
3293                                         IPPU.RenderedScreenWidth>>2);
3294                             // clear the sub Zbuffer to 1
3295                                 memset32 ((uint32_t*)(GFX.SubZBuffer + y * GFX.ZPitch), 0x01010101,
3296                                     IPPU.RenderedScreenWidth>>2);
3297                             if (IPPU.Clip [0].Count [5])
3298                             {
3299                                 // Blast, have to clear the sub-screen to the fixed-colour
3300                                 // because there is a colour window in effect clipping
3301                                 // the main screen that will allow the sub-screen
3302                                 // 'underneath' to show through.
3303
3304
3305                                 memset32 ((uint32_t*)(GFX.SubScreen + y * GFX.Pitch2), fixedColour,
3306                                     IPPU.RenderedScreenWidth>>1);
3307                             }
3308                         }
3309 #endif
3310
3311                         }
3312
3313                     if (ANYTHING_ON_SUB)
3314                     {
3315                                 GFX.DB = GFX.SubZBuffer;
3316                                 RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
3317                     }
3318
3319                     if (IPPU.Clip [0].Count [5])
3320                     {
3321                                         for (uint32 y = starty; y <= endy; y++)
3322                         {
3323                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3324                                         register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch ;
3325                                         register uint8 *e = d + SNES_WIDTH;
3326
3327                                         while (d < e)
3328                                 {
3329                                                 if (*d > 1)
3330                                                         *p = *(p + GFX.Delta);
3331                                 else
3332                                                         *p = BLACK;
3333                                                 d++;
3334                                                 p++;
3335                             }
3336                         }
3337                     }
3338
3339                     GFX.DB = GFX.ZBuffer;
3340                     RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
3341                     if (SUB_OR_ADD(5))
3342                     {
3343                         uint32 back = IPPU.ScreenColors [0];
3344                         uint32 Left = 0;
3345                         uint32 Right = 256;
3346                         uint32 Count;
3347
3348                         pClip = &IPPU.Clip [0];
3349
3350                         for (uint32 y = starty; y <= endy; y++)
3351                         {
3352                             if (!(Count = pClip->Count [5]))
3353                             {
3354                                 Left = 0;
3355                                 Right = 256 * x2;
3356                                 Count = 1;
3357                             }
3358
3359                             for (uint32 b = 0; b < Count; b++)
3360                             {
3361                                 if (pClip->Count [5])
3362                                 {
3363                                     Left = pClip->Left [b][5] * x2;
3364                                     Right = pClip->Right [b][5] * x2;
3365                                     if (Right <= Left)
3366                                         continue;
3367                                 }
3368
3369                                 if (GFX.r2131 & 0x80)
3370                                 {
3371                                     if (GFX.r2131 & 0x40)
3372                                     {
3373                                         // Subtract, halving the result.
3374                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3375                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3376                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3377                                         register uint8 *e = d + Right;
3378                                         uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3379
3380                                         d += Left;
3381                                         while (d < e)
3382                                         {
3383                                             if (*d == 0)
3384                                             {
3385                                                 if (*s)
3386                                                 {
3387                                                     if (*s != 1)
3388                                                         *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
3389                                                     else
3390                                                         *p = back_fixed;
3391                                                 }
3392                                                 else
3393                                                     *p = (uint16) back;
3394                                             }
3395                                             d++;
3396                                             p++;
3397                                             s++;
3398                                         }
3399                                     }
3400                                     else
3401                                     {
3402                                         // Subtract
3403                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3404                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3405                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3406                                         register uint8 *e = d + Right;
3407                                         uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
3408
3409                                         d += Left;
3410                                         while (d < e)
3411                                         {
3412                                             if (*d == 0)
3413                                             {
3414                                                 if (*s)
3415                                                 {
3416                                                     if (*s != 1)
3417                                                         *p = COLOR_SUB (back, *(p + GFX.Delta));
3418                                                     else
3419                                                         *p = back_fixed;
3420                                                 }
3421                                                 else
3422                                                     *p = (uint16) back;
3423                                             }
3424                                             d++;
3425                                             p++;
3426                                             s++;
3427                                         }
3428                                     }
3429                                 }
3430                                 else
3431                                 if (GFX.r2131 & 0x40)
3432                                 {
3433                                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3434                                     register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3435                                     register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3436                                     register uint8 *e = d + Right;
3437                                     uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3438                                     d += Left;
3439                                     while (d < e)
3440                                     {
3441                                         if (*d == 0)
3442                                         {
3443                                             if (*s)
3444                                             {
3445                                                 if (*s != 1)
3446                                                     *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
3447                                                 else
3448                                                     *p = back_fixed;
3449                                             }
3450                                             else
3451                                                 *p = (uint16) back;
3452                                         }
3453                                         d++;
3454                                         p++;
3455                                         s++;
3456                                     }
3457                                 }
3458                                 else
3459                                 if (back != 0)
3460                                 {
3461                                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3462                                     register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3463                                     register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3464                                     register uint8 *e = d + Right;
3465                                     uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
3466                                     d += Left;
3467                                     while (d < e)
3468                                     {
3469                                         if (*d == 0)
3470                                         {
3471                                             if (*s)
3472                                             {
3473                                                 if (*s != 1)
3474                                                     *p = COLOR_ADD (back, *(p + GFX.Delta));
3475                                                 else    
3476                                                     *p = back_fixed;
3477                                             }
3478                                             else
3479                                                 *p = (uint16) back;
3480                                         }
3481                                         d++;
3482                                         p++;
3483                                         s++;
3484                                     }
3485                                 }
3486                                 else
3487                                 {
3488                                     if (!pClip->Count [5])
3489                                     {
3490                                         // The backdrop has not been cleared yet - so
3491                                         // copy the sub-screen to the main screen
3492                                         // or fill it with the back-drop colour if the
3493                                         // sub-screen is clear.
3494                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3495                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3496                                         register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
3497                                         register uint8 *e = d + Right;
3498                                         d += Left;
3499                                         while (d < e)
3500                                         {
3501                                             if (*d == 0)
3502                                             {
3503                                                         if (*s)
3504                                                         {
3505                                                                 if (*s != 1)
3506                                                                         *p = *(p + GFX.Delta);
3507                                                                 else    
3508                                                                         *p = GFX.FixedColour;
3509                                                         }
3510                                                         else
3511                                                                 *p = (uint16) back;
3512                                             }
3513                                             d++;
3514                                             p++;
3515                                             s++;
3516                                         }
3517                                    }
3518                                 }
3519                             }
3520                         }
3521
3522                     }
3523                     else
3524                     {
3525                                 // Subscreen not being added to back
3526                                 uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3527                                 pClip = &IPPU.Clip [0];
3528
3529                                 if (pClip->Count [5])
3530                                 {
3531                                         for (uint32 y = starty; y <= endy; y++)
3532                                         {
3533                                                 for (uint32 b = 0; b < pClip->Count [5]; b++)
3534                                                 {
3535                                                         uint32 Left = pClip->Left [b][5] * x2;
3536                                                         uint32 Right = pClip->Right [b][5] * x2;
3537                                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
3538                                                         register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3539                                                         register uint8 *e = d + Right;
3540                                                         d += Left;
3541
3542                                                         while (d < e)
3543                                                         {
3544                                                                 if (*d++ == 0)
3545                                                                         *p = (int16) back;
3546                                                                 p++;
3547                                                         }
3548                                                 }
3549                                         }
3550                                 }
3551                                 else
3552                                 {
3553                                         for (uint32 y = starty; y <= endy; y++)
3554                                         {
3555                                                 register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
3556                                                 register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
3557                                                 register uint8 *e = d + 256 * x2;
3558
3559                                                 while (d < e)
3560                                                 {
3561                                                         if (*d == 0)
3562 #ifdef RC_OPTIMIZED
3563                                                                 *p++ = back;
3564                                                         d++;
3565 #else
3566                                                         *p = (int16) back;
3567                                                         d++;
3568                                                         p++;
3569 #endif
3570                                                 }
3571                                         }
3572                                 }
3573                     }
3574                 }       
3575                 else
3576                 {
3577                     // 16bit and transparency but currently no transparency effects in
3578                     // operation.
3579
3580                     // get the back colour of the current screen
3581                         uint32 back = IPPU.ScreenColors [0] | 
3582                                  (IPPU.ScreenColors [0] << 16);
3583
3584                     // if forceblanking in use then use black instead of the back color
3585                         if (PPU.ForcedBlanking)
3586                                 back = black;
3587                         
3588                         // not sure what Clip is used for yet
3589                         // could be a check to see if there is any clipping present?
3590                     if (IPPU.Clip [0].Count[5])
3591                     {
3592
3593 #ifdef RC_OPTIMIZED
3594                                 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3595                                 {
3596                                         memset (GFX.Screen + starty * GFX.Pitch2, black,
3597                                                         GFX.Pitch2 * (endy - starty - 1));
3598                                 }
3599                                 else
3600                                 {
3601                                         for (uint32 y = starty; y <= endy; y++)
3602                                         {
3603                                                 memset (GFX.Screen + y * GFX.Pitch2, black,
3604                                                                 GFX.Pitch2);
3605                                         }
3606                                 }
3607                                 for (uint32 y = starty; y <= endy; y++)
3608                                 {
3609                                         for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3610                                         {
3611                                                 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3612                                                 {
3613
3614                                                         memset ((GFX.Screen + y * GFX.Pitch2) + IPPU.Clip [0].Left [c][5] * x2,
3615                                                                         back,
3616                                                                         IPPU.Clip [0].Right [c][5] * x2 - IPPU.Clip [0].Left [c][5] * x2);
3617                                                 }
3618                                         }
3619                                 }
3620 #else
3621                                 // loop through all of the lines that are going to be updated as part of this screen update
3622                                 for (uint32 y = starty; y <= endy; y++)
3623                                 {
3624                                         memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), black,
3625                                                 IPPU.RenderedScreenWidth>>1);
3626
3627                                         if (black!=back)
3628                                         {
3629                                         for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
3630                                         {
3631                                                 if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
3632                                                 {
3633                                                         register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2); // get pointer to current line in screen buffer
3634                                                         register uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2; // get pointer to end of line
3635                                                         p += IPPU.Clip [0].Left [c][5] * x2;
3636
3637                                                         while (p < q)
3638                                                         *p++ = (uint16) back; // fill all pixels in clipped section with the back colour
3639                                                 }
3640                                         }
3641                                 }
3642                                 }
3643 #endif
3644                     }
3645                     else
3646                     {
3647 #ifdef RC_OPTIMIZED
3648                                 if (GFX.Pitch2 == (uint32)IPPU.RenderedScreenWidth)
3649                                 {
3650                                         memset (GFX.Screen + starty * GFX.Pitch2, back,
3651                                                         GFX.Pitch2 * (endy - starty - 1));
3652                                 }
3653                                 else
3654                                 {
3655                                         for (uint32 y = starty; y <= endy; y++)
3656                                         {
3657                                                 memset (GFX.Screen + y * GFX.Pitch2, back,
3658                                                                 GFX.Pitch2);
3659                                         }
3660                                 }
3661 #else
3662                                 // there is no clipping to worry about so just fill with the back colour
3663                                 for (uint32 y = starty; y <= endy; y++)
3664                                 {
3665                                         memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3666                                                 IPPU.RenderedScreenWidth>>1);
3667                                 }
3668 #endif
3669                     }
3670                         
3671                         // If Forced blanking is not in effect
3672                     if (!PPU.ForcedBlanking)
3673                     {
3674 #ifdef RC_OPTIMIZED
3675                                 if (GFX.ZPitch == (uint32)IPPU.RenderedScreenWidth)
3676                                 {
3677                                         memset (GFX.ZBuffer + starty * GFX.ZPitch, 0,
3678                                                         GFX.ZPitch * (endy - starty - 1));
3679                                 }
3680                                 else
3681                                 {
3682                                         for (uint32 y = starty; y <= endy; y++)
3683                                         {
3684                                                 memset (GFX.ZBuffer + y * GFX.ZPitch, 0,
3685                                                                 GFX.ZPitch);
3686                                         }
3687                                 }
3688 #else
3689                                 // Clear the Zbuffer for each of the lines which are going to be updated
3690                                 for (uint32 y = starty; y <= endy; y++)
3691                                 {
3692                                         memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3693                                                 GFX.ZPitch>>2);
3694                                 }
3695 #endif
3696                                 GFX.DB = GFX.ZBuffer;  // save pointer to Zbuffer in GFX object
3697                                 RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
3698                     }
3699                 }
3700     }
3701     else // Transparencys are disabled, ahh lovely ... nice and easy.
3702         {
3703 #ifndef _SNESPPC
3704                 if (Settings.SixteenBit)
3705 #endif
3706                 {
3707                     // get back colour to be used in clearing the screen
3708                         register uint32 back;
3709                         if (!(Memory.FillRAM [0x2131] & 0x80) &&(Memory.FillRAM[0x2131] & 0x20) &&
3710                                         (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
3711                         {
3712                                 back = (IPPU.XB[PPU.FixedColourRed]<<11) |
3713                                            (IPPU.XB[PPU.FixedColourGreen] << 6) | 
3714                                            (IPPU.XB[PPU.FixedColourBlue] << 1) | 1;
3715                                 back = (back << 16) | back;
3716                         }
3717                         else
3718                         {
3719                                 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
3720                         }
3721     
3722                     // if Forcedblanking in use then back colour becomes black
3723                         if (PPU.ForcedBlanking)
3724                                 back = black;
3725                     else
3726                         {
3727                                 SelectTileRenderer (TRUE);  //selects the tile renderers to be used
3728                                                                                         // TRUE means to use the default
3729                                                                                         // FALSE means use best renderer based on current
3730                                                                                         // graphics register settings
3731                         }
3732                     
3733                         // now clear all graphics lines which are being updated using the back colour
3734                         for (register uint32 y = starty; y <= endy; y++)
3735                     {
3736                                 memset32 ((uint32_t*)(GFX.Screen + y * GFX.Pitch2), back,
3737                                         IPPU.RenderedScreenWidth>>1);
3738                     }
3739                 }
3740 #ifndef _SNESPPC
3741                 else // Settings.SixteenBit == false
3742                 {
3743                     // because we are in 8 bit we can just use 0 to clear the screen
3744                         // this means we can use the Zero Memory function
3745                         
3746                         // Loop through all lines being updated and clear the pixels to 0
3747                         for (uint32 y = starty; y <= endy; y++)
3748                     {
3749                         ZeroMemory (GFX.Screen + y * GFX.Pitch2,
3750                                     IPPU.RenderedScreenWidth);
3751                     }
3752                 }
3753 #endif
3754                 if (!PPU.ForcedBlanking)
3755                 {
3756                         // Loop through all lines being updated and clear the
3757                         // zbuffer for each of the lines
3758                         for (uint32 y = starty; y <= endy; y++)
3759                     {
3760                                 memset32 ((uint32_t*)(GFX.ZBuffer + y * GFX.ZPitch), 0,
3761                                         IPPU.RenderedScreenWidth>>2);
3762                     }
3763                     GFX.DB = GFX.ZBuffer; // save pointer to Zbuffer in GFX object
3764                     GFX.pCurrentClip = &IPPU.Clip [0];
3765
3766 // Define an inline function to handle clipping
3767 #define FIXCLIP(n) \
3768 if (GFX.r212c & (1 << (n))) \
3769         GFX.pCurrentClip = &IPPU.Clip [0]; \
3770 else \
3771         GFX.pCurrentClip = &IPPU.Clip [1]
3772
3773 // Define an inline function to handle which BGs are being displayed
3774 #define DISPLAY(n) \
3775 (!(PPU.BG_Forced & n) && \
3776 (GFX.r212c & n) || \
3777 ((GFX.r212d & n) && subadd))
3778
3779                     uint8 subadd = GFX.r2131 & 0x3f;
3780
3781                         // go through all BGS are check if they need to be displayed
3782                     bool8_32 BG0 = DISPLAY(1) && !(Settings.os9x_hack & GFX_IGNORE_BG0);
3783                     bool8_32 BG1 = DISPLAY(2) && !(Settings.os9x_hack & GFX_IGNORE_BG1);
3784                     bool8_32 BG2 = DISPLAY(4) && !(Settings.os9x_hack & GFX_IGNORE_BG2);
3785                     bool8_32 BG3 = DISPLAY(8) && !(Settings.os9x_hack & GFX_IGNORE_BG3);
3786                     bool8_32 OB  = DISPLAY(16) && !(Settings.os9x_hack & GFX_IGNORE_OBJ);
3787
3788                     if (PPU.BGMode <= 1)
3789                     {
3790                                 // screen modes 0 and 1
3791                                 if (OB)
3792                                 {
3793                                     FIXCLIP(4);
3794                                     DrawOBJS ();
3795                                 }
3796                                 if (BG0)
3797                                 {
3798                                     FIXCLIP(0);
3799                                     DrawBackground (PPU.BGMode, 0, 10, 14);
3800                                 }
3801                                 if (BG1)
3802                                 {
3803                                     FIXCLIP(1);
3804                                     DrawBackground (PPU.BGMode, 1, 9, 13);
3805                                 }
3806                                 if (BG2)
3807                                 {
3808                                     FIXCLIP(2);
3809                                     DrawBackground (PPU.BGMode, 2, 3,
3810                                                     (Memory.FillRAM [0x2105] & 8) == 0 ? 6 : 17);
3811                                 }
3812                                 if (BG3 && PPU.BGMode == 0)
3813                                 {
3814                                     FIXCLIP(3);
3815                                     DrawBackground (PPU.BGMode, 3, 2, 5);
3816                                 }
3817                     }
3818                     else if (PPU.BGMode != 7)
3819                     {
3820                                 // screen modes 2 and up but not mode 7
3821                                 if (OB)
3822                                 {
3823                                     FIXCLIP(4);
3824                                     DrawOBJS ();
3825                                 }
3826                                 if (BG0)
3827                                 {
3828                                     FIXCLIP(0);
3829                                     DrawBackground (PPU.BGMode, 0, 5, 13);
3830                                 }
3831                                 if (BG1 && PPU.BGMode != 6)
3832                                 {
3833                                     FIXCLIP(1);
3834                                     DrawBackground (PPU.BGMode, 1, 2, 9);
3835                                 }
3836                     }
3837                     else 
3838                     {
3839                                 // screen mode 7
3840                                 if (OB)
3841                                 {
3842                                     FIXCLIP(4);
3843                                     DrawOBJS ();
3844                                 }
3845                                 if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
3846                                 {
3847                                     int bg;
3848                                     FIXCLIP(0);
3849                                     if (Memory.FillRAM [0x2133] & 0x40)
3850                                     {
3851                                         GFX.Mode7Mask = 0x7f;
3852                                         GFX.Mode7PriorityMask = 0x80;
3853                                         Mode7Depths [0] = 5;
3854                                         Mode7Depths [1] = 9;
3855                                         bg = 1;
3856                                     }
3857                                     else
3858                                     {
3859                                         GFX.Mode7Mask = 0xff;
3860                                         GFX.Mode7PriorityMask = 0;
3861                                         Mode7Depths [0] = 5;
3862                                         Mode7Depths [1] = 5;
3863                                         bg = 0;
3864                                     }
3865
3866 #ifndef _SNESPPC
3867                                     if (!Settings.SixteenBit)
3868                                         DrawBGMode7Background (GFX.Screen, bg);
3869                                     else
3870 #endif
3871                                     {
3872                                         if (!Settings.Mode7Interpolate)
3873                                         {       
3874                                             DrawBGMode7Background16 (GFX.Screen, bg);
3875                                         }
3876                                         else
3877                                         {       
3878                                             DrawBGMode7Background16_i (GFX.Screen, bg);
3879                                         }
3880                                   }
3881                                 }
3882                     }
3883                 }
3884         }
3885 #ifndef RC_OPTIMIZE // no hi res
3886     if (Settings.SupportHiRes && PPU.BGMode != 5 && PPU.BGMode != 6)
3887     {
3888         if (IPPU.DoubleWidthPixels)
3889         {
3890             // Mixure of background modes used on screen - scale width
3891             // of all non-mode 5 and 6 pixels.
3892 #ifndef _SNESPPC
3893                 if (Settings.SixteenBit)
3894 #endif
3895             {
3896                 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3897                 {
3898                     register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 255;
3899                     register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch) + 510;
3900                     for (register int x = 255; x >= 0; x--, p--, q -= 2)
3901                         *q = *(q + 1) = *p;
3902                 }
3903             }
3904 #ifndef _SNESPPC
3905             else
3906             {
3907                 for (register uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3908                 {
3909                     register uint8 *p = GFX.Screen + y * GFX.Pitch + 255;
3910                     register uint8 *q = GFX.Screen + y * GFX.Pitch + 510;
3911                     for (register int x = 255; x >= 0; x--, p--, q -= 2)
3912                         *q = *(q + 1) = *p;
3913                 }
3914             }
3915 #endif
3916         }
3917
3918         if (IPPU.LatchedInterlace)
3919         {
3920             // Interlace is enabled - double the height of all non-mode 5 and 6
3921             // pixels.
3922             for (uint32 y = GFX.StartY; y <= GFX.EndY; y++)
3923             {
3924                 memcpy32 ((uint32_t*)(GFX.Screen + (y * 2 + 1) * GFX.Pitch2),
3925                          (uint32_t*)(GFX.Screen + y * 2 * GFX.Pitch2),
3926                          GFX.Pitch2>>2);
3927             }
3928         }
3929     }
3930 #endif
3931     IPPU.PreviousLine = IPPU.CurrentLine;
3932 }
3933
3934 #ifdef GFX_MULTI_FORMAT
3935
3936 #define _BUILD_PIXEL(F) \
3937 uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
3938 { \
3939     return (BUILD_PIXEL_##F(R,G,B)); \
3940 }\
3941 uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
3942 { \
3943     return (BUILD_PIXEL2_##F(R,G,B)); \
3944 } \
3945 void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
3946 { \
3947     DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
3948 }
3949
3950 _BUILD_PIXEL(RGB565)
3951 _BUILD_PIXEL(RGB555)
3952 _BUILD_PIXEL(BGR565)
3953 _BUILD_PIXEL(BGR555)
3954 _BUILD_PIXEL(GBR565)
3955 _BUILD_PIXEL(GBR555)
3956 _BUILD_PIXEL(RGB5551)
3957
3958 bool8_32 S9xSetRenderPixelFormat (int format)
3959 {
3960     extern uint32 current_graphic_format;
3961
3962     current_graphic_format = format;
3963
3964     switch (format)
3965     {
3966     case RGB565:
3967         _BUILD_SETUP(RGB565)
3968         return (TRUE);
3969     case RGB555:
3970         _BUILD_SETUP(RGB555)
3971         return (TRUE);
3972     case BGR565:
3973         _BUILD_SETUP(BGR565)
3974         return (TRUE);
3975     case BGR555:
3976         _BUILD_SETUP(BGR555)
3977         return (TRUE);
3978     case GBR565:
3979         _BUILD_SETUP(GBR565)
3980         return (TRUE);
3981     case GBR555:
3982         _BUILD_SETUP(GBR555)
3983         return (TRUE);
3984     case RGB5551:
3985         _BUILD_SETUP(RGB5551)
3986         return (TRUE);
3987     default:
3988         break;
3989     }
3990     return (FALSE);
3991 }
3992 #endif