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