tile.cpp
   1  #include <Arduino.h>
   2  
   3  /*****************************************************************************\
   4       Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
   5                  This file is licensed under the Snes9x License.
   6     For further information, consult the LICENSE file in the root directory.
   7  \*****************************************************************************/
   8  
   9  // This file includes itself multiple times.
  10  // The other option would be to have 4 files, where A includes B, and B includes C 3 times, and C includes D 5 times.
  11  // Look for the following marker to find where the divisions are.
  12  
  13  // Top-level compilation.
  14  
  15  #ifndef _NEWTILE_CPP
  16  #define _NEWTILE_CPP
  17  
  18  // #pragma GCC optimize("Os")
  19  
  20  #include "snes9x.h"
  21  #include "ppu.h"
  22  #include "tile.h"
  23  
  24  static uint32	pixbit[8][16];
  25  static uint8	hrbit_odd[256];
  26  static uint8	hrbit_even[256];
  27  static SNESPixel	BlackColourMap[256];
  28  static SNESPixel	DirectColourMaps[8][256];
  29  static uint8	brightness_cap[64];
  30  static struct SLineMatrixData LineMatrixData[240];
  31  PROGMEM static uint8 mul_brightness[16][32] =
  32  {
  33  	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  34  	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
  35  	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  36  	  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
  37  	{ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
  38  	  0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04 },
  39  	{ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
  40  	  0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06 },
  41  	{ 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04,
  42  	  0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08 },
  43  	{ 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05,
  44  	  0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a },
  45  	{ 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06,
  46  	  0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c },
  47  	{ 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07,
  48  	  0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e },
  49  	{ 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08,
  50  	  0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x11 },
  51  	{ 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09,
  52  	  0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x13 },
  53  	{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x09, 0x0a,
  54  	  0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15 },
  55  	{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b,
  56  	  0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17 },
  57  	{ 0x00, 0x01, 0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c,
  58  	  0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19 },
  59  	{ 0x00, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d,
  60  	  0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1b },
  61  	{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
  62  	  0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d },
  63  	{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  64  	  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }
  65  };
  66  
  67  
  68  void S9xInitTileRenderer (void)
  69  {
  70    memset(BlackColourMap, 0, 256 * sizeof(SNESPixel));
  71  
  72  	S9xBuildDirectColourMaps();
  73  	S9xFixColourBrightness();
  74  
  75  	for (int i = 0; i < 16; i++)
  76  	{
  77  		uint32	b = 0;
  78  
  79  	#ifdef LSB_FIRST
  80  		if (i & 8) b |= 1;
  81  		if (i & 4) b |= 1 << 8;
  82  		if (i & 2) b |= 1 << 16;
  83  		if (i & 1) b |= 1 << 24;
  84  	#else
  85  		if (i & 8) b |= 1 << 24;
  86  		if (i & 4) b |= 1 << 16;
  87  		if (i & 2) b |= 1 << 8;
  88  		if (i & 1) b |= 1;
  89  	#endif
  90  
  91  		for (int bitshift = 0; bitshift < 8; bitshift++)
  92  			pixbit[bitshift][i] = b << bitshift;
  93  	}
  94  
  95  	for (int i = 0; i < 256; i++)
  96  	{
  97  		uint32	m = 0;
  98  		uint32	s = 0;
  99  
 100  		if (i & 0x80) s |= 8;
 101  		if (i & 0x40) m |= 8;
 102  		if (i & 0x20) s |= 4;
 103  		if (i & 0x10) m |= 4;
 104  		if (i & 0x08) s |= 2;
 105  		if (i & 0x04) m |= 2;
 106  		if (i & 0x02) s |= 1;
 107  		if (i & 0x01) m |= 1;
 108  
 109  		hrbit_odd[i]  = m;
 110  		hrbit_even[i] = s;
 111  	}
 112  }
 113  
 114  void S9xBuildDirectColourMaps (void)
 115  {
 116  	IPPU.XB = (uint8 *)mul_brightness[PPU.Brightness];
 117  
 118  	for (int p = 0; p < 8; p++)
 119  	{
 120  		for (int c = 0; c < 256; c++)
 121  		{
 122  			uint8 r = IPPU.XB[((c & 7) << 2) | ((p & 1) << 1)];
 123  			uint8 g = IPPU.XB[((c & 0x38) >> 1) | (p & 2)];
 124  			uint8 b = IPPU.XB[((c & 0xc0) >> 3) | (p & 4)];
 125  			DirectColourMaps[p][c] = BUILD_PIXEL(r, g, b);
 126  			//if ( DirectColourMaps[p][c] ) emu_printi(DirectColourMaps[p][c]);
 127  		}
 128  	}
 129  }
 130  
 131  void S9xFixColourBrightness (void)
 132  {
 133  	IPPU.XB = (uint8 *)mul_brightness[PPU.Brightness];
 134  
 135  	for (int i = 0; i < 64; i++)
 136  	{
 137  		if (i > IPPU.XB[0x1f])
 138  			brightness_cap[i] = IPPU.XB[0x1f];
 139  		else
 140  			brightness_cap[i] = i;
 141  	}
 142  
 143  	for (int i = 0; i < 256; i++)
 144  	{
 145  		uint8 r = IPPU.XB[(PPU.CGDATA[i])       & 0x1f];
 146  		uint8 g = IPPU.XB[(PPU.CGDATA[i] >>  5) & 0x1f];
 147  		uint8 b = IPPU.XB[(PPU.CGDATA[i] >> 10) & 0x1f];
 148  		IPPU.ScreenColors[i] = BUILD_PIXEL(r, g, b);
 149  	}
 150  }
 151  
 152  void S9UpdateLineMatrix(int line)
 153  {
 154  	struct SLineMatrixData *p = &LineMatrixData[line];
 155  	p->MatrixA = PPU.MatrixA;
 156  	p->MatrixB = PPU.MatrixB;
 157  	p->MatrixC = PPU.MatrixC;
 158  	p->MatrixD = PPU.MatrixD;
 159  	p->CentreX = PPU.CentreX;
 160  	p->CentreY = PPU.CentreY;
 161  	p->M7HOFS  = PPU.M7HOFS;
 162  	p->M7VOFS  = PPU.M7VOFS;
 163  }
 164  
 165  #define COLOR_ADD1_2(C1, C2) \
 166  	((((((C1) & RGB_REMOVE_LOW_BITS_MASK) + \
 167  	((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1) + \
 168  	((C1) & (C2) & RGB_LOW_BITS_MASK)) )
 169  #define COLOR_ADD_BRIGHTNESS1_2 COLOR_ADD1_2
 170  
 171  
 172  static inline uint16 COLOR_ADD_BRIGHTNESS(uint32 C1, uint32 C2)
 173  {
 174      return ((brightness_cap[ (C1 >> RED_SHIFT_BITS)           +  (C2 >> RED_SHIFT_BITS)          ] << RED_SHIFT_BITS)   |
 175              (brightness_cap[((C1 >> GREEN_SHIFT_BITS) & 0x1f) + ((C2 >> GREEN_SHIFT_BITS) & 0x1f)] << GREEN_SHIFT_BITS) |
 176  // Proper 15->16bit color conversion moves the high bit of green into the low bit.
 177  #if GREEN_SHIFT_BITS == 6
 178             ((brightness_cap[((C1 >> 6) & 0x1f) + ((C2 >> 6) & 0x1f)] & 0x10) << 1) |
 179  #endif
 180              (brightness_cap[ (C1                      & 0x1f) +  (C2                      & 0x1f)]      ));
 181  }
 182  
 183  static inline uint16 COLOR_ADD(uint32 C1, uint32 C2)
 184  {
 185  //  return C1;
 186    
 187  	const uint32 RED_MASK   = 0x1F << RED_SHIFT_BITS;
 188  	const uint32 GREEN_MASK = 0x1F << GREEN_SHIFT_BITS;
 189  	const uint32 BLUE_MASK  = 0x1F;
 190  
 191  	int rb = C1 & (RED_MASK | BLUE_MASK);
 192  	rb += C2 & (RED_MASK | BLUE_MASK);
 193  	int rbcarry = rb & ((0x20 << RED_SHIFT_BITS) | (0x20 << 0));
 194  	int g = (C1 & (GREEN_MASK)) + (C2 & (GREEN_MASK));
 195  	int rgbsaturate = (((g & (0x20 << GREEN_SHIFT_BITS)) | rbcarry) >> 5) * 0x1f;
 196  	uint16 retval = (rb & (RED_MASK | BLUE_MASK)) | (g & GREEN_MASK) | rgbsaturate;
 197  #if GREEN_SHIFT_BITS == 6
 198  	retval |= (retval & 0x0400) >> 5;
 199  #endif
 200  //  int rr = (retval & 0xF800) >> (2+11);
 201  //  int gg = (retval & 0x07E0) >> (3+5);
 202  //  int bb = (retval & 0x001F) >> 3  ;
 203  //  retval = (rr << 5) + (gg << 2) + bb;
 204  	return retval;
 205    
 206  }
 207  
 208  #define COLOR_SUB1_2(C1, C2) \
 209  	GFX.ZERO[(((C1) | RGB_HI_BITS_MASKx2) - \
 210  	((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1]
 211  
 212  static inline uint16 COLOR_SUB (uint32 C1, uint32 C2)
 213  {
 214  //  return C1;
 215    
 216  	int rb1 = (C1 & (THIRD_COLOR_MASK | FIRST_COLOR_MASK)) | ((0x20 << 0) | (0x20 << RED_SHIFT_BITS));
 217  	int rb2 = C2 & (THIRD_COLOR_MASK | FIRST_COLOR_MASK);
 218  	int rb = rb1 - rb2;
 219  	int rbcarry = rb & ((0x20 << RED_SHIFT_BITS) | (0x20 << 0));
 220  	int g = ((C1 & (SECOND_COLOR_MASK)) | (0x20 << GREEN_SHIFT_BITS)) - (C2 & (SECOND_COLOR_MASK));
 221  	int rgbsaturate = (((g & (0x20 << GREEN_SHIFT_BITS)) | rbcarry) >> 5) * 0x1f;
 222  	uint16 retval = ((rb & (THIRD_COLOR_MASK | FIRST_COLOR_MASK)) | (g & SECOND_COLOR_MASK)) & rgbsaturate;
 223  #if GREEN_SHIFT_BITS == 6
 224  	retval |= (retval & 0x0400) >> 5;
 225  #endif
 226  //  int rr = (retval & 0xF800) >> (2+11);
 227  //  int gg = (retval & 0x07E0) >> (3+5);
 228  //  int bb = (retval & 0x001F) >> 3  ;
 229  //  retval = (rr << 5) + (gg << 2) + bb;
 230  	return retval;
 231    
 232  }
 233  
 234  // Here are the tile converters, selected by S9xSelectTileConverter().
 235  // Really, except for the definition of DOBIT and the number of times it is called, they're all the same.
 236  
 237  #define DOBIT(n, i) \
 238  	if ((pix = *(tp + (n)))) \
 239  	{ \
 240  		p1 |= pixbit[(i)][pix >> 4]; \
 241  		p2 |= pixbit[(i)][pix & 0xf]; \
 242  	}
 243  
 244  static uint8 ConvertTile2 (uint8 *pCache, uint32 TileAddr, uint32 Unused)
 245  {
 246  	uint8	*tp      = &Memory.VRAM[TileAddr];
 247  	uint32	*p       = (uint32 *) pCache;
 248  	uint32	non_zero = 0;
 249  
 250  	for (int line = 8; line != 0; line--, tp += 2)
 251  	{
 252  		uint32	p1 = 0;
 253  		uint32	p2 = 0;
 254  		uint32	pix;
 255  
 256  		DOBIT( 0, 0);
 257  		DOBIT( 1, 1);
 258  		*p++ = p1;
 259  		*p++ = p2;
 260  		non_zero |= p1 | p2;
 261  	}
 262  
 263  	return (non_zero ? TRUE : BLANK_TILE);
 264  }
 265  
 266  static uint8 ConvertTile4 (uint8 *pCache, uint32 TileAddr, uint32 Unused)
 267  {
 268  	uint8	*tp      = &Memory.VRAM[TileAddr];
 269  	uint32	*p       = (uint32 *) pCache;
 270  	uint32	non_zero = 0;
 271  
 272  	for (int line = 8; line != 0; line--, tp += 2)
 273  	{
 274  		uint32	p1 = 0;
 275  		uint32	p2 = 0;
 276  		uint32	pix;
 277  
 278  		DOBIT( 0, 0);
 279  		DOBIT( 1, 1);
 280  		DOBIT(16, 2);
 281  		DOBIT(17, 3);
 282  		*p++ = p1;
 283  		*p++ = p2;
 284  		non_zero |= p1 | p2;
 285  	}
 286  
 287  	return (non_zero ? TRUE : BLANK_TILE);
 288  }
 289  
 290  static uint8 ConvertTile8 (uint8 *pCache, uint32 TileAddr, uint32 Unused)
 291  {
 292  	uint8	*tp      = &Memory.VRAM[TileAddr];
 293  	uint32	*p       = (uint32 *) pCache;
 294  	uint32	non_zero = 0;
 295  
 296  	for (int line = 8; line != 0; line--, tp += 2)
 297  	{
 298  		uint32	p1 = 0;
 299  		uint32	p2 = 0;
 300  		uint32	pix;
 301  
 302  		DOBIT( 0, 0);
 303  		DOBIT( 1, 1);
 304  		DOBIT(16, 2);
 305  		DOBIT(17, 3);
 306  		DOBIT(32, 4);
 307  		DOBIT(33, 5);
 308  		DOBIT(48, 6);
 309  		DOBIT(49, 7);
 310  		*p++ = p1;
 311  		*p++ = p2;
 312  		non_zero |= p1 | p2;
 313  	}
 314  
 315  	return (non_zero ? TRUE : BLANK_TILE);
 316  }
 317  
 318  #undef DOBIT
 319  
 320  #define DOBIT(n, i) \
 321  	if ((pix = hrbit_odd[*(tp1 + (n))])) \
 322  		p1 |= pixbit[(i)][pix]; \
 323  	if ((pix = hrbit_odd[*(tp2 + (n))])) \
 324  		p2 |= pixbit[(i)][pix];
 325  
 326  static uint8 ConvertTile2h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile)
 327  {
 328  	uint8	*tp1     = &Memory.VRAM[TileAddr], *tp2;
 329  	uint32	*p       = (uint32 *) pCache;
 330  	uint32	non_zero = 0;
 331  
 332  	if (Tile == 0x3ff)
 333  		tp2 = tp1 - (0x3ff << 4);
 334  	else
 335  		tp2 = tp1 + (1 << 4);
 336  
 337  	for (int line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
 338  	{
 339  		uint32	p1 = 0;
 340  		uint32	p2 = 0;
 341  		uint32	pix;
 342  
 343  		DOBIT( 0, 0);
 344  		DOBIT( 1, 1);
 345  		*p++ = p1;
 346  		*p++ = p2;
 347  		non_zero |= p1 | p2;
 348  	}
 349  
 350  	return (non_zero ? TRUE : BLANK_TILE);
 351  }
 352  
 353  static uint8 ConvertTile4h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile)
 354  {
 355  	uint8	*tp1     = &Memory.VRAM[TileAddr], *tp2;
 356  	uint32	*p       = (uint32 *) pCache;
 357  	uint32	non_zero = 0;
 358  
 359  	if (Tile == 0x3ff)
 360  		tp2 = tp1 - (0x3ff << 5);
 361  	else
 362  		tp2 = tp1 + (1 << 5);
 363  
 364  	for (int line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
 365  	{
 366  		uint32			p1 = 0;
 367  		uint32			p2 = 0;
 368  		uint8	pix;
 369  
 370  		DOBIT( 0, 0);
 371  		DOBIT( 1, 1);
 372  		DOBIT(16, 2);
 373  		DOBIT(17, 3);
 374  		*p++ = p1;
 375  		*p++ = p2;
 376  		non_zero |= p1 | p2;
 377  	}
 378  
 379  	return (non_zero ? TRUE : BLANK_TILE);
 380  }
 381  
 382  #undef DOBIT
 383  
 384  #define DOBIT(n, i) \
 385  	if ((pix = hrbit_even[*(tp1 + (n))])) \
 386  		p1 |= pixbit[(i)][pix]; \
 387  	if ((pix = hrbit_even[*(tp2 + (n))])) \
 388  		p2 |= pixbit[(i)][pix];
 389  
 390  static uint8 ConvertTile2h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile)
 391  {
 392  	uint8	*tp1     = &Memory.VRAM[TileAddr], *tp2;
 393  	uint32	*p       = (uint32 *) pCache;
 394  	uint32	non_zero = 0;
 395  
 396  	if (Tile == 0x3ff)
 397  		tp2 = tp1 - (0x3ff << 4);
 398  	else
 399  		tp2 = tp1 + (1 << 4);
 400  
 401  	for (int line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
 402  	{
 403  		uint32	p1 = 0;
 404  		uint32	p2 = 0;
 405  		uint32	pix;
 406  
 407  		DOBIT( 0, 0);
 408  		DOBIT( 1, 1);
 409  		*p++ = p1;
 410  		*p++ = p2;
 411  		non_zero |= p1 | p2;
 412  	}
 413  
 414  	return (non_zero ? TRUE : BLANK_TILE);
 415  }
 416  
 417  static uint8 ConvertTile4h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile)
 418  {
 419  	uint8	*tp1     = &Memory.VRAM[TileAddr], *tp2;
 420  	uint32	*p       = (uint32 *) pCache;
 421  	uint32	non_zero = 0;
 422  
 423  	if (Tile == 0x3ff)
 424  		tp2 = tp1 - (0x3ff << 5);
 425  	else
 426  		tp2 = tp1 + (1 << 5);
 427  
 428  	for (int line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
 429  	{
 430  		uint32	p1 = 0;
 431  		uint32	p2 = 0;
 432  		uint32	pix;
 433  
 434  		DOBIT( 0, 0);
 435  		DOBIT( 1, 1);
 436  		DOBIT(16, 2);
 437  		DOBIT(17, 3);
 438  		*p++ = p1;
 439  		*p++ = p2;
 440  		non_zero |= p1 | p2;
 441  	}
 442  
 443  	return (non_zero ? TRUE : BLANK_TILE);
 444  }
 445  
 446  #undef DOBIT
 447  
 448  // First-level include: Get all the renderers.
 449  #include "tile.cpp"
 450  
 451  // Functions to select which converter and renderer to use.
 452  
 453  void S9xSelectTileRenderers (int BGMode, bool8 sub, bool8 obj)
 454  {
 455  	void	(**DT)		(uint32, uint32, uint32, uint32);
 456  	void	(**DCT)		(uint32, uint32, uint32, uint32, uint32, uint32);
 457  	void	(**DMP)		(uint32, uint32, uint32, uint32, uint32, uint32);
 458  	void	(**DB)		(uint32, uint32, uint32);
 459  	void	(**DM7BG1)	(uint32, uint32, int);
 460  	void	(**DM7BG2)	(uint32, uint32, int);
 461  	bool8	M7M1, M7M2;
 462  
 463  	M7M1 = PPU.BGMosaic[0] && PPU.Mosaic > 1;
 464  	M7M2 = PPU.BGMosaic[1] && PPU.Mosaic > 1;
 465  
 466  	DT     = Renderers_DrawTile16Normal1x1;
 467  	DCT    = Renderers_DrawClippedTile16Normal1x1;
 468  	DMP    = Renderers_DrawMosaicPixel16Normal1x1;
 469  	DB     = Renderers_DrawBackdrop16Normal1x1;
 470  	DM7BG1 = M7M1 ? Renderers_DrawMode7MosaicBG1Normal1x1 : Renderers_DrawMode7BG1Normal1x1;
 471  	DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Normal1x1 : Renderers_DrawMode7BG2Normal1x1;
 472  
 473  	GFX.DrawTileNomath        = DT[0];
 474  	GFX.DrawClippedTileNomath = DCT[0];
 475  	GFX.DrawMosaicPixelNomath = DMP[0];
 476  	GFX.DrawBackdropNomath    = DB[0];
 477  	GFX.DrawMode7BG1Nomath    = DM7BG1[0];
 478  	GFX.DrawMode7BG2Nomath    = DM7BG2[0];
 479  
 480  	int	i = 0;
 481  
 482  	if (Settings.Transparency)
 483  	{
 484  		i = (Memory.PPU_IO[0x131] & 0x80) ? 4 : 1;
 485  		if (Memory.PPU_IO[0x131] & 0x40)
 486  		{
 487  			i++;
 488  			if (Memory.PPU_IO[0x130] & 2)
 489  				i++;
 490  		}
 491  		if (IPPU.MaxBrightness != 0xf)
 492  		{
 493  			if (i == 1)
 494  				i = 7;
 495  			else if (i == 3)
 496  				i = 8;
 497  		}
 498  	}
 499  
 500  	GFX.DrawTileMath        = DT[i];
 501  	GFX.DrawClippedTileMath = DCT[i];
 502  	GFX.DrawMosaicPixelMath = DMP[i];
 503  	GFX.DrawBackdropMath    = DB[i];
 504  	GFX.DrawMode7BG1Math    = DM7BG1[i];
 505  	GFX.DrawMode7BG2Math    = DM7BG2[i];
 506  }
 507  
 508  void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
 509  {
 510  	switch (depth)
 511  	{
 512  		case 8:
 513  			BG.ConvertTile      = BG.ConvertTileFlip = ConvertTile8;
 514  			BG.Buffered         = BG.BufferedFlip    = TILE_8BIT;
 515  			BG.TileShift        = 6;
 516  			BG.PaletteShift     = 0;
 517  			BG.PaletteMask      = 0;
 518  			BG.DirectColourMode = Memory.PPU_IO[0x130] & 1;
 519  
 520  			break;
 521  
 522  		case 4:
 523  			if (hires)
 524  			{
 525  				if (sub || mosaic)
 526  				{
 527  					BG.ConvertTile     = ConvertTile4h_even;
 528  					BG.Buffered        = TILE_4BIT_EVEN;
 529  					BG.ConvertTileFlip = ConvertTile4h_odd;
 530  					BG.BufferedFlip    = TILE_4BIT_ODD;
 531  				}
 532  				else
 533  				{
 534  					BG.ConvertTile     = ConvertTile4h_odd;
 535  					BG.Buffered        = TILE_4BIT_ODD;
 536  					BG.ConvertTileFlip = ConvertTile4h_even;
 537  					BG.BufferedFlip    = TILE_4BIT_EVEN;
 538  				}
 539  			}
 540  			else
 541  			{
 542  				BG.ConvertTile = BG.ConvertTileFlip = ConvertTile4;
 543  				BG.Buffered    = BG.BufferedFlip    = TILE_4BIT;
 544  			}
 545  
 546  			BG.TileShift        = 5;
 547  			BG.PaletteShift     = 10 - 4;
 548  			BG.PaletteMask      = 7 << 4;
 549  			BG.DirectColourMode = FALSE;
 550  
 551  			break;
 552  
 553  		case 2:
 554  			if (hires)
 555  			{
 556  				if (sub || mosaic)
 557  				{
 558  					BG.ConvertTile     = ConvertTile2h_even;
 559  					BG.Buffered        = TILE_2BIT_EVEN;
 560  					BG.ConvertTileFlip = ConvertTile2h_odd;
 561  					BG.BufferedFlip    = TILE_2BIT_ODD;
 562  				}
 563  				else
 564  				{
 565  					BG.ConvertTile     = ConvertTile2h_odd;
 566  					BG.Buffered        = TILE_2BIT_ODD;
 567  					BG.ConvertTileFlip = ConvertTile2h_even;
 568  					BG.BufferedFlip    = TILE_2BIT_EVEN;
 569  				}
 570  			}
 571  			else
 572  			{
 573  				BG.ConvertTile = BG.ConvertTileFlip = ConvertTile2;
 574  				BG.Buffered    = BG.BufferedFlip    = TILE_2BIT;
 575  			}
 576  
 577  			BG.TileShift        = 4;
 578  			BG.PaletteShift     = 10 - 2;
 579  			BG.PaletteMask      = 7 << 2;
 580  			BG.DirectColourMode = FALSE;
 581  
 582  			break;
 583  	}
 584  }
 585  
 586  /*****************************************************************************/
 587  #else
 588  #ifndef NAME1 // First-level: Get all the renderers.
 589  /*****************************************************************************/
 590  
 591  #define GET_CACHED_TILE() \
 592  	uint32	TileNumber; \
 593  	uint32	TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift); \
 594  	if (Tile & 0x100) \
 595  		TileAddr += BG.NameSelect; \
 596  	TileAddr &= 0xffff; \
 597  	TileNumber = TileAddr >> BG.TileShift; \
 598  	pCache = &IPPU.TileCacheData[TileNumber << 6]; \
 599  	if (Tile & H_FLIP) \
 600  	{ \
 601  		if (IPPU.TileCache[TileNumber] != (BG.BufferedFlip|TILE_CACHE_VALID|TILE_CACHE_FLIP)) { \
 602  			if (BG.ConvertTileFlip(pCache, TileAddr, Tile & 0x3ff) == BLANK_TILE) \
 603  				IPPU.TileCache[TileNumber] = BG.BufferedFlip|TILE_CACHE_VALID|TILE_CACHE_BLANK|TILE_CACHE_FLIP; \
 604  			else \
 605  				IPPU.TileCache[TileNumber] = BG.BufferedFlip|TILE_CACHE_VALID|TILE_CACHE_FLIP; \
 606  		} \
 607  	} \
 608  	else \
 609  	{ \
 610  		if (IPPU.TileCache[TileNumber] != (BG.Buffered|TILE_CACHE_VALID)) { \
 611  			if (BG.ConvertTile(pCache, TileAddr, Tile & 0x3ff) == BLANK_TILE) \
 612  				IPPU.TileCache[TileNumber] = BG.Buffered|TILE_CACHE_VALID|TILE_CACHE_BLANK; \
 613  			else \
 614  				IPPU.TileCache[TileNumber] = BG.Buffered|TILE_CACHE_VALID; \
 615  		} \
 616  	}
 617  
 618  #define IS_BLANK_TILE() \
 619  	(IPPU.TileCache[TileNumber] & TILE_CACHE_BLANK)
 620  
 621  #define SELECT_PALETTE() \
 622  	if (BG.DirectColourMode) \
 623  	{ \
 624  		GFX.RealScreenColors = DirectColourMaps[(Tile >> 10) & 7]; \
 625  	} \
 626  	else \
 627  		GFX.RealScreenColors = &IPPU.ScreenColors[((Tile >> BG.PaletteShift) & BG.PaletteMask) + BG.StartPalette]; \
 628  	GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors
 629  
 630  #define NOMATH(Op, Main, Sub, SD) \
 631  	(Main)
 632  
 633  #define REGMATH(Op, Main, Sub, SD) \
 634  	(COLOR_##Op((Main), ((SD) & 0x20) ? (Sub) : GFX.FixedColour))
 635  
 636  #define MATHF1_2(Op, Main, Sub, SD) \
 637  	(GFX.ClipColors ? (COLOR_##Op((Main), GFX.FixedColour)) : (COLOR_##Op##1_2((Main), GFX.FixedColour)))
 638  
 639  #define MATHS1_2(Op, Main, Sub, SD) \
 640  	(GFX.ClipColors ? REGMATH(Op, Main, Sub, SD) : (((SD) & 0x20) ? COLOR_##Op##1_2((Main), (Sub)) : COLOR_##Op((Main), GFX.FixedColour)))
 641  
 642  // Basic routine to render an unclipped tile.
 643  // Input parameters:
 644  //     DRAW_PIXEL(N, M) is a routine to actually draw the pixel. N is the pixel in the row to draw,
 645  //     and M is a test which if false means the pixel should be skipped.
 646  //     Z1 is the "draw if Z1 > cur_depth".
 647  //     Z2 is the "cur_depth = new_depth". OBJ need the two separate.
 648  //     Pix is the pixel to draw.
 649  
 650  #define Z1	GFX.Z1
 651  #define Z2	GFX.Z2
 652  
 653  #define DRAW_TILE() \
 654  	uint8			*pCache; \
 655  	int32	l; \
 656  	uint8	*bp, Pix; \
 657  	\
 658  	GET_CACHED_TILE(); \
 659  	if (IS_BLANK_TILE()) \
 660  		return; \
 661  	SELECT_PALETTE(); \
 662  	\
 663  	if (!(Tile & (V_FLIP | H_FLIP))) \
 664  	{ \
 665  		bp = pCache + StartLine; \
 666  		OFFSET_IN_LINE; \
 667  		for (l = LineCount; l > 0; l--, bp += 8, Offset += GFX.PPL) \
 668  		{ \
 669  			for (int x = 0; x < 8; x++) { \
 670  				DRAW_PIXEL(x, Pix = bp[x]); \
 671  			} \
 672  		} \
 673  	} \
 674  	else \
 675  	if (!(Tile & V_FLIP)) \
 676  	{ \
 677  		bp = pCache + StartLine; \
 678  		OFFSET_IN_LINE; \
 679  		for (l = LineCount; l > 0; l--, bp += 8, Offset += GFX.PPL) \
 680  		{ \
 681  			for (int x = 0; x < 8; x++) { \
 682  				DRAW_PIXEL(x, Pix = bp[7 - x]); \
 683  			} \
 684  		} \
 685  	} \
 686  	else \
 687  	if (!(Tile & H_FLIP)) \
 688  	{ \
 689  		bp = pCache + 56 - StartLine; \
 690  		OFFSET_IN_LINE; \
 691  		for (l = LineCount; l > 0; l--, bp -= 8, Offset += GFX.PPL) \
 692  		{ \
 693  			for (int x = 0; x < 8; x++) { \
 694  				DRAW_PIXEL(x, Pix = bp[x]); \
 695  			} \
 696  		} \
 697  	} \
 698  	else \
 699  	{ \
 700  		bp = pCache + 56 - StartLine; \
 701  		OFFSET_IN_LINE; \
 702  		for (l = LineCount; l > 0; l--, bp -= 8, Offset += GFX.PPL) \
 703  		{ \
 704  			for (int x = 0; x < 8; x++) { \
 705  				DRAW_PIXEL(x, Pix = bp[7 - x]); \
 706  			} \
 707  		} \
 708  	}
 709  
 710  #define NAME1	DrawTile16
 711  #define ARGS	uint32 Tile, uint32 Offset, uint32 StartLine, uint32 LineCount
 712  
 713  // Second-level include: Get the DrawTile16 renderers.
 714  
 715  #include "tile.cpp"
 716  
 717  #undef NAME1
 718  #undef ARGS
 719  #undef DRAW_TILE
 720  #undef Z1
 721  #undef Z2
 722  
 723  // Basic routine to render a clipped tile. Inputs same as above.
 724  
 725  #define Z1	GFX.Z1
 726  #define Z2	GFX.Z2
 727  
 728  #define DRAW_TILE() \
 729  	uint8	*pCache; \
 730  	int32	l; \
 731  	uint8	*bp, Pix, w; \
 732  	\
 733  	GET_CACHED_TILE(); \
 734  	if (IS_BLANK_TILE()) \
 735  		return; \
 736  	SELECT_PALETTE(); \
 737  	\
 738  	if (!(Tile & (V_FLIP | H_FLIP))) \
 739  	{ \
 740  		bp = pCache + StartLine; \
 741  		OFFSET_IN_LINE; \
 742  		for (l = LineCount; l > 0; l--, bp += 8 , Offset += GFX.PPL) \
 743  		{ \
 744  			w = Width; \
 745  			switch (StartPixel) \
 746  			{ \
 747  				case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; /* Fall through */ \
 748  				case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; /* Fall through */ \
 749  				case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; /* Fall through */ \
 750  				case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; /* Fall through */ \
 751  				case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; /* Fall through */ \
 752  				case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; /* Fall through */ \
 753  				case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; /* Fall through */ \
 754  				case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \
 755  			} \
 756  		} \
 757  	} \
 758  	else \
 759  	if (!(Tile & V_FLIP)) \
 760  	{ \
 761  		bp = pCache + StartLine; \
 762  		OFFSET_IN_LINE; \
 763  		for (l = LineCount; l > 0; l--, bp += 8, Offset += GFX.PPL) \
 764  		{ \
 765  			w = Width; \
 766  			switch (StartPixel) \
 767  			{ \
 768  				case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; /* Fall through */ \
 769  				case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; /* Fall through */ \
 770  				case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; /* Fall through */ \
 771  				case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; /* Fall through */ \
 772  				case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; /* Fall through */ \
 773  				case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; /* Fall through */ \
 774  				case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; /* Fall through */ \
 775  				case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \
 776  			} \
 777  		} \
 778  	} \
 779  	else \
 780  	if (!(Tile & H_FLIP)) \
 781  	{ \
 782  		bp = pCache + 56 - StartLine; \
 783  		OFFSET_IN_LINE; \
 784  		for (l = LineCount; l > 0; l--, bp -= 8, Offset += GFX.PPL) \
 785  		{ \
 786  			w = Width; \
 787  			switch (StartPixel) \
 788  			{ \
 789  				case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; /* Fall through */ \
 790  				case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; /* Fall through */ \
 791  				case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; /* Fall through */ \
 792  				case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; /* Fall through */ \
 793  				case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; /* Fall through */ \
 794  				case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; /* Fall through */ \
 795  				case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; /* Fall through */ \
 796  				case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \
 797  			} \
 798  		} \
 799  	} \
 800  	else \
 801  	{ \
 802  		bp = pCache + 56 - StartLine; \
 803  		OFFSET_IN_LINE; \
 804  		for (l = LineCount; l > 0; l--, bp -= 8, Offset += GFX.PPL) \
 805  		{ \
 806  			w = Width; \
 807  			switch (StartPixel) \
 808  			{ \
 809  				case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; /* Fall through */ \
 810  				case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; /* Fall through */ \
 811  				case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; /* Fall through */ \
 812  				case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; /* Fall through */ \
 813  				case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; /* Fall through */ \
 814  				case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; /* Fall through */ \
 815  				case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; /* Fall through */ \
 816  				case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \
 817  			} \
 818  		} \
 819  	}
 820  
 821  #define NAME1	DrawClippedTile16
 822  #define ARGS	uint32 Tile, uint32 Offset, uint32 StartPixel, uint32 Width, uint32 StartLine, uint32 LineCount
 823  
 824  // Second-level include: Get the DrawClippedTile16 renderers.
 825  
 826  #include "tile.cpp"
 827  
 828  #undef NAME1
 829  #undef ARGS
 830  #undef DRAW_TILE
 831  #undef Z1
 832  #undef Z2
 833  
 834  // Basic routine to render a single mosaic pixel.
 835  // DRAW_PIXEL, Z1, Z2 and Pix are the same as above
 836  
 837  #define Z1	GFX.Z1
 838  #define Z2	GFX.Z2
 839  
 840  #define DRAW_TILE() \
 841  	uint8			*pCache; \
 842  	int32	l, w; \
 843  	uint8	Pix; \
 844  	\
 845  	GET_CACHED_TILE(); \
 846  	if (IS_BLANK_TILE()) \
 847  		return; \
 848  	SELECT_PALETTE(); \
 849  	\
 850  	if (Tile & H_FLIP) \
 851  		StartPixel = 7 - StartPixel; \
 852  	\
 853  	if (Tile & V_FLIP) \
 854  		Pix = pCache[56 - StartLine + StartPixel]; \
 855  	else \
 856  		Pix = pCache[StartLine + StartPixel]; \
 857  	\
 858  	if (Pix) \
 859  	{ \
 860  		OFFSET_IN_LINE; \
 861  		for (l = LineCount; l > 0; l--, Offset += GFX.PPL) \
 862  		{ \
 863  			for (w = Width - 1; w >= 0; w--) \
 864  				DRAW_PIXEL(w, 1); \
 865  		} \
 866  	}
 867  
 868  #define NAME1	DrawMosaicPixel16
 869  #define ARGS	uint32 Tile, uint32 Offset, uint32 StartLine, uint32 StartPixel, uint32 Width, uint32 LineCount
 870  
 871  // Second-level include: Get the DrawMosaicPixel16 renderers.
 872  
 873  #include "tile.cpp"
 874  
 875  #undef NAME1
 876  #undef ARGS
 877  #undef DRAW_TILE
 878  #undef Z1
 879  #undef Z2
 880  
 881  // Basic routine to render the backdrop.
 882  // DRAW_PIXEL is the same as above
 883  // (or interlace at all, really).
 884  // The backdrop is always depth = 1, so Z1 = Z2 = 1. And backdrop is always color 0.
 885  
 886  #define Z1				1
 887  #define Z2				1
 888  #define Pix				0
 889  
 890  #define DRAW_TILE() \
 891  	uint32	l, x; \
 892  	\
 893  	GFX.RealScreenColors = IPPU.ScreenColors; \
 894  	GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \
 895  	\
 896  	OFFSET_IN_LINE; \
 897  	for (l = GFX.StartY; l <= GFX.EndY; l++, Offset += GFX.PPL) \
 898  	{ \
 899  		for (x = Left; x < Right; x++) \
 900  			DRAW_PIXEL(x, 1); \
 901  	}
 902  
 903  #define NAME1	DrawBackdrop16
 904  #define ARGS	uint32 Offset, uint32 Left, uint32 Right
 905  
 906  // Second-level include: Get the DrawBackdrop16 renderers.
 907  
 908  #include "tile.cpp"
 909  
 910  #undef NAME1
 911  #undef ARGS
 912  #undef DRAW_TILE
 913  #undef Pix
 914  #undef Z1
 915  #undef Z2
 916  
 917  // Basic routine to render a chunk of a Mode 7 BG.
 918  // We get some new parameters, so we can use the same DRAW_TILE to do BG1 or BG2:
 919  //     DCMODE tests if Direct Color should apply.
 920  //     BG is the BG, so we use the right clip window.
 921  //     MASK is 0xff or 0x7f, the 'color' portion of the pixel.
 922  // We define Z1/Z2 to either be constant 5 or to vary depending on the 'priority' portion of the pixel.
 923  
 924  #define CLIP_10_BIT_SIGNED(a)	(((a) & 0x2000) ? ((a) | ~0x3ff) : ((a) & 0x3ff))
 925  
 926  #define Z1				(D + 7)
 927  #define Z2				(D + 7)
 928  #define MASK			0xff
 929  #define DCMODE			(Memory.PPU_IO[0x130] & 1)
 930  #define BG				0
 931  
 932  #define DRAW_TILE_NORMAL() \
 933  	uint8	*VRAM1 = Memory.VRAM + 1; \
 934  	\
 935  	if (DCMODE) \
 936  	{ \
 937  		GFX.RealScreenColors = DirectColourMaps[0]; \
 938  	} \
 939  	else \
 940  		GFX.RealScreenColors = IPPU.ScreenColors; \
 941  	\
 942  	GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \
 943  	\
 944  	int	aa, cc; \
 945  	int	startx; \
 946  	\
 947  	uint32	Offset = GFX.StartY * GFX.PPL; \
 948  	struct SLineMatrixData	*l = &LineMatrixData[GFX.StartY]; \
 949  	\
 950  	OFFSET_IN_LINE; \
 951  	for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Offset += GFX.PPL, l++) \
 952  	{ \
 953  		int	yy, starty; \
 954  		\
 955  		int32	HOffset = ((int32) l->M7HOFS  << 19) >> 19; \
 956  		int32	VOffset = ((int32) l->M7VOFS  << 19) >> 19; \
 957  		\
 958  		int32	CentreX = ((int32) l->CentreX << 19) >> 19; \
 959  		int32	CentreY = ((int32) l->CentreY << 19) >> 19; \
 960  		\
 961  		if (PPU.Mode7VFlip) \
 962  			starty = 255 - (int) (Line + 1); \
 963  		else \
 964  			starty = Line + 1; \
 965  		\
 966  		yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); \
 967  		\
 968  		int	BB = ((l->MatrixB * starty) & ~63) + ((l->MatrixB * yy) & ~63) + (CentreX << 8); \
 969  		int	DD = ((l->MatrixD * starty) & ~63) + ((l->MatrixD * yy) & ~63) + (CentreY << 8); \
 970  		\
 971  		if (PPU.Mode7HFlip) \
 972  		{ \
 973  			startx = Right - 1; \
 974  			aa = -l->MatrixA; \
 975  			cc = -l->MatrixC; \
 976  		} \
 977  		else \
 978  		{ \
 979  			startx = Left; \
 980  			aa = l->MatrixA; \
 981  			cc = l->MatrixC; \
 982  		} \
 983  		\
 984  		int	xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); \
 985  		int	AA = l->MatrixA * startx + ((l->MatrixA * xx) & ~63); \
 986  		int	CC = l->MatrixC * startx + ((l->MatrixC * xx) & ~63); \
 987  		\
 988  		uint8	Pix; \
 989  		\
 990  		if (!PPU.Mode7Repeat) \
 991  		{ \
 992  			for (uint32 x = Left; x < Right; x++, AA += aa, CC += cc) \
 993  			{ \
 994  				int	X = ((AA + BB) >> 8) & 0x3ff; \
 995  				int	Y = ((CC + DD) >> 8) & 0x3ff; \
 996  				\
 997  				uint8	*TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
 998  				uint8	b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
 999  				\
1000  				DRAW_PIXEL(x, Pix = (b & MASK)); \
1001  			} \
1002  		} \
1003  		else \
1004  		{ \
1005  			for (uint32 x = Left; x < Right; x++, AA += aa, CC += cc) \
1006  			{ \
1007  				int	X = ((AA + BB) >> 8); \
1008  				int	Y = ((CC + DD) >> 8); \
1009  				\
1010  				uint8	b; \
1011  				\
1012  				if (((X | Y) & ~0x3ff) == 0) \
1013  				{ \
1014  					uint8	*TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
1015  					b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
1016  				} \
1017  				else \
1018  				if (PPU.Mode7Repeat == 3) \
1019  					b = *(VRAM1    + ((Y & 7) << 4) + ((X & 7) << 1)); \
1020  				else \
1021  					continue; \
1022  				\
1023  				DRAW_PIXEL(x, Pix = (b & MASK)); \
1024  			} \
1025  		} \
1026  	}
1027  
1028  #define DRAW_TILE_MOSAIC() \
1029  	uint8	*VRAM1 = Memory.VRAM + 1; \
1030  	\
1031  	if (DCMODE) \
1032  	{ \
1033  		GFX.RealScreenColors = DirectColourMaps[0]; \
1034  	} \
1035  	else \
1036  		GFX.RealScreenColors = IPPU.ScreenColors; \
1037  	\
1038  	GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \
1039  	\
1040  	int	aa, cc; \
1041  	int	startx, StartY = GFX.StartY; \
1042  	\
1043  	int		HMosaic = 1, VMosaic = 1, MosaicStart = 0; \
1044  	int32	MLeft = Left, MRight = Right; \
1045  	\
1046  	if (PPU.BGMosaic[0]) \
1047  	{ \
1048  		VMosaic = PPU.Mosaic; \
1049  		MosaicStart = ((uint32) GFX.StartY - PPU.MosaicStart) % VMosaic; \
1050  		StartY -= MosaicStart; \
1051  	} \
1052  	\
1053  	if (PPU.BGMosaic[BG]) \
1054  	{ \
1055  		HMosaic = PPU.Mosaic; \
1056  		MLeft  -= MLeft  % HMosaic; \
1057  		MRight += HMosaic - 1; \
1058  		MRight -= MRight % HMosaic; \
1059  	} \
1060  	\
1061  	uint32	Offset = StartY * GFX.PPL; \
1062  	struct SLineMatrixData	*l = &LineMatrixData[StartY]; \
1063  	\
1064  	OFFSET_IN_LINE; \
1065  	for (uint32 Line = StartY; Line <= GFX.EndY; Line += VMosaic, Offset += VMosaic * GFX.PPL, l += VMosaic) \
1066  	{ \
1067  		if (Line + VMosaic > GFX.EndY) \
1068  			VMosaic = GFX.EndY - Line + 1; \
1069  		\
1070  		int	yy, starty; \
1071  		\
1072  		int32	HOffset = ((int32) l->M7HOFS  << 19) >> 19; \
1073  		int32	VOffset = ((int32) l->M7VOFS  << 19) >> 19; \
1074  		\
1075  		int32	CentreX = ((int32) l->CentreX << 19) >> 19; \
1076  		int32	CentreY = ((int32) l->CentreY << 19) >> 19; \
1077  		\
1078  		if (PPU.Mode7VFlip) \
1079  			starty = 255 - (int) (Line + 1); \
1080  		else \
1081  			starty = Line + 1; \
1082  		\
1083  		yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); \
1084  		\
1085  		int	BB = ((l->MatrixB * starty) & ~63) + ((l->MatrixB * yy) & ~63) + (CentreX << 8); \
1086  		int	DD = ((l->MatrixD * starty) & ~63) + ((l->MatrixD * yy) & ~63) + (CentreY << 8); \
1087  		\
1088  		if (PPU.Mode7HFlip) \
1089  		{ \
1090  			startx = MRight - 1; \
1091  			aa = -l->MatrixA; \
1092  			cc = -l->MatrixC; \
1093  		} \
1094  		else \
1095  		{ \
1096  			startx = MLeft; \
1097  			aa = l->MatrixA; \
1098  			cc = l->MatrixC; \
1099  		} \
1100  		\
1101  		int	xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); \
1102  		int	AA = l->MatrixA * startx + ((l->MatrixA * xx) & ~63); \
1103  		int	CC = l->MatrixC * startx + ((l->MatrixC * xx) & ~63); \
1104  		\
1105  		uint8	Pix; \
1106  		uint8	ctr = 1; \
1107  		\
1108  		if (!PPU.Mode7Repeat) \
1109  		{ \
1110  			for (int x = MLeft; x < MRight; x++, AA += aa, CC += cc) \
1111  			{ \
1112  				if (--ctr) \
1113  					continue; \
1114  				ctr = HMosaic; \
1115  				\
1116  				int	X = ((AA + BB) >> 8) & 0x3ff; \
1117  				int	Y = ((CC + DD) >> 8) & 0x3ff; \
1118  				\
1119  				uint8	*TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
1120  				uint8	b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
1121  				\
1122  				if ((Pix = (b & MASK))) \
1123  				{ \
1124  					for (int h = MosaicStart; h < VMosaic; h++) \
1125  					{ \
1126  						for (int w = x + HMosaic - 1; w >= x; w--) \
1127  							DRAW_PIXEL(w + h * GFX.PPL, (w >= (int32) Left && w < (int32) Right)); \
1128  					} \
1129  				} \
1130  			} \
1131  		} \
1132  		else \
1133  		{ \
1134  			for (int x = MLeft; x < MRight; x++, AA += aa, CC += cc) \
1135  			{ \
1136  				if (--ctr) \
1137  					continue; \
1138  				ctr = HMosaic; \
1139  				\
1140  				int	X = ((AA + BB) >> 8); \
1141  				int	Y = ((CC + DD) >> 8); \
1142  				\
1143  				uint8	b; \
1144  				\
1145  				if (((X | Y) & ~0x3ff) == 0) \
1146  				{ \
1147  					uint8	*TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
1148  					b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
1149  				} \
1150  				else \
1151  				if (PPU.Mode7Repeat == 3) \
1152  					b = *(VRAM1    + ((Y & 7) << 4) + ((X & 7) << 1)); \
1153  				else \
1154  					continue; \
1155  				\
1156  				if ((Pix = (b & MASK))) \
1157  				{ \
1158  					for (int h = MosaicStart; h < VMosaic; h++) \
1159  					{ \
1160  						for (int w = x + HMosaic - 1; w >= x; w--) \
1161  							DRAW_PIXEL(w + h * GFX.PPL, (w >= (int32) Left && w < (int32) Right)); \
1162  					} \
1163  				} \
1164  			} \
1165  		} \
1166  		\
1167  		MosaicStart = 0; \
1168  	}
1169  
1170  #define DRAW_TILE()	DRAW_TILE_NORMAL()
1171  #define NAME1		DrawMode7BG1
1172  #define ARGS		uint32 Left, uint32 Right, int D
1173  
1174  // Second-level include: Get the DrawMode7BG1 renderers.
1175  
1176  #include "tile.cpp"
1177  
1178  #undef NAME1
1179  #undef DRAW_TILE
1180  
1181  #define DRAW_TILE()	DRAW_TILE_MOSAIC()
1182  #define NAME1		DrawMode7MosaicBG1
1183  
1184  // Second-level include: Get the DrawMode7MosaicBG1 renderers.
1185  
1186  #include "tile.cpp"
1187  
1188  #undef DRAW_TILE
1189  #undef NAME1
1190  #undef Z1
1191  #undef Z2
1192  #undef MASK
1193  #undef DCMODE
1194  #undef BG
1195  
1196  #define NAME1		DrawMode7BG2
1197  #define DRAW_TILE()	DRAW_TILE_NORMAL()
1198  #define Z1			(D + ((b & 0x80) ? 11 : 3))
1199  #define Z2			(D + ((b & 0x80) ? 11 : 3))
1200  #define MASK		0x7f
1201  #define DCMODE		0
1202  #define BG			1
1203  
1204  // Second-level include: Get the DrawMode7BG2 renderers.
1205  
1206  #include "tile.cpp"
1207  
1208  #undef NAME1
1209  #undef DRAW_TILE
1210  
1211  #define DRAW_TILE()	DRAW_TILE_MOSAIC()
1212  #define NAME1		DrawMode7MosaicBG2
1213  
1214  // Second-level include: Get the DrawMode7MosaicBG2 renderers.
1215  
1216  #include "tile.cpp"
1217  
1218  #undef MASK
1219  #undef DCMODE
1220  #undef BG
1221  #undef NAME1
1222  #undef ARGS
1223  #undef DRAW_TILE
1224  #undef DRAW_TILE_NORMAL
1225  #undef DRAW_TILE_MOSAIC
1226  #undef Z1
1227  #undef Z2
1228  
1229  /*****************************************************************************/
1230  #else
1231  #ifndef NAME2 // Second-level: Get all the NAME1 renderers.
1232  /*****************************************************************************/
1233  
1234  // The 1x1 pixel plotter, for speedhacking modes.
1235  
1236  #define OFFSET_IN_LINE
1237  #define DRAW_PIXEL(N, M) \
1238  	if (Z1 > GFX.DB[Offset + N] && (M)) \
1239  	{ \
1240  		GFX.S[Offset + N] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + N], GFX.SubZBuffer[Offset + N]); \
1241  		GFX.DB[Offset + N] = Z2; \
1242  	}
1243  
1244  #define NAME2	Normal1x1
1245  
1246  // Third-level include: Get the Normal1x1 renderers.
1247  
1248  #include "tile.cpp"
1249  
1250  #undef NAME2
1251  #undef DRAW_PIXEL
1252  
1253  /*****************************************************************************/
1254  #else // Third-level: Renderers for each math mode for NAME1 + NAME2.
1255  /*****************************************************************************/
1256  
1257  #define CONCAT3(A, B, C)	A##B##C
1258  #define MAKENAME(A, B, C)	CONCAT3(A, B, C)
1259  
1260  static void MAKENAME(NAME1, _, NAME2) (ARGS)
1261  {
1262  #define MATH(A, B, C)	NOMATH(x, A, B, C)
1263  	DRAW_TILE();
1264  #undef MATH
1265  }
1266  
1267  static void MAKENAME(NAME1, Add_, NAME2) (ARGS)
1268  {
1269  #define MATH(A, B, C)	REGMATH(ADD, A, B, C)
1270  	DRAW_TILE();
1271  #undef MATH
1272  }
1273  
1274  static void MAKENAME(NAME1, Add_Brightness_, NAME2) (ARGS)
1275  {
1276  #define MATH(A, B, C)	REGMATH(ADD_BRIGHTNESS, A, B, C)
1277  	DRAW_TILE();
1278  #undef MATH
1279  }
1280  
1281  static void MAKENAME(NAME1, AddF1_2_, NAME2) (ARGS)
1282  {
1283  #define MATH(A, B, C)	MATHF1_2(ADD, A, B, C)
1284  	DRAW_TILE();
1285  #undef MATH
1286  }
1287  
1288  static void MAKENAME(NAME1, AddS1_2_, NAME2) (ARGS)
1289  {
1290  #define MATH(A, B, C)	MATHS1_2(ADD, A, B, C)
1291  	DRAW_TILE();
1292  #undef MATH
1293  }
1294  
1295  static void MAKENAME(NAME1, AddS1_2_Brightness_, NAME2) (ARGS)
1296  {
1297  #define MATH(A, B, C)	MATHS1_2(ADD_BRIGHTNESS, A, B, C)
1298  	DRAW_TILE();
1299  #undef MATH
1300  }
1301  
1302  static void MAKENAME(NAME1, Sub_, NAME2) (ARGS)
1303  {
1304  #define MATH(A, B, C)	REGMATH(SUB, A, B, C)
1305  	DRAW_TILE();
1306  #undef MATH
1307  }
1308  
1309  static void MAKENAME(NAME1, SubF1_2_, NAME2) (ARGS)
1310  {
1311  #define MATH(A, B, C)	MATHF1_2(SUB, A, B, C)
1312  	DRAW_TILE();
1313  #undef MATH
1314  }
1315  
1316  static void MAKENAME(NAME1, SubS1_2_, NAME2) (ARGS)
1317  {
1318  #define MATH(A, B, C)	MATHS1_2(SUB, A, B, C)
1319  	DRAW_TILE();
1320  #undef MATH
1321  }
1322  
1323  static void (*MAKENAME(Renderers_, NAME1, NAME2)[9]) (ARGS) =
1324  {
1325  	MAKENAME(NAME1, _, NAME2),
1326  	MAKENAME(NAME1, Add_, NAME2),
1327  	MAKENAME(NAME1, AddF1_2_, NAME2),
1328  	MAKENAME(NAME1, AddS1_2_, NAME2),
1329  	MAKENAME(NAME1, Sub_, NAME2),
1330  	MAKENAME(NAME1, SubF1_2_, NAME2),
1331  	MAKENAME(NAME1, SubS1_2_, NAME2),
1332  	MAKENAME(NAME1, Add_Brightness_, NAME2),
1333  	MAKENAME(NAME1, AddS1_2_Brightness_, NAME2)
1334  };
1335  
1336  #undef MAKENAME
1337  #undef CONCAT3
1338  
1339  #endif
1340  #endif
1341  #endif