From c9d1c8e467d6b4ff81c8eb97138dd6a89970773a Mon Sep 17 00:00:00 2001 From: nitsuja Date: Sun, 13 Dec 2009 11:30:52 +0000 Subject: [PATCH] add more 1.5x render filters, fix the EPX 1.5x filter, fix loading of frameskip=0 setting --- desmume/src/windows/filter/epx.cpp | 200 +++++++++++++++++++++++++++- desmume/src/windows/filter/filter.h | 5 +- desmume/src/windows/filter/hq2x.cpp | 4 - desmume/src/windows/filter/interp.h | 3 +- desmume/src/windows/filter/lq2x.cpp | 4 - desmume/src/windows/main.cpp | 34 ++++- desmume/src/windows/resource.h | 6 +- desmume/src/windows/resources.rc | Bin 888854 -> 892086 bytes desmume/src/windows/video.h | 19 +++ 9 files changed, 262 insertions(+), 13 deletions(-) diff --git a/desmume/src/windows/filter/epx.cpp b/desmume/src/windows/filter/epx.cpp index 55d7dcb01..f88f5c480 100644 --- a/desmume/src/windows/filter/epx.cpp +++ b/desmume/src/windows/filter/epx.cpp @@ -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(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(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(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(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 } } - diff --git a/desmume/src/windows/filter/filter.h b/desmume/src/windows/filter/filter.h index 4de9664bd..e31ec099b 100644 --- a/desmume/src/windows/filter/filter.h +++ b/desmume/src/windows/filter/filter.h @@ -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); diff --git a/desmume/src/windows/filter/hq2x.cpp b/desmume/src/windows/filter/hq2x.cpp index 2c8f94300..a0559d18b 100644 --- a/desmume/src/windows/filter/hq2x.cpp +++ b/desmume/src/windows/filter/hq2x.cpp @@ -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; diff --git a/desmume/src/windows/filter/interp.h b/desmume/src/windows/filter/interp.h index 9d74baa99..0df62b8e5 100644 --- a/desmume/src/windows/filter/interp.h +++ b/desmume/src/windows/filter/interp.h @@ -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)) diff --git a/desmume/src/windows/filter/lq2x.cpp b/desmume/src/windows/filter/lq2x.cpp index f1bdfd918..086d3cac1 100644 --- a/desmume/src/windows/filter/lq2x.cpp +++ b/desmume/src/windows/filter/lq2x.cpp @@ -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; diff --git a/desmume/src/windows/main.cpp b/desmume/src/windows/main.cpp index 81163b09b..a9790de2d 100644 --- a/desmume/src/windows/main.cpp +++ b/desmume/src/windows/main.cpp @@ -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: { diff --git a/desmume/src/windows/resource.h b/desmume/src/windows/resource.h index ae84ee9ac..fd7e78e1d 100644 --- a/desmume/src/windows/resource.h +++ b/desmume/src/windows/resource.h @@ -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 diff --git a/desmume/src/windows/resources.rc b/desmume/src/windows/resources.rc index eab78d2251707df27eba4a4df5d3d29800a88355..9d5932fa34c2cfbb75ef53b0922b8f19531c6e74 100644 GIT binary patch delta 1076 zcmbQXz--%2vxXMNElfIyG4u8lnJfWIkljz354Qt-xQcoD17}`==`60iUTEF| zN$^4Jr=gG9fx!dBY}WTDG57WZ%{+3uhl97aFLC89@&W*qlse=9 delta 465 zcmdnC(`?!TvxXMNElfvfpGmT9e_>@fLXj07agk