You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

530 lines
14 KiB

/*****************************************************************************\
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.
\*****************************************************************************/
#include "snes9x.h"
#include "blit.h"
#define ALL_COLOR_MASK (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK)
#define lowPixelMask (RGB_LOW_BITS_MASK)
#define qlowPixelMask ((RGB_HI_BITS_MASK >> 3) | TWO_LOW_BITS_MASK)
#define highBitsMask (ALL_COLOR_MASK & RGB_REMOVE_LOW_BITS_MASK)
#define colorMask (((~RGB_HI_BITS_MASK & ALL_COLOR_MASK) << 16) | (~RGB_HI_BITS_MASK & ALL_COLOR_MASK))
static snes_ntsc_t *ntsc = NULL;
static uint8 *XDelta = NULL;
bool8 S9xBlitFilterInit (void)
{
XDelta = new uint8[SNES_WIDTH * SNES_HEIGHT_EXTENDED * 4];
if (!XDelta)
return (FALSE);
S9xBlitClearDelta();
return (TRUE);
}
void S9xBlitFilterDeinit (void)
{
if (XDelta)
{
delete[] XDelta;
XDelta = NULL;
}
}
void S9xBlitClearDelta (void)
{
uint32 *d = (uint32 *) XDelta;
for (int y = 0; y < SNES_HEIGHT_EXTENDED; y++)
for (int x = 0; x < SNES_WIDTH; x++)
*d++ = 0x80008000;
}
bool8 S9xBlitNTSCFilterInit (void)
{
ntsc = (snes_ntsc_t *) malloc(sizeof(snes_ntsc_t));
if (!ntsc)
return (FALSE);
snes_ntsc_init(ntsc, &snes_ntsc_composite);
return (TRUE);
}
void S9xBlitNTSCFilterDeinit (void)
{
if (ntsc)
{
free(ntsc);
ntsc = NULL;
}
}
void S9xBlitNTSCFilterSet (const snes_ntsc_setup_t *setup)
{
snes_ntsc_init(ntsc, setup);
}
void S9xBlitPixSimple1x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
width <<= 1;
for (; height; height--)
{
memcpy(dstPtr, srcPtr, width);
srcPtr += srcRowBytes;
dstPtr += dstRowBytes;
}
}
void S9xBlitPixSimple1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
width <<= 1;
for (; height; height--)
{
memcpy(dstPtr, srcPtr, width);
dstPtr += dstRowBytes;
memcpy(dstPtr, srcPtr, width);
srcPtr += srcRowBytes;
dstPtr += dstRowBytes;
}
}
void S9xBlitPixSimple2x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
for (; height; height--)
{
uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr;
for (int i = 0; i < (width >> 1); i++)
{
*dP++ = *bP;
*dP++ = *bP++;
*dP++ = *bP;
*dP++ = *bP++;
}
srcPtr += srcRowBytes;
dstPtr += dstRowBytes;
}
}
void S9xBlitPixSimple2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta;
dstRowBytes <<= 1;
for (; height; height--)
{
uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr;
uint32 currentPixel, lastPixel, currentPixA, currentPixB, colorA, colorB;
for (int i = 0; i < (width >> 1); i++)
{
currentPixel = *bP;
lastPixel = *xP;
if (currentPixel != lastPixel)
{
#ifdef MSB_FIRST
colorA = (currentPixel >> 16) & 0xFFFF;
colorB = (currentPixel ) & 0xFFFF;
#else
colorA = (currentPixel ) & 0xFFFF;
colorB = (currentPixel >> 16) & 0xFFFF;
#endif
currentPixA = (colorA << 16) | colorA;
currentPixB = (colorB << 16) | colorB;
dP1[0] = currentPixA;
dP1[1] = currentPixB;
dP2[0] = currentPixA;
dP2[1] = currentPixB;
*xP = *bP;
}
bP++;
xP++;
dP1 += 2;
dP2 += 2;
}
srcPtr += srcRowBytes;
deltaPtr += srcRowBytes;
dstPtr += dstRowBytes;
dstPtr2 += dstRowBytes;
}
}
void S9xBlitPixBlend1x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
for (; height; height--)
{
uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr;
uint16 prev, curr;
prev = *bP;
for (int i = 0; i < (width >> 1); i++)
{
curr = *bP++;
*dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1);
prev = curr;
curr = *bP++;
*dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1);
prev = curr;
}
srcPtr += srcRowBytes;
dstPtr += dstRowBytes;
}
}
void S9xBlitPixBlend2x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
for (; height; height--)
{
uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr;
uint16 prev, curr;
prev = *bP;
for (int i = 0; i < (width >> 1); i++)
{
curr = *bP++;
*dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1);
*dP++ = curr;
prev = curr;
curr = *bP++;
*dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1);
*dP++ = curr;
prev = curr;
}
srcPtr += srcRowBytes;
dstPtr += dstRowBytes;
}
}
void S9xBlitPixTV1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
uint8 *dstPtr2 = dstPtr + dstRowBytes;
dstRowBytes <<= 1;
for (; height; height--)
{
uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr;
uint32 product, darkened;
for (int i = 0; i < (width >> 1); i++)
{
product = *dP1++ = *bP++;
darkened = (product = (product >> 1) & colorMask);
darkened += (product = (product >> 1) & colorMask);
*dP2++ = darkened;
}
srcPtr += srcRowBytes;
dstPtr += dstRowBytes;
dstPtr2 += dstRowBytes;
}
}
void S9xBlitPixTV2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta;
dstRowBytes <<= 1;
for (; height; height--)
{
uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr;
uint32 currentPixel, nextPixel, currentDelta, nextDelta, colorA, colorB, product, darkened;
for (int i = 0; i < (width >> 1) - 1; i++)
{
currentPixel = *bP;
currentDelta = *xP;
nextPixel = *(bP + 1);
nextDelta = *(xP + 1);
if ((currentPixel != currentDelta) || (nextPixel != nextDelta))
{
*xP = *bP;
#ifdef MSB_FIRST
colorA = (currentPixel >> 16) & 0xFFFF;
colorB = (currentPixel ) & 0xFFFF;
#else
colorA = (currentPixel ) & 0xFFFF;
colorB = (currentPixel >> 16) & 0xFFFF;
#endif
#ifdef MSB_FIRST
*dP1 = product = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) );
#else
*dP1 = product = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16);
#endif
darkened = (product = ((product >> 1) & colorMask));
darkened += (product = ((product >> 1) & colorMask));
darkened += (product >> 1) & colorMask;
*dP2 = darkened;
#ifdef MSB_FIRST
colorA = (nextPixel >> 16) & 0xFFFF;
#else
colorA = (nextPixel ) & 0xFFFF;
#endif
#ifdef MSB_FIRST
*(dP1 + 1) = product = (colorB << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) );
#else
*(dP1 + 1) = product = (colorB ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16);
#endif
darkened = (product = ((product >> 1) & colorMask));
darkened += (product = ((product >> 1) & colorMask));
darkened += (product >> 1) & colorMask;
*(dP2 + 1) = darkened;
}
bP++;
xP++;
dP1 += 2;
dP2 += 2;
}
// Last 2 Pixels
currentPixel = *bP;
currentDelta = *xP;
if (currentPixel != currentDelta)
{
*xP = *bP;
#ifdef MSB_FIRST
colorA = (currentPixel >> 16) & 0xFFFF;
colorB = (currentPixel ) & 0xFFFF;
#else
colorA = (currentPixel ) & 0xFFFF;
colorB = (currentPixel >> 16) & 0xFFFF;
#endif
#ifdef MSB_FIRST
*dP1 = product = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) );
#else
*dP1 = product = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16);
#endif
darkened = (product = ((product >> 1) & colorMask));
darkened += (product = ((product >> 1) & colorMask));
darkened += (product >> 1) & colorMask;
*dP2 = darkened;
*(dP1 + 1) = product = (colorB << 16) | colorB;
darkened = (product = ((product >> 1) & colorMask));
darkened += (product = ((product >> 1) & colorMask));
darkened += (product >> 1) & colorMask;
*(dP2 + 1) = darkened;
}
srcPtr += srcRowBytes;
deltaPtr += srcRowBytes;
dstPtr += dstRowBytes;
dstPtr2 += dstRowBytes;
}
}
void S9xBlitPixMixedTV1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
uint8 *dstPtr2 = dstPtr + dstRowBytes, *srcPtr2 = srcPtr + srcRowBytes;
dstRowBytes <<= 1;
for (; height > 1; height--)
{
uint16 *dP1 = (uint16 *) dstPtr, *dP2 = (uint16 *) dstPtr2, *bP1 = (uint16 *) srcPtr, *bP2 = (uint16 *) srcPtr2;
uint16 prev, next, mixed;
for (int i = 0; i < width; i++)
{
prev = *bP1++;
next = *bP2++;
mixed = prev + next + ((prev ^ next) & lowPixelMask);
*dP1++ = prev;
*dP2++ = (mixed >> 1) - (mixed >> 4 & qlowPixelMask);
}
srcPtr += srcRowBytes;
srcPtr2 += srcRowBytes;
dstPtr += dstRowBytes;
dstPtr2 += dstRowBytes;
}
// Last 1 line
uint16 *dP1 = (uint16 *) dstPtr, *dP2 = (uint16 *) dstPtr2, *bP1 = (uint16 *) srcPtr;
uint16 prev, mixed;
for (int i = 0; i < width; i++)
{
prev = *bP1++;
mixed = prev + ((prev ^ 0) & lowPixelMask);
*dP1++ = prev;
*dP2++ = (mixed >> 1) - (mixed >> 4 & qlowPixelMask);
}
}
void S9xBlitPixSmooth2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta;
uint32 lastLinePix[SNES_WIDTH << 1];
uint8 lastLineChg[SNES_WIDTH >> 1];
int lineBytes = width << 1;
dstRowBytes <<= 1;
memset(lastLinePix, 0, sizeof(lastLinePix));
memset(lastLineChg, 0, sizeof(lastLineChg));
for (; height; height--)
{
uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr;
uint32 *lL = lastLinePix;
uint8 *lC = lastLineChg;
uint32 currentPixel, nextPixel, currentDelta, nextDelta, lastPix, lastChg, thisChg, currentPixA, currentPixB, colorA, colorB, colorC;
uint16 savePixel;
savePixel = *(uint16 *) (srcPtr + lineBytes);
*(uint16 *) (srcPtr + lineBytes) = *(uint16 *) (srcPtr + lineBytes - 2);
*(uint32 *) (deltaPtr + lineBytes) = *(uint32 *) (srcPtr + lineBytes);
nextPixel = *bP++;
nextDelta = *xP++;
for (int i = 0; i < (width >> 1); i++)
{
currentPixel = nextPixel;
currentDelta = nextDelta;
nextPixel = *bP++;
nextDelta = *xP++;
lastChg = *lC;
thisChg = (nextPixel - nextDelta) | (currentPixel - currentDelta);
#ifdef MSB_FIRST
colorA = (currentPixel >> 16) & 0xFFFF;
colorB = (currentPixel ) & 0xFFFF;
colorC = (nextPixel >> 16) & 0xFFFF;
currentPixA = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) );
currentPixB = (colorB << 16) | ((((colorC >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorC & colorB & lowPixelMask)) );
#else
colorA = (currentPixel ) & 0xFFFF;
colorB = (currentPixel >> 16) & 0xFFFF;
colorC = (nextPixel ) & 0xFFFF;
currentPixA = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16);
currentPixB = (colorB ) | ((((colorC >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorC & colorB & lowPixelMask)) << 16);
#endif
if (thisChg | lastChg)
{
xP[-2] = currentPixel;
lastPix = lL[0];
dP1[0] = ((currentPixA >> 1) & colorMask) + ((lastPix >> 1) & colorMask) + (currentPixA & lastPix & lowPixelMask);
dP2[0] = currentPixA;
lL[0] = currentPixA;
lastPix = lL[1];
dP1[1] = ((currentPixB >> 1) & colorMask) + ((lastPix >> 1) & colorMask) + (currentPixB & lastPix & lowPixelMask);
dP2[1] = currentPixB;
lL[1] = currentPixB;
*lC++ = (thisChg != 0);
}
else
{
lL[0] = currentPixA;
lL[1] = currentPixB;
*lC++ = 0;
}
lL += 2;
dP2 += 2;
dP1 += 2;
}
*(uint16 *) (srcPtr + lineBytes) = savePixel;
srcPtr += srcRowBytes;
deltaPtr += srcRowBytes;
dstPtr += dstRowBytes;
dstPtr2 += dstRowBytes;
}
}
void S9xBlitPixSuper2xSaI16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
Super2xSaI(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height);
}
void S9xBlitPix2xSaI16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
_2xSaI(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height);
}
void S9xBlitPixSuperEagle16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
SuperEagle(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height);
}
void S9xBlitPixEPX16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
EPX_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height);
}
void S9xBlitPixHQ2x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
HQ2X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height);
}
void S9xBlitPixHQ3x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
HQ3X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height);
}
void S9xBlitPixHQ4x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
HQ4X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height);
}
void S9xBlitPixNTSC16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
snes_ntsc_blit(ntsc, (SNES_NTSC_IN_T const *) srcPtr, srcRowBytes >> 1, 0, width, height, dstPtr, dstRowBytes);
}
void S9xBlitPixHiResNTSC16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height)
{
snes_ntsc_blit_hires(ntsc, (SNES_NTSC_IN_T const *) srcPtr, srcRowBytes >> 1, 0, width, height, dstPtr, dstRowBytes);
}