add more 1.5x render filters, fix the EPX 1.5x filter, fix loading of frameskip=0 setting

This commit is contained in:
nitsuja 2009-12-13 11:30:52 +00:00
parent 04e3d1dafd
commit c9d1c8e467
9 changed files with 262 additions and 13 deletions

View File

@ -19,7 +19,10 @@
#include "filter.h"
#include "types.h"
#include "interp.h"
// transforms each 1 pixel into a 2x2 block of output pixels
// where each corner is selected based on equivalence of neighboring pixels
void RenderEPX (SSurface Src, SSurface Dst)
{
uint32 *lpSrc;
@ -66,7 +69,203 @@ void RenderEPX (SSurface Src, SSurface Dst)
}
}
// transforms each 2x2 block of pixels into a 3x3 block of output pixels
// where each pixel is selected based on equivalence of neighboring pixels
void RenderEPX_1Point5x (SSurface Src, SSurface Dst)
{
u32 *lpSrc;
u32 srcHeight = Src.Height;
u32 srcWidth = Src.Width;
u32 dstHeight = Dst.Height;
u32 dstWidth = Dst.Width;
const unsigned int srcPitch = Src.Pitch >> 1;
lpSrc = reinterpret_cast<u32 *>(Src.Surface);
const unsigned int dstPitch = Dst.Pitch >> 1;
u32 *lpDst = (u32*)Dst.Surface;
for(int yi=0, yo=0; yi < srcHeight; yi+=2, yo+=3)
{
u32* SrcLine = lpSrc + srcPitch*yi;
u32* DstLine1 = lpDst + dstPitch*(yo);
u32* DstLine2 = lpDst + dstPitch*(yo+1);
u32* DstLine3 = lpDst + dstPitch*(yo+2);
for(int xi=0; xi < srcWidth; xi+=2)
{
u32 s10 = *(SrcLine-srcPitch), s20 = *(SrcLine-srcPitch+1), s30 = *(SrcLine-srcPitch+2);
u32 s01 = *(SrcLine-1), s11 = *(SrcLine), s21 = *(SrcLine+1), s31 = *(SrcLine+2);
u32 s02 = *(SrcLine+srcPitch-1), s12 = *(SrcLine+srcPitch), s22 = *(SrcLine+srcPitch+1), s32 = *(SrcLine+srcPitch+2);
u32 s03 = *(SrcLine+2*srcPitch-1), s13 = *(SrcLine+2*srcPitch), s23 = *(SrcLine+2*srcPitch+1), s33 = *(SrcLine+2*srcPitch+2);
*DstLine1++ = s01==s10 && s10!=s21 && s01!=s12
? s01:s11;
*DstLine1++ = s10==s21 && s10!=s01 && s21!=s12
? s21:s11;
*DstLine1++ = (s11==s20 && s20!=s31 && s11!=s22 && s21!=s30)
|| (s20==s31 && s20!=s11 && s31!=s22 && s21!=s10) ? s20:s21;
*DstLine2++ = s01==s12 && s01!=s10 && s12!=s21
? s01:s11;
*DstLine2++ = s12==s21 && s01!=s12 && s10!=s21
? s21:s11;
*DstLine2++ = (s11==s22 && s11!=s20 && s22!=s31 && s21!=s32)
|| (s22==s31 && s11!=s22 && s20!=s31 && s21!=s12) ? s22:s21;
*DstLine3++ = (s02==s11 && s11!=s22 && s02!=s13 && s12!=s03)
|| (s02==s13 && s02!=s11 && s13!=s22 && s12!=s01) ? s02:s12;
*DstLine3++ = (s11==s22 && s11!=s02 && s22!=s13 && s12!=s23)
|| (s13==s22 && s02!=s13 && s11!=s22 && s12!=s21) ? s22:s12;
*DstLine3++ = s22;
SrcLine+=2;
}
}
}
static u32 min(u32 a, u32 b) { return (a < b) ? a : b; }
static u32 min3(u32 a, u32 b, u32 c) { return min(a,min(b,c)); }
static u32 dist(u32 a, u32 b)
{
return ABS( (a & 0x0000FF) - (b & 0x0000FF))*2
+ ABS(((a & 0x00FF00)>>8) - ((b & 0x00FF00)>>8))*3
+ ABS(((a & 0xFF0000)>>16) - ((b & 0xFF0000)>>16))*3;
}
// note: we only use mix to make the arbitrary choice between two almost-equal colors.
// this filter doesn't really do much interpolating or have the appearance of doing any.
#define mix interp_32_11
// transforms each 1 pixel into a 2x2 block of output pixels
// where each corner is selected based on relative equivalence of neighboring pixels
void RenderEPXPlus (SSurface Src, SSurface Dst)
{
uint32 *lpSrc;
const uint32 srcHeight = Src.Height;
const uint32 srcWidth = Src.Width;
const unsigned int srcPitch = Src.Pitch >> 1;
lpSrc = reinterpret_cast<uint32 *>(Src.Surface);
const unsigned int dstPitch = Dst.Pitch >> 1;
uint32 *lpDst = (uint32*)Dst.Surface;
for(int j = 0; j < srcHeight; j++)
{
uint32* SrcLine = lpSrc + srcPitch*j;
uint32* DstLine1 = lpDst + dstPitch*(j*2);
uint32* DstLine2 = lpDst + dstPitch*(j*2+1);
for(int i = 0; i < srcWidth; i++)
{
uint32 L = *(SrcLine-1);
uint32 C = *(SrcLine);
uint32 R = *(SrcLine+1);
uint32 U = *(SrcLine-srcPitch);
uint32 D = *(SrcLine+srcPitch);
*DstLine1++ = dist(L,U) < min(dist(L,D),dist(R,U)) ? mix(L,U) : C;
*DstLine1++ = dist(R,U) < min(dist(L,U),dist(R,D)) ? mix(R,U) : C;
*DstLine2++ = dist(L,D) < min(dist(L,U),dist(R,D)) ? mix(L,D) : C;
*DstLine2++ = dist(R,D) < min(dist(L,D),dist(R,U)) ? mix(R,D) : C;
SrcLine++;
}
}
}
// transforms each 2x2 block of pixels into a 3x3 block of output pixels
// where each pixel is selected based on relative equivalence of neighboring pixels
void RenderEPXPlus_1Point5x (SSurface Src, SSurface Dst)
{
u32 *lpSrc;
u32 srcHeight = Src.Height;
u32 srcWidth = Src.Width;
u32 dstHeight = Dst.Height;
u32 dstWidth = Dst.Width;
const unsigned int srcPitch = Src.Pitch >> 1;
lpSrc = reinterpret_cast<u32 *>(Src.Surface);
const unsigned int dstPitch = Dst.Pitch >> 1;
u32 *lpDst = (u32*)Dst.Surface;
for(int yi=0, yo=0; yi < srcHeight; yi+=2, yo+=3)
{
u32* SrcLine = lpSrc + srcPitch*yi;
u32* DstLine1 = lpDst + dstPitch*(yo);
u32* DstLine2 = lpDst + dstPitch*(yo+1);
u32* DstLine3 = lpDst + dstPitch*(yo+2);
for(int xi=0; xi < srcWidth; xi+=2)
{
u32 s10 = *(SrcLine-srcPitch), s20 = *(SrcLine-srcPitch+1), s30 = *(SrcLine-srcPitch+2);
u32 s01 = *(SrcLine-1), s11 = *(SrcLine), s21 = *(SrcLine+1), s31 = *(SrcLine+2);
u32 s02 = *(SrcLine+srcPitch-1), s12 = *(SrcLine+srcPitch), s22 = *(SrcLine+srcPitch+1), s32 = *(SrcLine+srcPitch+2);
u32 s03 = *(SrcLine+2*srcPitch-1), s13 = *(SrcLine+2*srcPitch), s23 = *(SrcLine+2*srcPitch+1), s33 = *(SrcLine+2*srcPitch+2);
*DstLine1++ = dist(s01,s10) < min( dist(s10,s21),dist(s01,s12))
? mix(s01,s10):s11;
*DstLine1++ = dist(s10,s21) < min( dist(s10,s01),dist(s21,s12))
? mix(s10,s21):s11;
*DstLine1++ = dist(s11,s20) < min3(dist(s20,s31),dist(s11,s22),dist(s21,s30)) ? mix(s11,s20):
dist(s20,s31) < min3(dist(s20,s11),dist(s31,s22),dist(s21,s10)) ? mix(s20,s31):s21;
*DstLine2++ = dist(s01,s12) < min( dist(s01,s10),dist(s12,s21))
? mix(s01,s12):s11;
*DstLine2++ = dist(s12,s21) < min( dist(s01,s12),dist(s10,s21))
? mix(s12,s21):s11;
*DstLine2++ = dist(s11,s22) < min3(dist(s11,s20),dist(s22,s31),dist(s21,s32)) ? mix(s11,s22):
dist(s22,s31) < min3(dist(s11,s22),dist(s20,s31),dist(s21,s12)) ? mix(s22,s31):s21;
*DstLine3++ = dist(s02,s11) < min3(dist(s11,s22),dist(s02,s13),dist(s12,s03)) ? mix(s02,s11):
dist(s02,s13) < min3(dist(s02,s11),dist(s13,s22),dist(s12,s01)) ? mix(s02,s13):s12;
*DstLine3++ = dist(s11,s22) < min3(dist(s11,s02),dist(s22,s13),dist(s12,s23)) ? mix(s11,s22):
dist(s13,s22) < min3(dist(s02,s13),dist(s11,s22),dist(s12,s21)) ? mix(s13,s22):s12;
*DstLine3++ = s22;
SrcLine+=2;
}
}
}
// transforms each 2x2 block of pixels into 3x3 output which is
// a 2x2 block that has 1 block of padding on the right and bottom sides
// which are selected stupidly from neighboring pixels in the original 2x2 block
void RenderNearest_1Point5x (SSurface Src, SSurface Dst)
{
uint32 *lpSrc;
uint32 srcHeight = Src.Height;
uint32 srcWidth = Src.Width;
uint32 dstHeight = Dst.Height;
uint32 dstWidth = Dst.Width;
const unsigned int srcPitch = Src.Pitch >> 1;
lpSrc = reinterpret_cast<uint32 *>(Src.Surface);
const unsigned int dstPitch = Dst.Pitch >> 1;
uint32 *lpDst = (uint32*)Dst.Surface;
for(int yi = 0, yo = 0; yi < srcHeight; yi+=2, yo+=3)
{
u32* srcPix1 = lpSrc + srcPitch*(yi);
u32* srcPix2 = lpSrc + srcPitch*(yi+1);
u32* dstPix1 = lpDst + dstPitch*(yo);
u32* dstPix2 = lpDst + dstPitch*(yo+1);
u32* dstPix3 = lpDst + dstPitch*(yo+2);
for(int xi = 0; xi < srcWidth; xi+=2)
{
*dstPix1++ = *srcPix1++;
*dstPix1++ = *srcPix1;
*dstPix1++ = *srcPix1++;
*dstPix2++ = *srcPix2;
*dstPix3++ = *srcPix2++;
*dstPix2++ = *srcPix2;
*dstPix3++ = *srcPix2;
*dstPix2++ = *srcPix2;
*dstPix3++ = *srcPix2++;
}
}
}
// transforms each 2x2 block of pixels into 3x3 output which is
// a 2x2 block that has 1 block of padding on the right and bottom sides
// which are selected from neighboring pixels depending on matching diagonals
void RenderNearestPlus_1Point5x (SSurface Src, SSurface Dst)
{
uint32 *lpSrc;
@ -108,4 +307,3 @@ void RenderEPX_1Point5x (SSurface Src, SSurface Dst)
#undef BETTER
}
}

