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