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