View File

@ -35,5 +35,8 @@ void RenderSuperEagle (SSurface Src, SSurface Dst);
void RenderScanline( SSurface Src, SSurface Dst);
void RenderBilinear( SSurface Src, SSurface Dst);
void RenderEPX( SSurface Src, SSurface Dst);
void RenderEPXPlus( SSurface Src, SSurface Dst);
void RenderEPX_1Point5x( SSurface Src, SSurface Dst);
void RenderEPXPlus_1Point5x( SSurface Src, SSurface Dst);
void RenderNearest_1Point5x( SSurface Src, SSurface Dst);
void RenderNearestPlus_1Point5x( SSurface Src, SSurface Dst);

View File

@ -329,8 +329,6 @@ static void hq2xS_16_def(u16* dst0, u16* dst1, const u16* src0, const u16* src1,
int diffBright = ((maxBright - minBright) * 7) >> 4;
if(diffBright > 7)
{
#define ABS(x) ((x) < 0 ? -(x) : (x))
const int centerBright = brightArray[4];
if(ABS(brightArray[0] - centerBright) > diffBright)
mask |= 1 << 0;
@ -461,8 +459,6 @@ static void hq2xS_32_def(u32* dst0, u32* dst1, const u32* src0, const u32* src1,
int diffBright = ((maxBright - minBright) * 7) >> 4;
if(diffBright > 7)
{
#define ABS(x) ((x) < 0 ? -(x) : (x))
const int centerBright = brightArray[4];
if(ABS(brightArray[0] - centerBright) > diffBright)
mask |= 1 << 0;

View File

@ -277,7 +277,8 @@ static int interp_32_diff(u32 p1, u32 p2)
#define INTERP_LIMIT2 (96000)
#define ABS(x) ((x) < 0 ? -(x) : (x))
//#define ABS(x) ((x) < 0 ? -(x) : (x))
static __forceinline unsigned int ABS(int x) { return (x+(x>>31))^(x>>31); } // faster
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) < (y) ? (x) : (y))

View File

@ -193,8 +193,6 @@ static void lq2xS_16_def(u16* dst0, u16* dst1, const u16* src0, const u16* src1,
int diffBright = ((maxBright - minBright) * 7) >> 4;
if(diffBright > 7)
{
#define ABS(x) ((x) < 0 ? -(x) : (x))
const int centerBright = brightArray[4];
if(ABS(brightArray[0] - centerBright) > diffBright)
mask |= 1 << 0;
@ -434,8 +432,6 @@ static void lq2xS_32_def(u32* dst0, u32* dst1, const u32* src0, const u32* src1,
int diffBright = ((maxBright - minBright) * 7) >> 4;
if(diffBright > 7)
{
#define ABS(x) ((x) < 0 ? -(x) : (x))
const int centerBright = brightArray[4];
if(ABS(brightArray[0] - centerBright) > diffBright)
mask |= 1 << 0;

View File

@ -2442,7 +2442,7 @@ int _main()
frameskiprate=9;
else
frameskiprate=atoi(text+4);
if(frameskiprate < 1)
if(frameskiprate < 0)
frameskiprate = 9;
}
else
@ -3689,7 +3689,11 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
MainWindow->checkMenu(IDM_RENDER_BILINEAR, video.currentfilter == video.BILINEAR );
MainWindow->checkMenu(IDM_RENDER_NEAREST2X, video.currentfilter == video.NEAREST2X );
MainWindow->checkMenu(IDM_RENDER_EPX, video.currentfilter == video.EPX );
MainWindow->checkMenu(IDM_RENDER_EPXPLUS, video.currentfilter == video.EPXPLUS );
MainWindow->checkMenu(IDM_RENDER_EPX1POINT5, video.currentfilter == video.EPX1POINT5 );
MainWindow->checkMenu(IDM_RENDER_EPXPLUS1POINT5, video.currentfilter == video.EPXPLUS1POINT5 );
MainWindow->checkMenu(IDM_RENDER_NEAREST1POINT5, video.currentfilter == video.NEAREST1POINT5 );
MainWindow->checkMenu(IDM_RENDER_NEARESTPLUS1POINT5, video.currentfilter == video.NEARESTPLUS1POINT5 );
MainWindow->checkMenu(IDC_STATEREWINDING, staterewindingenabled == 1 );
@ -4333,6 +4337,13 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
FilterUpdate(hwnd);
}
break;
case IDM_RENDER_EPXPLUS:
{
Lock lock (win_backbuffer_sync);
video.setfilter(video.EPXPLUS);
FilterUpdate(hwnd);
}
break;
case IDM_RENDER_EPX1POINT5:
{
Lock lock (win_backbuffer_sync);
@ -4340,6 +4351,27 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
FilterUpdate(hwnd);
}
break;
case IDM_RENDER_EPXPLUS1POINT5:
{
Lock lock (win_backbuffer_sync);
video.setfilter(video.EPXPLUS1POINT5);
FilterUpdate(hwnd);
}
break;
case IDM_RENDER_NEAREST1POINT5:
{
Lock lock (win_backbuffer_sync);
video.setfilter(video.NEAREST1POINT5);
FilterUpdate(hwnd);
}
break;
case IDM_RENDER_NEARESTPLUS1POINT5:
{
Lock lock (win_backbuffer_sync);
video.setfilter(video.NEARESTPLUS1POINT5);
FilterUpdate(hwnd);
}
break;
case IDM_STATE_LOAD:
{

View File

@ -176,7 +176,11 @@
#define IDM_RENDER_BILINEAR 557
#define IDM_RENDER_NEAREST2X 558
#define IDM_RENDER_EPX 559
#define IDM_RENDER_EPX1POINT5 560
#define IDM_RENDER_EPXPLUS 560
#define IDM_RENDER_EPX1POINT5 561
#define IDM_RENDER_EPXPLUS1POINT5 562
#define IDM_RENDER_NEAREST1POINT5 563
#define IDM_RENDER_NEARESTPLUS1POINT5 564
#define IDD_IO_REG 601
#define IDM_RECORD_MOVIE 602
#define IDM_PLAY_MOVIE 603

Binary file not shown.

View File

@ -33,7 +33,11 @@ public:
LQ2X,
LQ2XS,
EPX,
NEARESTPLUS1POINT5,
NEAREST1POINT5,
EPXPLUS,
EPX1POINT5,
EPXPLUS1POINT5,
NUM_FILTERS,
};
@ -58,6 +62,9 @@ public:
height = 384;
break;
case EPX1POINT5:
case EPXPLUS1POINT5:
case NEAREST1POINT5:
case NEARESTPLUS1POINT5:
width = 256*3/2;
height = 384*3/2;
break;
@ -127,9 +134,21 @@ public:
case EPX:
RenderEPX(src,dst);
break;
case EPXPLUS:
RenderEPXPlus(src,dst);
break;
case EPX1POINT5:
RenderEPX_1Point5x(src,dst);
break;
case EPXPLUS1POINT5:
RenderEPXPlus_1Point5x(src,dst);
break;
case NEAREST1POINT5:
RenderNearest_1Point5x(src,dst);
break;
case NEARESTPLUS1POINT5:
RenderNearestPlus_1Point5x(src,dst);
break;
}
}