MCUME/MCUME_teensy41/teensysnes/tile.cpp

1342 wiersze
35 KiB
C++

#include <Arduino.h>
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
// This file includes itself multiple times.
// 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.
// Look for the following marker to find where the divisions are.
// Top-level compilation.
#ifndef _NEWTILE_CPP
#define _NEWTILE_CPP
// #pragma GCC optimize("Os")
#include "snes9x.h"
#include "ppu.h"
#include "tile.h"
static uint32 pixbit[8][16];
static uint8 hrbit_odd[256];
static uint8 hrbit_even[256];
static SNESPixel BlackColourMap[256];
static SNESPixel DirectColourMaps[8][256];
static uint8 brightness_cap[64];
static struct SLineMatrixData LineMatrixData[240];
PROGMEM static uint8 mul_brightness[16][32] =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
{ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04 },
{ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06 },
{ 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04,
0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08 },
{ 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05,
0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a },
{ 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06,
0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c },
{ 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07,
0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e },
{ 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08,
0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x11 },
{ 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09,
0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x13 },
{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x09, 0x0a,
0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15 },
{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b,
0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17 },
{ 0x00, 0x01, 0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c,
0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19 },
{ 0x00, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1b },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }
};
void S9xInitTileRenderer (void)
{
memset(BlackColourMap, 0, 256 * sizeof(SNESPixel));
S9xBuildDirectColourMaps();
S9xFixColourBrightness();
for (int i = 0; i < 16; i++)
{
uint32 b = 0;
#ifdef LSB_FIRST
if (i & 8) b |= 1;
if (i & 4) b |= 1 << 8;
if (i & 2) b |= 1 << 16;
if (i & 1) b |= 1 << 24;
#else
if (i & 8) b |= 1 << 24;
if (i & 4) b |= 1 << 16;
if (i & 2) b |= 1 << 8;
if (i & 1) b |= 1;
#endif
for (int bitshift = 0; bitshift < 8; bitshift++)
pixbit[bitshift][i] = b << bitshift;
}
for (int i = 0; i < 256; i++)
{
uint32 m = 0;
uint32 s = 0;
if (i & 0x80) s |= 8;
if (i & 0x40) m |= 8;
if (i & 0x20) s |= 4;
if (i & 0x10) m |= 4;
if (i & 0x08) s |= 2;
if (i & 0x04) m |= 2;
if (i & 0x02) s |= 1;
if (i & 0x01) m |= 1;
hrbit_odd[i] = m;
hrbit_even[i] = s;
}
}
void S9xBuildDirectColourMaps (void)
{
IPPU.XB = (uint8 *)mul_brightness[PPU.Brightness];
for (int p = 0; p < 8; p++)
{
for (int c = 0; c < 256; c++)
{
uint8 r = IPPU.XB[((c & 7) << 2) | ((p & 1) << 1)];
uint8 g = IPPU.XB[((c & 0x38) >> 1) | (p & 2)];
uint8 b = IPPU.XB[((c & 0xc0) >> 3) | (p & 4)];
DirectColourMaps[p][c] = BUILD_PIXEL(r, g, b);
//if ( DirectColourMaps[p][c] ) emu_printi(DirectColourMaps[p][c]);
}
}
}
void S9xFixColourBrightness (void)
{
IPPU.XB = (uint8 *)mul_brightness[PPU.Brightness];
for (int i = 0; i < 64; i++)
{
if (i > IPPU.XB[0x1f])
brightness_cap[i] = IPPU.XB[0x1f];
else
brightness_cap[i] = i;
}
for (int i = 0; i < 256; i++)
{
uint8 r = IPPU.XB[(PPU.CGDATA[i]) & 0x1f];
uint8 g = IPPU.XB[(PPU.CGDATA[i] >> 5) & 0x1f];
uint8 b = IPPU.XB[(PPU.CGDATA[i] >> 10) & 0x1f];
IPPU.ScreenColors[i] = BUILD_PIXEL(r, g, b);
}
}
void S9UpdateLineMatrix(int line)
{
struct SLineMatrixData *p = &LineMatrixData[line];
p->MatrixA = PPU.MatrixA;
p->MatrixB = PPU.MatrixB;
p->MatrixC = PPU.MatrixC;
p->MatrixD = PPU.MatrixD;
p->CentreX = PPU.CentreX;
p->CentreY = PPU.CentreY;
p->M7HOFS = PPU.M7HOFS;
p->M7VOFS = PPU.M7VOFS;
}
#define COLOR_ADD1_2(C1, C2) \
((((((C1) & RGB_REMOVE_LOW_BITS_MASK) + \
((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1) + \
((C1) & (C2) & RGB_LOW_BITS_MASK)) )
#define COLOR_ADD_BRIGHTNESS1_2 COLOR_ADD1_2
static inline uint16 COLOR_ADD_BRIGHTNESS(uint32 C1, uint32 C2)
{
return ((brightness_cap[ (C1 >> RED_SHIFT_BITS) + (C2 >> RED_SHIFT_BITS) ] << RED_SHIFT_BITS) |
(brightness_cap[((C1 >> GREEN_SHIFT_BITS) & 0x1f) + ((C2 >> GREEN_SHIFT_BITS) & 0x1f)] << GREEN_SHIFT_BITS) |
// Proper 15->16bit color conversion moves the high bit of green into the low bit.
#if GREEN_SHIFT_BITS == 6
((brightness_cap[((C1 >> 6) & 0x1f) + ((C2 >> 6) & 0x1f)] & 0x10) << 1) |
#endif
(brightness_cap[ (C1 & 0x1f) + (C2 & 0x1f)] ));
}
static inline uint16 COLOR_ADD(uint32 C1, uint32 C2)
{
// return C1;
const uint32 RED_MASK = 0x1F << RED_SHIFT_BITS;
const uint32 GREEN_MASK = 0x1F << GREEN_SHIFT_BITS;
const uint32 BLUE_MASK = 0x1F;
int rb = C1 & (RED_MASK | BLUE_MASK);
rb += C2 & (RED_MASK | BLUE_MASK);
int rbcarry = rb & ((0x20 << RED_SHIFT_BITS) | (0x20 << 0));
int g = (C1 & (GREEN_MASK)) + (C2 & (GREEN_MASK));
int rgbsaturate = (((g & (0x20 << GREEN_SHIFT_BITS)) | rbcarry) >> 5) * 0x1f;
uint16 retval = (rb & (RED_MASK | BLUE_MASK)) | (g & GREEN_MASK) | rgbsaturate;
#if GREEN_SHIFT_BITS == 6
retval |= (retval & 0x0400) >> 5;
#endif
// int rr = (retval & 0xF800) >> (2+11);
// int gg = (retval & 0x07E0) >> (3+5);
// int bb = (retval & 0x001F) >> 3 ;
// retval = (rr << 5) + (gg << 2) + bb;
return retval;
}
#define COLOR_SUB1_2(C1, C2) \
GFX.ZERO[(((C1) | RGB_HI_BITS_MASKx2) - \
((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1]
static inline uint16 COLOR_SUB (uint32 C1, uint32 C2)
{
// return C1;
int rb1 = (C1 & (THIRD_COLOR_MASK | FIRST_COLOR_MASK)) | ((0x20 << 0) | (0x20 << RED_SHIFT_BITS));
int rb2 = C2 & (THIRD_COLOR_MASK | FIRST_COLOR_MASK);
int rb = rb1 - rb2;
int rbcarry = rb & ((0x20 << RED_SHIFT_BITS) | (0x20 << 0));
int g = ((C1 & (SECOND_COLOR_MASK)) | (0x20 << GREEN_SHIFT_BITS)) - (C2 & (SECOND_COLOR_MASK));
int rgbsaturate = (((g & (0x20 << GREEN_SHIFT_BITS)) | rbcarry) >> 5) * 0x1f;
uint16 retval = ((rb & (THIRD_COLOR_MASK | FIRST_COLOR_MASK)) | (g & SECOND_COLOR_MASK)) & rgbsaturate;
#if GREEN_SHIFT_BITS == 6
retval |= (retval & 0x0400) >> 5;
#endif
// int rr = (retval & 0xF800) >> (2+11);
// int gg = (retval & 0x07E0) >> (3+5);
// int bb = (retval & 0x001F) >> 3 ;
// retval = (rr << 5) + (gg << 2) + bb;
return retval;
}
// Here are the tile converters, selected by S9xSelectTileConverter().
// Really, except for the definition of DOBIT and the number of times it is called, they're all the same.
#define DOBIT(n, i) \
if ((pix = *(tp + (n)))) \
{ \
p1 |= pixbit[(i)][pix >> 4]; \
p2 |= pixbit[(i)][pix & 0xf]; \
}
static uint8 ConvertTile2 (uint8 *pCache, uint32 TileAddr, uint32 Unused)
{
uint8 *tp = &Memory.VRAM[TileAddr];
uint32 *p = (uint32 *) pCache;
uint32 non_zero = 0;
for (int line = 8; line != 0; line--, tp += 2)
{
uint32 p1 = 0;
uint32 p2 = 0;
uint32 pix;
DOBIT( 0, 0);
DOBIT( 1, 1);
*p++ = p1;
*p++ = p2;
non_zero |= p1 | p2;
}
return (non_zero ? TRUE : BLANK_TILE);
}
static uint8 ConvertTile4 (uint8 *pCache, uint32 TileAddr, uint32 Unused)
{
uint8 *tp = &Memory.VRAM[TileAddr];
uint32 *p = (uint32 *) pCache;
uint32 non_zero = 0;
for (int line = 8; line != 0; line--, tp += 2)
{
uint32 p1 = 0;
uint32 p2 = 0;
uint32 pix;
DOBIT( 0, 0);
DOBIT( 1, 1);
DOBIT(16, 2);
DOBIT(17, 3);
*p++ = p1;
*p++ = p2;
non_zero |= p1 | p2;
}
return (non_zero ? TRUE : BLANK_TILE);
}
static uint8 ConvertTile8 (uint8 *pCache, uint32 TileAddr, uint32 Unused)
{
uint8 *tp = &Memory.VRAM[TileAddr];
uint32 *p = (uint32 *) pCache;
uint32 non_zero = 0;
for (int line = 8; line != 0; line--, tp += 2)
{
uint32 p1 = 0;
uint32 p2 = 0;
uint32 pix;
DOBIT( 0, 0);
DOBIT( 1, 1);
DOBIT(16, 2);
DOBIT(17, 3);
DOBIT(32, 4);
DOBIT(33, 5);
DOBIT(48, 6);
DOBIT(49, 7);
*p++ = p1;
*p++ = p2;
non_zero |= p1 | p2;
}
return (non_zero ? TRUE : BLANK_TILE);
}
#undef DOBIT
#define DOBIT(n, i) \
if ((pix = hrbit_odd[*(tp1 + (n))])) \
p1 |= pixbit[(i)][pix]; \
if ((pix = hrbit_odd[*(tp2 + (n))])) \
p2 |= pixbit[(i)][pix];
static uint8 ConvertTile2h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile)
{
uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2;
uint32 *p = (uint32 *) pCache;
uint32 non_zero = 0;
if (Tile == 0x3ff)
tp2 = tp1 - (0x3ff << 4);
else
tp2 = tp1 + (1 << 4);
for (int line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
{
uint32 p1 = 0;
uint32 p2 = 0;
uint32 pix;
DOBIT( 0, 0);
DOBIT( 1, 1);
*p++ = p1;
*p++ = p2;
non_zero |= p1 | p2;
}
return (non_zero ? TRUE : BLANK_TILE);
}
static uint8 ConvertTile4h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile)
{
uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2;
uint32 *p = (uint32 *) pCache;
uint32 non_zero = 0;
if (Tile == 0x3ff)
tp2 = tp1 - (0x3ff << 5);
else
tp2 = tp1 + (1 << 5);
for (int line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
{
uint32 p1 = 0;
uint32 p2 = 0;
uint8 pix;
DOBIT( 0, 0);
DOBIT( 1, 1);
DOBIT(16, 2);
DOBIT(17, 3);
*p++ = p1;
*p++ = p2;
non_zero |= p1 | p2;
}
return (non_zero ? TRUE : BLANK_TILE);
}
#undef DOBIT
#define DOBIT(n, i) \
if ((pix = hrbit_even[*(tp1 + (n))])) \
p1 |= pixbit[(i)][pix]; \
if ((pix = hrbit_even[*(tp2 + (n))])) \
p2 |= pixbit[(i)][pix];
static uint8 ConvertTile2h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile)
{
uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2;
uint32 *p = (uint32 *) pCache;
uint32 non_zero = 0;
if (Tile == 0x3ff)
tp2 = tp1 - (0x3ff << 4);
else
tp2 = tp1 + (1 << 4);
for (int line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
{
uint32 p1 = 0;
uint32 p2 = 0;
uint32 pix;
DOBIT( 0, 0);
DOBIT( 1, 1);
*p++ = p1;
*p++ = p2;
non_zero |= p1 | p2;
}
return (non_zero ? TRUE : BLANK_TILE);
}
static uint8 ConvertTile4h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile)
{
uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2;
uint32 *p = (uint32 *) pCache;
uint32 non_zero = 0;
if (Tile == 0x3ff)
tp2 = tp1 - (0x3ff << 5);
else
tp2 = tp1 + (1 << 5);
for (int line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
{
uint32 p1 = 0;
uint32 p2 = 0;
uint32 pix;
DOBIT( 0, 0);
DOBIT( 1, 1);
DOBIT(16, 2);
DOBIT(17, 3);
*p++ = p1;
*p++ = p2;
non_zero |= p1 | p2;
}
return (non_zero ? TRUE : BLANK_TILE);
}
#undef DOBIT
// First-level include: Get all the renderers.
#include "tile.cpp"
// Functions to select which converter and renderer to use.
void S9xSelectTileRenderers (int BGMode, bool8 sub, bool8 obj)
{
void (**DT) (uint32, uint32, uint32, uint32);
void (**DCT) (uint32, uint32, uint32, uint32, uint32, uint32);
void (**DMP) (uint32, uint32, uint32, uint32, uint32, uint32);
void (**DB) (uint32, uint32, uint32);
void (**DM7BG1) (uint32, uint32, int);
void (**DM7BG2) (uint32, uint32, int);
bool8 M7M1, M7M2;
M7M1 = PPU.BGMosaic[0] && PPU.Mosaic > 1;
M7M2 = PPU.BGMosaic[1] && PPU.Mosaic > 1;
DT = Renderers_DrawTile16Normal1x1;
DCT = Renderers_DrawClippedTile16Normal1x1;
DMP = Renderers_DrawMosaicPixel16Normal1x1;
DB = Renderers_DrawBackdrop16Normal1x1;
DM7BG1 = M7M1 ? Renderers_DrawMode7MosaicBG1Normal1x1 : Renderers_DrawMode7BG1Normal1x1;
DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Normal1x1 : Renderers_DrawMode7BG2Normal1x1;
GFX.DrawTileNomath = DT[0];
GFX.DrawClippedTileNomath = DCT[0];
GFX.DrawMosaicPixelNomath = DMP[0];
GFX.DrawBackdropNomath = DB[0];
GFX.DrawMode7BG1Nomath = DM7BG1[0];
GFX.DrawMode7BG2Nomath = DM7BG2[0];
int i = 0;
if (Settings.Transparency)
{
i = (Memory.PPU_IO[0x131] & 0x80) ? 4 : 1;
if (Memory.PPU_IO[0x131] & 0x40)
{
i++;
if (Memory.PPU_IO[0x130] & 2)
i++;
}
if (IPPU.MaxBrightness != 0xf)
{
if (i == 1)
i = 7;
else if (i == 3)
i = 8;
}
}
GFX.DrawTileMath = DT[i];
GFX.DrawClippedTileMath = DCT[i];
GFX.DrawMosaicPixelMath = DMP[i];
GFX.DrawBackdropMath = DB[i];
GFX.DrawMode7BG1Math = DM7BG1[i];
GFX.DrawMode7BG2Math = DM7BG2[i];
}
void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
{
switch (depth)
{
case 8:
BG.ConvertTile = BG.ConvertTileFlip = ConvertTile8;
BG.Buffered = BG.BufferedFlip = TILE_8BIT;
BG.TileShift = 6;
BG.PaletteShift = 0;
BG.PaletteMask = 0;
BG.DirectColourMode = Memory.PPU_IO[0x130] & 1;
break;
case 4:
if (hires)
{
if (sub || mosaic)
{
BG.ConvertTile = ConvertTile4h_even;
BG.Buffered = TILE_4BIT_EVEN;
BG.ConvertTileFlip = ConvertTile4h_odd;
BG.BufferedFlip = TILE_4BIT_ODD;
}
else
{
BG.ConvertTile = ConvertTile4h_odd;
BG.Buffered = TILE_4BIT_ODD;
BG.ConvertTileFlip = ConvertTile4h_even;
BG.BufferedFlip = TILE_4BIT_EVEN;
}
}
else
{
BG.ConvertTile = BG.ConvertTileFlip = ConvertTile4;
BG.Buffered = BG.BufferedFlip = TILE_4BIT;
}
BG.TileShift = 5;
BG.PaletteShift = 10 - 4;
BG.PaletteMask = 7 << 4;
BG.DirectColourMode = FALSE;
break;
case 2:
if (hires)
{
if (sub || mosaic)
{
BG.ConvertTile = ConvertTile2h_even;
BG.Buffered = TILE_2BIT_EVEN;
BG.ConvertTileFlip = ConvertTile2h_odd;
BG.BufferedFlip = TILE_2BIT_ODD;
}
else
{
BG.ConvertTile = ConvertTile2h_odd;
BG.Buffered = TILE_2BIT_ODD;
BG.ConvertTileFlip = ConvertTile2h_even;
BG.BufferedFlip = TILE_2BIT_EVEN;
}
}
else
{
BG.ConvertTile = BG.ConvertTileFlip = ConvertTile2;
BG.Buffered = BG.BufferedFlip = TILE_2BIT;
}
BG.TileShift = 4;
BG.PaletteShift = 10 - 2;
BG.PaletteMask = 7 << 2;
BG.DirectColourMode = FALSE;
break;
}
}
/*****************************************************************************/
#else
#ifndef NAME1 // First-level: Get all the renderers.
/*****************************************************************************/
#define GET_CACHED_TILE() \
uint32 TileNumber; \
uint32 TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift); \
if (Tile & 0x100) \
TileAddr += BG.NameSelect; \
TileAddr &= 0xffff; \
TileNumber = TileAddr >> BG.TileShift; \
pCache = &IPPU.TileCacheData[TileNumber << 6]; \
if (Tile & H_FLIP) \
{ \
if (IPPU.TileCache[TileNumber] != (BG.BufferedFlip|TILE_CACHE_VALID|TILE_CACHE_FLIP)) { \
if (BG.ConvertTileFlip(pCache, TileAddr, Tile & 0x3ff) == BLANK_TILE) \
IPPU.TileCache[TileNumber] = BG.BufferedFlip|TILE_CACHE_VALID|TILE_CACHE_BLANK|TILE_CACHE_FLIP; \
else \
IPPU.TileCache[TileNumber] = BG.BufferedFlip|TILE_CACHE_VALID|TILE_CACHE_FLIP; \
} \
} \
else \
{ \
if (IPPU.TileCache[TileNumber] != (BG.Buffered|TILE_CACHE_VALID)) { \
if (BG.ConvertTile(pCache, TileAddr, Tile & 0x3ff) == BLANK_TILE) \
IPPU.TileCache[TileNumber] = BG.Buffered|TILE_CACHE_VALID|TILE_CACHE_BLANK; \
else \
IPPU.TileCache[TileNumber] = BG.Buffered|TILE_CACHE_VALID; \
} \
}
#define IS_BLANK_TILE() \
(IPPU.TileCache[TileNumber] & TILE_CACHE_BLANK)
#define SELECT_PALETTE() \
if (BG.DirectColourMode) \
{ \
GFX.RealScreenColors = DirectColourMaps[(Tile >> 10) & 7]; \
} \
else \
GFX.RealScreenColors = &IPPU.ScreenColors[((Tile >> BG.PaletteShift) & BG.PaletteMask) + BG.StartPalette]; \
GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors
#define NOMATH(Op, Main, Sub, SD) \
(Main)
#define REGMATH(Op, Main, Sub, SD) \
(COLOR_##Op((Main), ((SD) & 0x20) ? (Sub) : GFX.FixedColour))
#define MATHF1_2(Op, Main, Sub, SD) \
(GFX.ClipColors ? (COLOR_##Op((Main), GFX.FixedColour)) : (COLOR_##Op##1_2((Main), GFX.FixedColour)))
#define MATHS1_2(Op, Main, Sub, SD) \
(GFX.ClipColors ? REGMATH(Op, Main, Sub, SD) : (((SD) & 0x20) ? COLOR_##Op##1_2((Main), (Sub)) : COLOR_##Op((Main), GFX.FixedColour)))
// Basic routine to render an unclipped tile.
// Input parameters:
// DRAW_PIXEL(N, M) is a routine to actually draw the pixel. N is the pixel in the row to draw,
// and M is a test which if false means the pixel should be skipped.
// Z1 is the "draw if Z1 > cur_depth".
// Z2 is the "cur_depth = new_depth". OBJ need the two separate.
// Pix is the pixel to draw.
#define Z1 GFX.Z1
#define Z2 GFX.Z2
#define DRAW_TILE() \
uint8 *pCache; \
int32 l; \
uint8 *bp, Pix; \
\
GET_CACHED_TILE(); \
if (IS_BLANK_TILE()) \
return; \
SELECT_PALETTE(); \
\
if (!(Tile & (V_FLIP | H_FLIP))) \
{ \
bp = pCache + StartLine; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp += 8, Offset += GFX.PPL) \
{ \
for (int x = 0; x < 8; x++) { \
DRAW_PIXEL(x, Pix = bp[x]); \
} \
} \
} \
else \
if (!(Tile & V_FLIP)) \
{ \
bp = pCache + StartLine; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp += 8, Offset += GFX.PPL) \
{ \
for (int x = 0; x < 8; x++) { \
DRAW_PIXEL(x, Pix = bp[7 - x]); \
} \
} \
} \
else \
if (!(Tile & H_FLIP)) \
{ \
bp = pCache + 56 - StartLine; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp -= 8, Offset += GFX.PPL) \
{ \
for (int x = 0; x < 8; x++) { \
DRAW_PIXEL(x, Pix = bp[x]); \
} \
} \
} \
else \
{ \
bp = pCache + 56 - StartLine; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp -= 8, Offset += GFX.PPL) \
{ \
for (int x = 0; x < 8; x++) { \
DRAW_PIXEL(x, Pix = bp[7 - x]); \
} \
} \
}
#define NAME1 DrawTile16
#define ARGS uint32 Tile, uint32 Offset, uint32 StartLine, uint32 LineCount
// Second-level include: Get the DrawTile16 renderers.
#include "tile.cpp"
#undef NAME1
#undef ARGS
#undef DRAW_TILE
#undef Z1
#undef Z2
// Basic routine to render a clipped tile. Inputs same as above.
#define Z1 GFX.Z1
#define Z2 GFX.Z2
#define DRAW_TILE() \
uint8 *pCache; \
int32 l; \
uint8 *bp, Pix, w; \
\
GET_CACHED_TILE(); \
if (IS_BLANK_TILE()) \
return; \
SELECT_PALETTE(); \
\
if (!(Tile & (V_FLIP | H_FLIP))) \
{ \
bp = pCache + StartLine; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp += 8 , Offset += GFX.PPL) \
{ \
w = Width; \
switch (StartPixel) \
{ \
case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; /* Fall through */ \
case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; /* Fall through */ \
case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; /* Fall through */ \
case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; /* Fall through */ \
case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; /* Fall through */ \
case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; /* Fall through */ \
case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; /* Fall through */ \
case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \
} \
} \
} \
else \
if (!(Tile & V_FLIP)) \
{ \
bp = pCache + StartLine; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp += 8, Offset += GFX.PPL) \
{ \
w = Width; \
switch (StartPixel) \
{ \
case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; /* Fall through */ \
case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; /* Fall through */ \
case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; /* Fall through */ \
case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; /* Fall through */ \
case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; /* Fall through */ \
case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; /* Fall through */ \
case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; /* Fall through */ \
case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \
} \
} \
} \
else \
if (!(Tile & H_FLIP)) \
{ \
bp = pCache + 56 - StartLine; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp -= 8, Offset += GFX.PPL) \
{ \
w = Width; \
switch (StartPixel) \
{ \
case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; /* Fall through */ \
case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; /* Fall through */ \
case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; /* Fall through */ \
case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; /* Fall through */ \
case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; /* Fall through */ \
case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; /* Fall through */ \
case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; /* Fall through */ \
case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \
} \
} \
} \
else \
{ \
bp = pCache + 56 - StartLine; \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, bp -= 8, Offset += GFX.PPL) \
{ \
w = Width; \
switch (StartPixel) \
{ \
case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; /* Fall through */ \
case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; /* Fall through */ \
case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; /* Fall through */ \
case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; /* Fall through */ \
case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; /* Fall through */ \
case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; /* Fall through */ \
case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; /* Fall through */ \
case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \
} \
} \
}
#define NAME1 DrawClippedTile16
#define ARGS uint32 Tile, uint32 Offset, uint32 StartPixel, uint32 Width, uint32 StartLine, uint32 LineCount
// Second-level include: Get the DrawClippedTile16 renderers.
#include "tile.cpp"
#undef NAME1
#undef ARGS
#undef DRAW_TILE
#undef Z1
#undef Z2
// Basic routine to render a single mosaic pixel.
// DRAW_PIXEL, Z1, Z2 and Pix are the same as above
#define Z1 GFX.Z1
#define Z2 GFX.Z2
#define DRAW_TILE() \
uint8 *pCache; \
int32 l, w; \
uint8 Pix; \
\
GET_CACHED_TILE(); \
if (IS_BLANK_TILE()) \
return; \
SELECT_PALETTE(); \
\
if (Tile & H_FLIP) \
StartPixel = 7 - StartPixel; \
\
if (Tile & V_FLIP) \
Pix = pCache[56 - StartLine + StartPixel]; \
else \
Pix = pCache[StartLine + StartPixel]; \
\
if (Pix) \
{ \
OFFSET_IN_LINE; \
for (l = LineCount; l > 0; l--, Offset += GFX.PPL) \
{ \
for (w = Width - 1; w >= 0; w--) \
DRAW_PIXEL(w, 1); \
} \
}
#define NAME1 DrawMosaicPixel16
#define ARGS uint32 Tile, uint32 Offset, uint32 StartLine, uint32 StartPixel, uint32 Width, uint32 LineCount
// Second-level include: Get the DrawMosaicPixel16 renderers.
#include "tile.cpp"
#undef NAME1
#undef ARGS
#undef DRAW_TILE
#undef Z1
#undef Z2
// Basic routine to render the backdrop.
// DRAW_PIXEL is the same as above
// (or interlace at all, really).
// The backdrop is always depth = 1, so Z1 = Z2 = 1. And backdrop is always color 0.
#define Z1 1
#define Z2 1
#define Pix 0
#define DRAW_TILE() \
uint32 l, x; \
\
GFX.RealScreenColors = IPPU.ScreenColors; \
GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \
\
OFFSET_IN_LINE; \
for (l = GFX.StartY; l <= GFX.EndY; l++, Offset += GFX.PPL) \
{ \
for (x = Left; x < Right; x++) \
DRAW_PIXEL(x, 1); \
}
#define NAME1 DrawBackdrop16
#define ARGS uint32 Offset, uint32 Left, uint32 Right
// Second-level include: Get the DrawBackdrop16 renderers.
#include "tile.cpp"
#undef NAME1
#undef ARGS
#undef DRAW_TILE
#undef Pix
#undef Z1
#undef Z2
// Basic routine to render a chunk of a Mode 7 BG.
// We get some new parameters, so we can use the same DRAW_TILE to do BG1 or BG2:
// DCMODE tests if Direct Color should apply.
// BG is the BG, so we use the right clip window.
// MASK is 0xff or 0x7f, the 'color' portion of the pixel.
// We define Z1/Z2 to either be constant 5 or to vary depending on the 'priority' portion of the pixel.
#define CLIP_10_BIT_SIGNED(a) (((a) & 0x2000) ? ((a) | ~0x3ff) : ((a) & 0x3ff))
#define Z1 (D + 7)
#define Z2 (D + 7)
#define MASK 0xff
#define DCMODE (Memory.PPU_IO[0x130] & 1)
#define BG 0
#define DRAW_TILE_NORMAL() \
uint8 *VRAM1 = Memory.VRAM + 1; \
\
if (DCMODE) \
{ \
GFX.RealScreenColors = DirectColourMaps[0]; \
} \
else \
GFX.RealScreenColors = IPPU.ScreenColors; \
\
GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \
\
int aa, cc; \
int startx; \
\
uint32 Offset = GFX.StartY * GFX.PPL; \
struct SLineMatrixData *l = &LineMatrixData[GFX.StartY]; \
\
OFFSET_IN_LINE; \
for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Offset += GFX.PPL, l++) \
{ \
int yy, starty; \
\
int32 HOffset = ((int32) l->M7HOFS << 19) >> 19; \
int32 VOffset = ((int32) l->M7VOFS << 19) >> 19; \
\
int32 CentreX = ((int32) l->CentreX << 19) >> 19; \
int32 CentreY = ((int32) l->CentreY << 19) >> 19; \
\
if (PPU.Mode7VFlip) \
starty = 255 - (int) (Line + 1); \
else \
starty = Line + 1; \
\
yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); \
\
int BB = ((l->MatrixB * starty) & ~63) + ((l->MatrixB * yy) & ~63) + (CentreX << 8); \
int DD = ((l->MatrixD * starty) & ~63) + ((l->MatrixD * yy) & ~63) + (CentreY << 8); \
\
if (PPU.Mode7HFlip) \
{ \
startx = Right - 1; \
aa = -l->MatrixA; \
cc = -l->MatrixC; \
} \
else \
{ \
startx = Left; \
aa = l->MatrixA; \
cc = l->MatrixC; \
} \
\
int xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); \
int AA = l->MatrixA * startx + ((l->MatrixA * xx) & ~63); \
int CC = l->MatrixC * startx + ((l->MatrixC * xx) & ~63); \
\
uint8 Pix; \
\
if (!PPU.Mode7Repeat) \
{ \
for (uint32 x = Left; x < Right; x++, AA += aa, CC += cc) \
{ \
int X = ((AA + BB) >> 8) & 0x3ff; \
int Y = ((CC + DD) >> 8) & 0x3ff; \
\
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
\
DRAW_PIXEL(x, Pix = (b & MASK)); \
} \
} \
else \
{ \
for (uint32 x = Left; x < Right; x++, AA += aa, CC += cc) \
{ \
int X = ((AA + BB) >> 8); \
int Y = ((CC + DD) >> 8); \
\
uint8 b; \
\
if (((X | Y) & ~0x3ff) == 0) \
{ \
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
} \
else \
if (PPU.Mode7Repeat == 3) \
b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
else \
continue; \
\
DRAW_PIXEL(x, Pix = (b & MASK)); \
} \
} \
}
#define DRAW_TILE_MOSAIC() \
uint8 *VRAM1 = Memory.VRAM + 1; \
\
if (DCMODE) \
{ \
GFX.RealScreenColors = DirectColourMaps[0]; \
} \
else \
GFX.RealScreenColors = IPPU.ScreenColors; \
\
GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \
\
int aa, cc; \
int startx, StartY = GFX.StartY; \
\
int HMosaic = 1, VMosaic = 1, MosaicStart = 0; \
int32 MLeft = Left, MRight = Right; \
\
if (PPU.BGMosaic[0]) \
{ \
VMosaic = PPU.Mosaic; \
MosaicStart = ((uint32) GFX.StartY - PPU.MosaicStart) % VMosaic; \
StartY -= MosaicStart; \
} \
\
if (PPU.BGMosaic[BG]) \
{ \
HMosaic = PPU.Mosaic; \
MLeft -= MLeft % HMosaic; \
MRight += HMosaic - 1; \
MRight -= MRight % HMosaic; \
} \
\
uint32 Offset = StartY * GFX.PPL; \
struct SLineMatrixData *l = &LineMatrixData[StartY]; \
\
OFFSET_IN_LINE; \
for (uint32 Line = StartY; Line <= GFX.EndY; Line += VMosaic, Offset += VMosaic * GFX.PPL, l += VMosaic) \
{ \
if (Line + VMosaic > GFX.EndY) \
VMosaic = GFX.EndY - Line + 1; \
\
int yy, starty; \
\
int32 HOffset = ((int32) l->M7HOFS << 19) >> 19; \
int32 VOffset = ((int32) l->M7VOFS << 19) >> 19; \
\
int32 CentreX = ((int32) l->CentreX << 19) >> 19; \
int32 CentreY = ((int32) l->CentreY << 19) >> 19; \
\
if (PPU.Mode7VFlip) \
starty = 255 - (int) (Line + 1); \
else \
starty = Line + 1; \
\
yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); \
\
int BB = ((l->MatrixB * starty) & ~63) + ((l->MatrixB * yy) & ~63) + (CentreX << 8); \
int DD = ((l->MatrixD * starty) & ~63) + ((l->MatrixD * yy) & ~63) + (CentreY << 8); \
\
if (PPU.Mode7HFlip) \
{ \
startx = MRight - 1; \
aa = -l->MatrixA; \
cc = -l->MatrixC; \
} \
else \
{ \
startx = MLeft; \
aa = l->MatrixA; \
cc = l->MatrixC; \
} \
\
int xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); \
int AA = l->MatrixA * startx + ((l->MatrixA * xx) & ~63); \
int CC = l->MatrixC * startx + ((l->MatrixC * xx) & ~63); \
\
uint8 Pix; \
uint8 ctr = 1; \
\
if (!PPU.Mode7Repeat) \
{ \
for (int x = MLeft; x < MRight; x++, AA += aa, CC += cc) \
{ \
if (--ctr) \
continue; \
ctr = HMosaic; \
\
int X = ((AA + BB) >> 8) & 0x3ff; \
int Y = ((CC + DD) >> 8) & 0x3ff; \
\
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
\
if ((Pix = (b & MASK))) \
{ \
for (int h = MosaicStart; h < VMosaic; h++) \
{ \
for (int w = x + HMosaic - 1; w >= x; w--) \
DRAW_PIXEL(w + h * GFX.PPL, (w >= (int32) Left && w < (int32) Right)); \
} \
} \
} \
} \
else \
{ \
for (int x = MLeft; x < MRight; x++, AA += aa, CC += cc) \
{ \
if (--ctr) \
continue; \
ctr = HMosaic; \
\
int X = ((AA + BB) >> 8); \
int Y = ((CC + DD) >> 8); \
\
uint8 b; \
\
if (((X | Y) & ~0x3ff) == 0) \
{ \
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
} \
else \
if (PPU.Mode7Repeat == 3) \
b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
else \
continue; \
\
if ((Pix = (b & MASK))) \
{ \
for (int h = MosaicStart; h < VMosaic; h++) \
{ \
for (int w = x + HMosaic - 1; w >= x; w--) \
DRAW_PIXEL(w + h * GFX.PPL, (w >= (int32) Left && w < (int32) Right)); \
} \
} \
} \
} \
\
MosaicStart = 0; \
}
#define DRAW_TILE() DRAW_TILE_NORMAL()
#define NAME1 DrawMode7BG1
#define ARGS uint32 Left, uint32 Right, int D
// Second-level include: Get the DrawMode7BG1 renderers.
#include "tile.cpp"
#undef NAME1
#undef DRAW_TILE
#define DRAW_TILE() DRAW_TILE_MOSAIC()
#define NAME1 DrawMode7MosaicBG1
// Second-level include: Get the DrawMode7MosaicBG1 renderers.
#include "tile.cpp"
#undef DRAW_TILE
#undef NAME1
#undef Z1
#undef Z2
#undef MASK
#undef DCMODE
#undef BG
#define NAME1 DrawMode7BG2
#define DRAW_TILE() DRAW_TILE_NORMAL()
#define Z1 (D + ((b & 0x80) ? 11 : 3))
#define Z2 (D + ((b & 0x80) ? 11 : 3))
#define MASK 0x7f
#define DCMODE 0
#define BG 1
// Second-level include: Get the DrawMode7BG2 renderers.
#include "tile.cpp"
#undef NAME1
#undef DRAW_TILE
#define DRAW_TILE() DRAW_TILE_MOSAIC()
#define NAME1 DrawMode7MosaicBG2
// Second-level include: Get the DrawMode7MosaicBG2 renderers.
#include "tile.cpp"
#undef MASK
#undef DCMODE
#undef BG
#undef NAME1
#undef ARGS
#undef DRAW_TILE
#undef DRAW_TILE_NORMAL
#undef DRAW_TILE_MOSAIC
#undef Z1
#undef Z2
/*****************************************************************************/
#else
#ifndef NAME2 // Second-level: Get all the NAME1 renderers.
/*****************************************************************************/
// The 1x1 pixel plotter, for speedhacking modes.
#define OFFSET_IN_LINE
#define DRAW_PIXEL(N, M) \
if (Z1 > GFX.DB[Offset + N] && (M)) \
{ \
GFX.S[Offset + N] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + N], GFX.SubZBuffer[Offset + N]); \
GFX.DB[Offset + N] = Z2; \
}
#define NAME2 Normal1x1
// Third-level include: Get the Normal1x1 renderers.
#include "tile.cpp"
#undef NAME2
#undef DRAW_PIXEL
/*****************************************************************************/
#else // Third-level: Renderers for each math mode for NAME1 + NAME2.
/*****************************************************************************/
#define CONCAT3(A, B, C) A##B##C
#define MAKENAME(A, B, C) CONCAT3(A, B, C)
static void MAKENAME(NAME1, _, NAME2) (ARGS)
{
#define MATH(A, B, C) NOMATH(x, A, B, C)
DRAW_TILE();
#undef MATH
}
static void MAKENAME(NAME1, Add_, NAME2) (ARGS)
{
#define MATH(A, B, C) REGMATH(ADD, A, B, C)
DRAW_TILE();
#undef MATH
}
static void MAKENAME(NAME1, Add_Brightness_, NAME2) (ARGS)
{
#define MATH(A, B, C) REGMATH(ADD_BRIGHTNESS, A, B, C)
DRAW_TILE();
#undef MATH
}
static void MAKENAME(NAME1, AddF1_2_, NAME2) (ARGS)
{
#define MATH(A, B, C) MATHF1_2(ADD, A, B, C)
DRAW_TILE();
#undef MATH
}
static void MAKENAME(NAME1, AddS1_2_, NAME2) (ARGS)
{
#define MATH(A, B, C) MATHS1_2(ADD, A, B, C)
DRAW_TILE();
#undef MATH
}
static void MAKENAME(NAME1, AddS1_2_Brightness_, NAME2) (ARGS)
{
#define MATH(A, B, C) MATHS1_2(ADD_BRIGHTNESS, A, B, C)
DRAW_TILE();
#undef MATH
}
static void MAKENAME(NAME1, Sub_, NAME2) (ARGS)
{
#define MATH(A, B, C) REGMATH(SUB, A, B, C)
DRAW_TILE();
#undef MATH
}
static void MAKENAME(NAME1, SubF1_2_, NAME2) (ARGS)
{
#define MATH(A, B, C) MATHF1_2(SUB, A, B, C)
DRAW_TILE();
#undef MATH
}
static void MAKENAME(NAME1, SubS1_2_, NAME2) (ARGS)
{
#define MATH(A, B, C) MATHS1_2(SUB, A, B, C)
DRAW_TILE();
#undef MATH
}
static void (*MAKENAME(Renderers_, NAME1, NAME2)[9]) (ARGS) =
{
MAKENAME(NAME1, _, NAME2),
MAKENAME(NAME1, Add_, NAME2),
MAKENAME(NAME1, AddF1_2_, NAME2),
MAKENAME(NAME1, AddS1_2_, NAME2),
MAKENAME(NAME1, Sub_, NAME2),
MAKENAME(NAME1, SubF1_2_, NAME2),
MAKENAME(NAME1, SubS1_2_, NAME2),
MAKENAME(NAME1, Add_Brightness_, NAME2),
MAKENAME(NAME1, AddS1_2_Brightness_, NAME2)
};
#undef MAKENAME
#undef CONCAT3
#endif
#endif
#endif