diff --git a/QtCore4.dll b/QtCore4.dll deleted file mode 100644 index 1cbd0974..00000000 Binary files a/QtCore4.dll and /dev/null differ diff --git a/QtGui4.dll b/QtGui4.dll deleted file mode 100644 index dd3d7c13..00000000 Binary files a/QtGui4.dll and /dev/null differ diff --git a/bsnes.exe b/bsnes.exe deleted file mode 100644 index e751b740..00000000 Binary files a/bsnes.exe and /dev/null differ diff --git a/bsnesd.exe b/bsnesd.exe deleted file mode 100644 index 64793c4c..00000000 Binary files a/bsnesd.exe and /dev/null differ diff --git a/libgomp-1.dll b/libgomp-1.dll deleted file mode 100644 index 3bb99f0f..00000000 Binary files a/libgomp-1.dll and /dev/null differ diff --git a/mingwm10.dll b/mingwm10.dll deleted file mode 100644 index 83923d7f..00000000 Binary files a/mingwm10.dll and /dev/null differ diff --git a/pixelshaders/Curvature/fragment b/pixelshaders/Curvature/fragment new file mode 100644 index 00000000..5c311da9 --- /dev/null +++ b/pixelshaders/Curvature/fragment @@ -0,0 +1,17 @@ +//CRT curvature shader +//license: GPL +//author: DOLLS + +uniform sampler2D rubyTexture; + +#define distortion 0.2 + +vec2 barrelDistortion(vec2 coord) { + vec2 cc = coord - 0.5; + float dist = dot(cc, cc); + return coord + cc * (dist + distortion * dist * dist) * distortion; +} + +void main(void) { + gl_FragColor = texture2D(rubyTexture, barrelDistortion(gl_TexCoord[0].xy)); +} diff --git a/pixelshaders/HDRTV/fragment b/pixelshaders/HDRTV/fragment new file mode 100644 index 00000000..16098b90 --- /dev/null +++ b/pixelshaders/HDRTV/fragment @@ -0,0 +1,14 @@ +//HDRTV GLSL shader +//license: GPL +//original version by SimoneT +//ruby port by byuu + +uniform sampler2D rubyTexture; + +void main(void) { + vec4 rgb = texture2D(rubyTexture, gl_TexCoord[0].xy); + vec4 intens = smoothstep(0.2,0.8,rgb) + normalize(vec4(rgb.xyz, 1.0)); + + if(fract(gl_FragCoord.y * 0.5) > 0.5) intens = rgb * 0.8; + gl_FragColor = intens; +} diff --git a/pixelshaders/HDRTV/vertex b/pixelshaders/HDRTV/vertex new file mode 100644 index 00000000..70591d55 --- /dev/null +++ b/pixelshaders/HDRTV/vertex @@ -0,0 +1,9 @@ +//HDRTV GLSL shader +//license: GPL +//original version by SimoneT +//ruby port by byuu + +void main(void) { + gl_Position = ftransform(); + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/pixelshaders/HLSL/sepia.fx b/pixelshaders/HLSL/sepia.fx new file mode 100644 index 00000000..a9295d06 --- /dev/null +++ b/pixelshaders/HLSL/sepia.fx @@ -0,0 +1,25 @@ +texture rubyTexture; + +float4 vec; + +sampler s0 = sampler_state { texture = ; }; +float3 LightColor = { 1.0, 0.7, 0.5 }; +float3 DarkColor = { 0.2, 0.05, 0.0 }; + +float4 DiffColorPass(in float2 Tex : TEXCOORD0) : COLOR0 +{ + vec.x = 0.5; + vec.y = 1.0; + float3 scnColor = LightColor * tex2D(s0, Tex).xyz; + float3 grayXfer = float3(0.3, 0.59, 0.11); + float gray = dot(grayXfer, scnColor); + float3 muted = lerp(scnColor, gray.xxx, vec.x); + float3 sepia = lerp(DarkColor, LightColor, gray); + float3 result = lerp(muted, sepia, vec.y); + return float4(result, 1); +} + +Technique T0 +{ + pass p0 { PixelShader = compile ps_2_0 DiffColorPass(); } +} diff --git a/pixelshaders/HQ2x/fragment b/pixelshaders/HQ2x/fragment new file mode 100644 index 00000000..0bf24db3 --- /dev/null +++ b/pixelshaders/HQ2x/fragment @@ -0,0 +1,49 @@ +//HQ2x GLSL shader +//license: GPL +//original version by guest(r) +//ruby port by byuu + +uniform sampler2D rubyTexture; + +const float mx = 0.325; // start smoothing wt. +const float k = -0.250; // wt. decrease factor +const float max_w = 0.25; // max filter weigth +const float min_w =-0.05; // min filter weigth +const float lum_add = 0.25; // effects smoothing + +void main() { + vec3 c00 = texture2D(rubyTexture, gl_TexCoord[1].xy).xyz; + vec3 c10 = texture2D(rubyTexture, gl_TexCoord[1].zw).xyz; + vec3 c20 = texture2D(rubyTexture, gl_TexCoord[2].xy).xyz; + vec3 c01 = texture2D(rubyTexture, gl_TexCoord[4].zw).xyz; + vec3 c11 = texture2D(rubyTexture, gl_TexCoord[0].xy).xyz; + vec3 c21 = texture2D(rubyTexture, gl_TexCoord[2].zw).xyz; + vec3 c02 = texture2D(rubyTexture, gl_TexCoord[4].xy).xyz; + vec3 c12 = texture2D(rubyTexture, gl_TexCoord[3].zw).xyz; + vec3 c22 = texture2D(rubyTexture, gl_TexCoord[3].xy).xyz; + vec3 dt = vec3(1.0, 1.0, 1.0); + + float md1 = dot(abs(c00 - c22), dt); + float md2 = dot(abs(c02 - c20), dt); + + float w1 = dot(abs(c22 - c11), dt) * md2; + float w2 = dot(abs(c02 - c11), dt) * md1; + float w3 = dot(abs(c00 - c11), dt) * md2; + float w4 = dot(abs(c20 - c11), dt) * md1; + + float t1 = w1 + w3; + float t2 = w2 + w4; + float ww = max(t1, t2) + 0.0001; + + c11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww); + + float lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add); + float lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add); + + w1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w); + w2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w); + w3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w); + w4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w); + + gl_FragColor.xyz = w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11; +} diff --git a/pixelshaders/HQ2x/vertex b/pixelshaders/HQ2x/vertex new file mode 100644 index 00000000..488a870e --- /dev/null +++ b/pixelshaders/HQ2x/vertex @@ -0,0 +1,26 @@ +//HQ2x GLSL shader +//license: GPL +//original version by guest(r) +//ruby port by byuu + +uniform vec2 rubyTextureSize; + +void main() { + float x = 0.5 * (1.0 / rubyTextureSize.x); + float y = 0.5 * (1.0 / rubyTextureSize.y); + vec2 dg1 = vec2( x, y); + vec2 dg2 = vec2(-x, y); + vec2 dx = vec2(x, 0.0); + vec2 dy = vec2(0.0, y); + + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_TexCoord[1].xy = gl_TexCoord[0].xy - dg1; + gl_TexCoord[1].zw = gl_TexCoord[0].xy - dy; + gl_TexCoord[2].xy = gl_TexCoord[0].xy - dg2; + gl_TexCoord[2].zw = gl_TexCoord[0].xy + dx; + gl_TexCoord[3].xy = gl_TexCoord[0].xy + dg1; + gl_TexCoord[3].zw = gl_TexCoord[0].xy + dy; + gl_TexCoord[4].xy = gl_TexCoord[0].xy + dg2; + gl_TexCoord[4].zw = gl_TexCoord[0].xy - dx; +} diff --git a/pixelshaders/Pixellate/fragment b/pixelshaders/Pixellate/fragment new file mode 100644 index 00000000..ff94deea --- /dev/null +++ b/pixelshaders/Pixellate/fragment @@ -0,0 +1,36 @@ +//Pixellate shader +//license: GPL +//author: Fes + +uniform sampler2D rubyTexture; +uniform vec2 rubyTextureSize; + +void main() { + vec2 texelSize = 1.0 / rubyTextureSize; + + vec2 range; + range.x = dFdx(gl_TexCoord[0].x) / 2.0 * 0.99; + range.y = dFdy(gl_TexCoord[0].y) / 2.0 * 0.99; + + float left = gl_TexCoord[0].x - range.x; + float top = gl_TexCoord[0].y + range.y; + float right = gl_TexCoord[0].x + range.x; + float bottom = gl_TexCoord[0].y - range.y; + + vec4 topLeftColor = texture2D(rubyTexture, (floor(vec2(left, top) / texelSize) + 0.5) * texelSize); + vec4 bottomRightColor = texture2D(rubyTexture, (floor(vec2(right, bottom) / texelSize) + 0.5) * texelSize); + vec4 bottomLeftColor = texture2D(rubyTexture, (floor(vec2(left, bottom) / texelSize) + 0.5) * texelSize); + vec4 topRightColor = texture2D(rubyTexture, (floor(vec2(right, top) / texelSize) + 0.5) * texelSize); + + vec2 border = clamp(round(gl_TexCoord[0] / texelSize) * texelSize, vec2(left, bottom), vec2(right, top)); + + float totalArea = 4.0 * range.x * range.y; + + vec4 averageColor; + averageColor = ((border.x - left) * (top - border.y) / totalArea) * topLeftColor; + averageColor += ((right - border.x) * (border.y - bottom) / totalArea) * bottomRightColor; + averageColor += ((border.x - left) * (border.y - bottom) / totalArea) * bottomLeftColor; + averageColor += ((right - border.x) * (top - border.y) / totalArea) * topRightColor; + + gl_FragColor = averageColor; +} diff --git a/pixelshaders/Pixellate/vertex b/pixelshaders/Pixellate/vertex new file mode 100644 index 00000000..898112ee --- /dev/null +++ b/pixelshaders/Pixellate/vertex @@ -0,0 +1,8 @@ +//Pixellate shader +//license: GPL +//author: Fes + +void main() { + gl_Position = ftransform(); + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/pixelshaders/Scale2x/fragment b/pixelshaders/Scale2x/fragment new file mode 100644 index 00000000..c72625ae --- /dev/null +++ b/pixelshaders/Scale2x/fragment @@ -0,0 +1,28 @@ +//Scale2x GLSL shader +//license: GPL +//original version by Pete Bernert +//ruby port by byuu + uniform sampler2D rubyTexture; +uniform vec2 rubyTextureSize; + +void main() { + vec4 colD, colF, colB, colH, col, tmp; + vec2 sel; + + col = texture2DProj(rubyTexture, gl_TexCoord[0]); //central (can be E0-E3) + colD = texture2DProj(rubyTexture, gl_TexCoord[1]); //D (left) + colF = texture2DProj(rubyTexture, gl_TexCoord[2]); //F (right) + colB = texture2DProj(rubyTexture, gl_TexCoord[3]); //B (top) + colH = texture2DProj(rubyTexture, gl_TexCoord[4]); //H (bottom) + + sel = fract(gl_TexCoord[0].xy * rubyTextureSize.xy); //where are we (E0-E3)? + //E0 is default + if(sel.y >= 0.5) { tmp = colB; colB = colH; colH = tmp; } //E1 (or E3): swap B and H + if(sel.x >= 0.5) { tmp = colF; colF = colD; colD = tmp; } //E2 (or E3): swap D and F + + if(colB == colD && colB != colF && colD != colH) { //do the Scale2x rule + col = colD; + } + + gl_FragColor = col; +} diff --git a/pixelshaders/Scale2x/vertex b/pixelshaders/Scale2x/vertex new file mode 100644 index 00000000..6e172cd1 --- /dev/null +++ b/pixelshaders/Scale2x/vertex @@ -0,0 +1,28 @@ +//Scale2x GLSL shader +//license: GPL +//original version by Pete Bernert +//ruby port by byuu + +uniform vec2 rubyTextureSize; + +void main() { + vec4 offsetx; + vec4 offsety; + + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + offsetx.x = 1.0 / rubyTextureSize.x; + offsetx.y = 0.0; + offsetx.w = 0.0; + offsetx.z = 0.0; + offsety.y = 1.0 / rubyTextureSize.y; + offsety.x = 0.0; + offsety.w = 0.0; + offsety.z = 0.0; + + gl_TexCoord[0] = gl_MultiTexCoord0; //center + gl_TexCoord[1] = gl_TexCoord[0] - offsetx; //left + gl_TexCoord[2] = gl_TexCoord[0] + offsetx; //right + gl_TexCoord[3] = gl_TexCoord[0] - offsety; //top + gl_TexCoord[4] = gl_TexCoord[0] + offsety; //bottom +} diff --git a/pthreadGC2.dll b/pthreadGC2.dll deleted file mode 100644 index bfdf4fd9..00000000 Binary files a/pthreadGC2.dll and /dev/null differ diff --git a/snesfilter.dll b/snesfilter.dll deleted file mode 100644 index e978c82e..00000000 Binary files a/snesfilter.dll and /dev/null differ diff --git a/snesfilter/nall/platform.hpp b/snesfilter/nall/platform.hpp index 5d2bd6ab..68ed37ce 100644 --- a/snesfilter/nall/platform.hpp +++ b/snesfilter/nall/platform.hpp @@ -1,6 +1,8 @@ #ifndef NALL_PLATFORM_HPP #define NALL_PLATFORM_HPP +#include + //========================= //standard platform headers //========================= @@ -50,7 +52,7 @@ #define getcwd _getcwd #define ftruncate _chsize #define putenv _putenv - #define mkdir(n, m) mkdir(n) + #define mkdir(n, m) _wmkdir(nall::utf16_t(n)) #define rmdir _rmdir #define vsnprintf _vsnprintf #define usleep(n) Sleep(n / 1000) diff --git a/snesfilter/nall/qt/Makefile b/snesfilter/nall/qt/Makefile index 6e148e42..69e84960 100644 --- a/snesfilter/nall/qt/Makefile +++ b/snesfilter/nall/qt/Makefile @@ -21,7 +21,7 @@ ifeq ($(platform),x) qtinc := `pkg-config --cflags $(qtlibs)` qtlib := `pkg-config --libs $(qtlibs)` else ifeq ($(platform),osx) - qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers + qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers) qtlib := -L/Library/Frameworks qtlib += $(foreach lib,$(qtlibs),-framework $(lib)) diff --git a/snesfilter/nall/qt/file-dialog.moc.hpp b/snesfilter/nall/qt/file-dialog.moc.hpp index ff833fcf..bcccfaf5 100644 --- a/snesfilter/nall/qt/file-dialog.moc.hpp +++ b/snesfilter/nall/qt/file-dialog.moc.hpp @@ -342,6 +342,7 @@ inline FileDialog::FileDialog() { fileSystemModel->setNameFilterDisables(false); fileView = new FileView; + fileView->setMinimumWidth(320); fileView->setModel(fileSystemModel); fileView->setIconSize(QSize(16, 16)); browseLayout->addWidget(fileView); diff --git a/snesreader.dll b/snesreader.dll deleted file mode 100644 index 76ce5af3..00000000 Binary files a/snesreader.dll and /dev/null differ diff --git a/snesreader/nall/platform.hpp b/snesreader/nall/platform.hpp index 5d2bd6ab..68ed37ce 100644 --- a/snesreader/nall/platform.hpp +++ b/snesreader/nall/platform.hpp @@ -1,6 +1,8 @@ #ifndef NALL_PLATFORM_HPP #define NALL_PLATFORM_HPP +#include + //========================= //standard platform headers //========================= @@ -50,7 +52,7 @@ #define getcwd _getcwd #define ftruncate _chsize #define putenv _putenv - #define mkdir(n, m) mkdir(n) + #define mkdir(n, m) _wmkdir(nall::utf16_t(n)) #define rmdir _rmdir #define vsnprintf _vsnprintf #define usleep(n) Sleep(n / 1000) diff --git a/snesreader/nall/qt/Makefile b/snesreader/nall/qt/Makefile index 6e148e42..69e84960 100644 --- a/snesreader/nall/qt/Makefile +++ b/snesreader/nall/qt/Makefile @@ -21,7 +21,7 @@ ifeq ($(platform),x) qtinc := `pkg-config --cflags $(qtlibs)` qtlib := `pkg-config --libs $(qtlibs)` else ifeq ($(platform),osx) - qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers + qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers) qtlib := -L/Library/Frameworks qtlib += $(foreach lib,$(qtlibs),-framework $(lib)) diff --git a/snesreader/nall/qt/file-dialog.moc.hpp b/snesreader/nall/qt/file-dialog.moc.hpp index ff833fcf..bcccfaf5 100644 --- a/snesreader/nall/qt/file-dialog.moc.hpp +++ b/snesreader/nall/qt/file-dialog.moc.hpp @@ -342,6 +342,7 @@ inline FileDialog::FileDialog() { fileSystemModel->setNameFilterDisables(false); fileView = new FileView; + fileView->setMinimumWidth(320); fileView->setModel(fileSystemModel); fileView->setIconSize(QSize(16, 16)); browseLayout->addWidget(fileView); diff --git a/src/base.hpp b/src/base.hpp index 17c90983..6e841e23 100644 --- a/src/base.hpp +++ b/src/base.hpp @@ -1,4 +1,4 @@ -static const char bsnesVersion[] = "059.06"; +static const char bsnesVersion[] = "060"; static const char bsnesTitle[] = "bsnes"; static const unsigned bsnesSerializerVersion = 4; diff --git a/src/chip/msu/msu.cpp b/src/chip/msu/msu.cpp index ede3fbbb..02fe3390 100644 --- a/src/chip/msu/msu.cpp +++ b/src/chip/msu/msu.cpp @@ -48,7 +48,7 @@ void MSU::enable() { audio.coprocessor_enable(true); audio.coprocessor_frequency(44100.0); - for(unsigned i = 0x2200; i <= 0x2207; i++) { + for(unsigned i = 0x2000; i <= 0x2007; i++) { memory::mmio.map(i, *this); } @@ -74,7 +74,7 @@ void MSU::reset() { uint8 MSU::mmio_read(unsigned addr) { addr &= 0xffff; - if(addr == 0x2200) { + if(addr == 0x2000) { return (mmio.data_busy << 7) | (mmio.audio_busy << 6) | (mmio.audio_repeat << 5) @@ -82,19 +82,19 @@ uint8 MSU::mmio_read(unsigned addr) { | (Revision << 0); } - if(addr == 0x2201) { + if(addr == 0x2001) { if(mmio.data_busy) return 0x00; mmio.data_offset++; if(datafile.open()) return datafile.read(); return 0x00; } - if(addr == 0x2202) return 'S'; - if(addr == 0x2203) return '-'; - if(addr == 0x2204) return 'M'; - if(addr == 0x2205) return 'S'; - if(addr == 0x2206) return 'U'; - if(addr == 0x2207) return '0' + Revision; + if(addr == 0x2002) return 'S'; + if(addr == 0x2003) return '-'; + if(addr == 0x2004) return 'M'; + if(addr == 0x2005) return 'S'; + if(addr == 0x2006) return 'U'; + if(addr == 0x2007) return '0' + Revision; return 0x00; } @@ -102,29 +102,29 @@ uint8 MSU::mmio_read(unsigned addr) { void MSU::mmio_write(unsigned addr, uint8 data) { addr &= 0xffff; - if(addr == 0x2200) { + if(addr == 0x2000) { mmio.data_offset = (mmio.data_offset & 0xffffff00) | (data << 0); } - if(addr == 0x2201) { + if(addr == 0x2001) { mmio.data_offset = (mmio.data_offset & 0xffff00ff) | (data << 8); } - if(addr == 0x2202) { + if(addr == 0x2002) { mmio.data_offset = (mmio.data_offset & 0xff00ffff) | (data << 16); } - if(addr == 0x2203) { + if(addr == 0x2003) { mmio.data_offset = (mmio.data_offset & 0x00ffffff) | (data << 24); if(datafile.open()) datafile.seek(mmio.data_offset); mmio.data_busy = false; } - if(addr == 0x2204) { + if(addr == 0x2004) { mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0); } - if(addr == 0x2205) { + if(addr == 0x2005) { mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8); if(audiofile.open()) audiofile.close(); char track[16]; @@ -137,11 +137,11 @@ void MSU::mmio_write(unsigned addr, uint8 data) { mmio.audio_play = false; } - if(addr == 0x2206) { + if(addr == 0x2006) { mmio.audio_volume = data; } - if(addr == 0x2207) { + if(addr == 0x2007) { mmio.audio_repeat = data & 2; mmio.audio_play = data & 1; } diff --git a/src/lib/nall/qt/Makefile b/src/lib/nall/qt/Makefile index 6e148e42..69e84960 100644 --- a/src/lib/nall/qt/Makefile +++ b/src/lib/nall/qt/Makefile @@ -21,7 +21,7 @@ ifeq ($(platform),x) qtinc := `pkg-config --cflags $(qtlibs)` qtlib := `pkg-config --libs $(qtlibs)` else ifeq ($(platform),osx) - qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers + qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers) qtlib := -L/Library/Frameworks qtlib += $(foreach lib,$(qtlibs),-framework $(lib)) diff --git a/src/lib/nall/qt/file-dialog.moc.hpp b/src/lib/nall/qt/file-dialog.moc.hpp index ff833fcf..bcccfaf5 100644 --- a/src/lib/nall/qt/file-dialog.moc.hpp +++ b/src/lib/nall/qt/file-dialog.moc.hpp @@ -342,6 +342,7 @@ inline FileDialog::FileDialog() { fileSystemModel->setNameFilterDisables(false); fileView = new FileView; + fileView->setMinimumWidth(320); fileView->setModel(fileSystemModel); fileView->setIconSize(QSize(16, 16)); browseLayout->addWidget(fileView); diff --git a/src/lib/ruby/video/direct3d.cpp b/src/lib/ruby/video/direct3d.cpp index b138b3bb..d7ded059 100644 --- a/src/lib/ruby/video/direct3d.cpp +++ b/src/lib/ruby/video/direct3d.cpp @@ -1,10 +1,14 @@ #undef interface #define interface struct #include +#include #undef interface #define D3DVERTEX (D3DFVF_XYZRHW | D3DFVF_TEX1) +typedef HRESULT (__stdcall *EffectProc)(LPDIRECT3DDEVICE9, LPCVOID, UINT, D3DXMACRO const*, LPD3DXINCLUDE, DWORD, LPD3DXEFFECTPOOL, LPD3DXEFFECT*, LPD3DXBUFFER*); +typedef HRESULT (__stdcall *TextureProc)(LPDIRECT3DDEVICE9, LPCTSTR, LPDIRECT3DTEXTURE9*); + namespace ruby { class pVideoD3D { @@ -19,6 +23,9 @@ public: D3DCAPS9 d3dcaps; LPDIRECT3DTEXTURE9 texture; LPDIRECT3DSURFACE9 surface; + LPD3DXEFFECT effect; + string shaderSource; + bool lost; unsigned iwidth, iheight; @@ -36,7 +43,7 @@ public: struct { bool dynamic; //device supports dynamic textures - bool stretchrect; //device supports StretchRect + bool shader; //device supports pixel shaders } caps; struct { @@ -57,6 +64,7 @@ public: if(name == Video::Handle) return true; if(name == Video::Synchronize) return true; if(name == Video::Filter) return true; + if(name == Video::FragmentShader) return true; return false; } @@ -84,6 +92,11 @@ public: return true; } + if(name == Video::FragmentShader) { + set_fragment_shader(any_cast(value)); + return true; + } + return false; } @@ -118,8 +131,7 @@ public: device->SetVertexShader(NULL); device->SetFVF(D3DVERTEX); - device->CreateVertexBuffer(sizeof(d3dvertex) * 4, flags.v_usage, D3DVERTEX, - static_cast(flags.v_pool), &vertex_buffer, NULL); + device->CreateVertexBuffer(sizeof(d3dvertex) * 4, flags.v_usage, D3DVERTEX, (D3DPOOL)flags.v_pool, &vertex_buffer, NULL); iwidth = 0; iheight = 0; resize(settings.width = 256, settings.height = 256); @@ -149,15 +161,8 @@ public: return; } - if(caps.stretchrect == true) { - if(surface) surface->Release(); - device->CreateOffscreenPlainSurface(iwidth, iheight, D3DFMT_X8R8G8B8, - D3DPOOL_DEFAULT, &surface, NULL); - } else { - if(texture) texture->Release(); - device->CreateTexture(iwidth, iheight, 1, flags.t_usage, D3DFMT_X8R8G8B8, - static_cast(flags.t_pool), &texture, NULL); - } + if(texture) texture->Release(); + device->CreateTexture(iwidth, iheight, 1, flags.t_usage, D3DFMT_X8R8G8B8, (D3DPOOL)flags.t_pool, &texture, NULL); } void update_filter() { @@ -217,14 +222,12 @@ public: void clear() { if(lost && !recover()) return; - if(caps.stretchrect == false) { - texture->GetLevelDesc(0, &d3dsd); - texture->GetSurfaceLevel(0, &surface); - } + texture->GetLevelDesc(0, &d3dsd); + texture->GetSurfaceLevel(0, &surface); if(surface) { device->ColorFill(surface, 0, D3DCOLOR_XRGB(0x00, 0x00, 0x00)); - if(caps.stretchrect == false) surface->Release(); + surface->Release(); } //clear primary display and all backbuffers @@ -241,10 +244,8 @@ public: resize(settings.width = width, settings.height = height); } - if(caps.stretchrect == false) { - texture->GetLevelDesc(0, &d3dsd); - texture->GetSurfaceLevel(0, &surface); - } + texture->GetLevelDesc(0, &d3dsd); + texture->GetSurfaceLevel(0, &surface); surface->LockRect(&d3dlr, 0, flags.lock); pitch = d3dlr.Pitch; @@ -253,7 +254,7 @@ public: void unlock() { surface->UnlockRect(); - if(caps.stretchrect == false) surface->Release(); + surface->Release(); } void refresh() { @@ -267,24 +268,54 @@ public: //failure to do so causes scaling issues on some video drivers. if(state.width != rd.right || state.height != rd.bottom) { init(); + set_fragment_shader(shaderSource); return; } - device->BeginScene(); + if(caps.shader && effect) { + device->BeginScene(); + set_vertex(0, 0, settings.width, settings.height, iwidth, iheight, 0, 0, rd.right, rd.bottom); - if(caps.stretchrect == true) { - LPDIRECT3DSURFACE9 temp; - device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &temp); - device->StretchRect(surface, &rs, temp, 0, static_cast(flags.filter)); - temp->Release(); + D3DXVECTOR4 rubyTextureSize; + rubyTextureSize.x = iwidth; + rubyTextureSize.y = iheight; + rubyTextureSize.z = 1.0 / iheight; + rubyTextureSize.w = 1.0 / iwidth; + effect->SetVector("rubyTextureSize", &rubyTextureSize); + + D3DXVECTOR4 rubyInputSize; + rubyInputSize.x = settings.width; + rubyInputSize.y = settings.height; + rubyInputSize.z = 1.0 / settings.height; + rubyInputSize.w = 1.0 / settings.width; + effect->SetVector("rubyInputSize", &rubyInputSize); + + D3DXVECTOR4 rubyOutputSize; + rubyOutputSize.x = rd.right; + rubyOutputSize.y = rd.bottom; + rubyOutputSize.z = 1.0 / rd.bottom; + rubyOutputSize.w = 1.0 / rd.right; + effect->SetVector("rubyOutputSize", &rubyOutputSize); + + UINT passes; + effect->Begin(&passes, 0); + effect->SetTexture("rubyTexture", texture); + device->SetTexture(0, texture); + for(unsigned pass = 0; pass < passes; pass++) { + effect->BeginPass(pass); + device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + effect->EndPass(); + } + effect->End(); + device->EndScene(); } else { + device->BeginScene(); set_vertex(0, 0, settings.width, settings.height, iwidth, iheight, 0, 0, rd.right, rd.bottom); device->SetTexture(0, texture); device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + device->EndScene(); } - device->EndScene(); - if(settings.synchronize) { while(true) { D3DRASTER_STATUS status; @@ -296,6 +327,42 @@ public: if(device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) lost = true; } + void set_fragment_shader(const char *source) { + if(!caps.shader) return; + + if(effect) { + effect->Release(); + effect = NULL; + } + + if(!source || !*source) { + shaderSource = ""; + return; + } + + shaderSource = source; + + HMODULE d3dx; + for(unsigned i = 0; i < 256; i++) { + char t[256]; + sprintf(t, "d3dx9_%u.dll", i); + d3dx = LoadLibrary(t); + if(d3dx) break; + } + if(!d3dx) d3dx = LoadLibrary("d3dx9.dll"); + if(!d3dx) return; + + EffectProc effectProc = (EffectProc)GetProcAddress(d3dx, "D3DXCreateEffect"); + TextureProc textureProc = (TextureProc)GetProcAddress(d3dx, "D3DXCreateTextureFromFileA"); + + LPD3DXBUFFER pBufferErrors = NULL; + effectProc(device, shaderSource, lstrlen(source), NULL, NULL, NULL, NULL, &effect, &pBufferErrors); + + D3DXHANDLE hTech; + effect->FindNextValidTechnique(NULL, &hTech); + effect->SetTechnique(hTech); + } + bool init() { term(); @@ -330,11 +397,7 @@ public: device->GetDeviceCaps(&d3dcaps); caps.dynamic = bool(d3dcaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES); - caps.stretchrect = (d3dcaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) && - (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT) && - (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT) && - (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) && - (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR); + caps.shader = d3dcaps.PixelShaderVersion > D3DPS_VERSION(1, 4); if(caps.dynamic == true) { flags.t_usage = D3DUSAGE_DYNAMIC; @@ -356,6 +419,7 @@ public: } void release_resources() { + if(effect) { effect->Release(); effect = 0; } if(vertex_buffer) { vertex_buffer->Release(); vertex_buffer = 0; } if(surface) { surface->Release(); surface = 0; } if(texture) { texture->Release(); texture = 0; } @@ -368,6 +432,7 @@ public: } pVideoD3D() { + effect = 0; vertex_buffer = 0; surface = 0; texture = 0; diff --git a/src/ui_qt/application/application.cpp b/src/ui_qt/application/application.cpp index a10c3910..0cef3ad2 100644 --- a/src/ui_qt/application/application.cpp +++ b/src/ui_qt/application/application.cpp @@ -1,8 +1,19 @@ #include "application.moc" +VideoDisplay display; Application application; #include "init.cpp" +VideoDisplay::VideoDisplay() { + outputWidth = 0; + outputHeight = 0; + + cropLeft = 0; + cropTop = 0; + cropRight = 0; + cropBottom = 0; +} + void Application::initPaths(const char *basename) { char temp[PATH_MAX]; diff --git a/src/ui_qt/application/application.moc.hpp b/src/ui_qt/application/application.moc.hpp index 627b4aab..aeae287a 100644 --- a/src/ui_qt/application/application.moc.hpp +++ b/src/ui_qt/application/application.moc.hpp @@ -1,3 +1,15 @@ +struct VideoDisplay { + unsigned outputWidth; + unsigned outputHeight; + + unsigned cropLeft; + unsigned cropTop; + unsigned cropRight; + unsigned cropBottom; + + VideoDisplay(); +}; + class Application : public QObject { Q_OBJECT @@ -41,4 +53,5 @@ public slots: void run(); }; +extern VideoDisplay display; extern Application application; diff --git a/src/ui_qt/application/init.cpp b/src/ui_qt/application/init.cpp index a5922ab8..3cb77c87 100644 --- a/src/ui_qt/application/init.cpp +++ b/src/ui_qt/application/init.cpp @@ -93,8 +93,8 @@ void Application::init() { config().system.crashedOnLastRun = false; config().save(configFilename); - //no sense showing unusable options ... - pixelShaderWindow->setVisible(video.cap(Video::FragmentShader) || video.cap(Video::VertexShader)); + //hide pixel shader settings if driver does not support them + videoSettingsWindow->synchronizePixelShaderSettings(); utility.resizeMainWindow(); utility.updateAvSync(); diff --git a/src/ui_qt/base/filebrowser.cpp b/src/ui_qt/base/filebrowser.cpp index e5e5e446..5085c813 100644 --- a/src/ui_qt/base/filebrowser.cpp +++ b/src/ui_qt/base/filebrowser.cpp @@ -77,9 +77,17 @@ FileBrowser::FileBrowser() { string FileBrowser::resolveFilename(const string &path) { if(QDir(path).exists()) { - if(striend(path, ".sfc") == false) return ""; + string filter; + if(striend(path, ".sfc")) filter = "*.sfc"; + if(striend(path, ".bs" )) filter = "*.bs"; + if(striend(path, ".st" )) filter = "*.st"; + if(striend(path, ".gb" )) filter = "*.gb"; + if(striend(path, ".sgb")) filter = "*.sgb"; + if(striend(path, ".gbc")) filter = "*.gbc"; + if(filter == "") return ""; + QDir directory(path); - directory.setNameFilters(QStringList() << "*.sfc"); + directory.setNameFilters(QStringList() << filter); QStringList list = directory.entryList(QDir::Files | QDir::NoDotAndDotDot); if(list.count() == 1) return string() << path << "/" << list[0].toUtf8().constData(); return ""; @@ -93,31 +101,34 @@ void FileBrowser::onChangeCartridge(const string &path) { if(QDir(path).exists()) filename = resolveFilename(path); else filename = path; - if(file::exists(filename) && striend(filename, ".sfc")) { - Cartridge::Information info; - if(cartridge.information(filename, info)) { + string info; + string image = string() << nall::basename(filename) << ".png"; + string patch = string() << nall::basename(filename) << ".ups"; + + if(file::exists(filename)) { + if(striend(filename, ".sfc")) { + Cartridge::Information cartinfo; + if(cartridge.information(filename, cartinfo)) { + info << ""; + info << ""; + info << ""; + info << ""; + info << "" : info << "None"; + info << "
Title: " << cartinfo.name << "
Region: " << cartinfo.region << "
ROM: " << cartinfo.romSize * 8 / 1024 / 1024 << "mbit
RAM: "; + cartinfo.ramSize ? info << cartinfo.ramSize * 8 / 1024 << "kbit
"; + } + } else if(striend(filename, ".st")) { unsigned size = file::size(filename); - string text; - text << ""; - text << ""; - text << ""; - text << ""; - text << "" : text << "None"; - text << "
Title: " << info.name << "
Region: " << info.region << "
ROM: " << info.romSize * 8 / 1024 / 1024 << "mbit
RAM: "; - info.ramSize ? text << info.ramSize * 8 / 1024 << "kbit
"; - previewInfo->setText(text); + info << ""; + info << ""; + info << "
ROM: " << size * 8 / 1024 / 1024 << "mbit
"; } - - string image = string() << nall::basename(filename) << ".png"; - previewImage->setStyleSheet(string() << "background: url(" << image << ") top left no-repeat;"); - - string patch = string() << nall::basename(filename) << ".ups"; - previewApplyPatch->setVisible(file::exists(patch)); - } else { - previewInfo->setText(""); - previewImage->setStyleSheet("background: transparent;"); - previewApplyPatch->hide(); } + + if(info == "") info = "No preview available"; + previewInfo->setText(info); + previewImage->setStyleSheet(string() << "background: url(" << image << ") center left no-repeat;"); + previewApplyPatch->setVisible(file::exists(patch)); } void FileBrowser::onAcceptCartridge(const string &path) { @@ -134,31 +145,23 @@ void FileBrowser::onAcceptCartridge(const string &path) { if(cartridgeMode == LoadDirect) { config().path.current.filter = filterBox->currentIndex(); - string filter = filterBox->currentText().toUtf8().constData(); - if(strbegin(filter, "SNES cartridges")) { - cartridge.loadNormal(filename); - } else if(strbegin(filter, "BS-X cartridges")) { - if(config().path.bsx == "") { - loaderWindow->loadBsxCartridge("", filename); - } else { - cartridge.loadBsx(config().path.bsx, filename); - } - } else if(strbegin(filter, "Sufami Turbo cartridges")) { - if(config().path.st == "") { - loaderWindow->loadSufamiTurboCartridge("", filename, ""); - } else { - cartridge.loadSufamiTurbo(config().path.st, filename, ""); - } - } else if(strbegin(filter, "Game Boy cartridges")) { - if(config().path.sgb == "") { - loaderWindow->loadSuperGameBoyCartridge("", filename); - } else { - cartridge.loadSuperGameBoy(config().path.sgb, filename); - } - } else { - cartridge.loadNormal(filename); - } + + if(0); + //file extension detection + else if(striend(filename, ".sfc")) acceptNormal(filename); + else if(striend(filename, ".bs")) acceptBsx(filename); + else if(striend(filename, ".st")) acceptSufamiTurbo(filename); + else if(striend(filename, ".gb")) acceptSuperGameBoy(filename); + else if(striend(filename, ".sgb")) acceptSuperGameBoy(filename); + else if(striend(filename, ".gbc")) acceptSuperGameBoy(filename); + //filter detection + else if(strbegin(filter, "SNES cartridges")) acceptNormal(filename); + else if(strbegin(filter, "BS-X cartridges")) acceptBsx(filename); + else if(strbegin(filter, "Sufami Turbo cartridges")) acceptSufamiTurbo(filename); + else if(strbegin(filter, "Game Boy cartridges")) acceptSuperGameBoy(filename); + //fallback behavior + else acceptNormal(filename); } else if(cartridgeMode == LoadBase) { loaderWindow->selectBaseCartridge(filename); } else if(cartridgeMode == LoadSlot1) { @@ -168,3 +171,31 @@ void FileBrowser::onAcceptCartridge(const string &path) { } } } + +void FileBrowser::acceptNormal(const string &filename) { + cartridge.loadNormal(filename); +} + +void FileBrowser::acceptBsx(const string &filename) { + if(config().path.bsx == "") { + loaderWindow->loadBsxCartridge("", filename); + } else { + cartridge.loadBsx(config().path.bsx, filename); + } +} + +void FileBrowser::acceptSufamiTurbo(const string &filename) { + if(config().path.st == "") { + loaderWindow->loadSufamiTurboCartridge("", filename, ""); + } else { + cartridge.loadSufamiTurbo(config().path.st, filename, ""); + } +} + +void FileBrowser::acceptSuperGameBoy(const string &filename) { + if(config().path.sgb == "") { + loaderWindow->loadSuperGameBoyCartridge("", filename); + } else { + cartridge.loadSuperGameBoy(config().path.sgb, filename); + } +} diff --git a/src/ui_qt/base/filebrowser.moc.hpp b/src/ui_qt/base/filebrowser.moc.hpp index b6ea2ff9..f3051698 100644 --- a/src/ui_qt/base/filebrowser.moc.hpp +++ b/src/ui_qt/base/filebrowser.moc.hpp @@ -28,6 +28,11 @@ private: string resolveFilename(const string&); void onChangeCartridge(const string&); void onAcceptCartridge(const string&); + + void acceptNormal(const string &filename); + void acceptBsx(const string &filename); + void acceptSufamiTurbo(const string &filename); + void acceptSuperGameBoy(const string &filename); }; extern FileBrowser *fileBrowser; diff --git a/src/ui_qt/base/main.cpp b/src/ui_qt/base/main.cpp index 91fd05ce..29caf705 100644 --- a/src/ui_qt/base/main.cpp +++ b/src/ui_qt/base/main.cpp @@ -86,6 +86,12 @@ MainWindow::MainWindow() { settings_videoMode->addAction(settings_videoMode_5x = new RadioAction("Scale &5x", 0)); + settings_videoMode->addAction(settings_videoMode_max_normal = new RadioAction("Scale Max - &Normal", 0)); + + settings_videoMode->addAction(settings_videoMode_max_wide = new RadioAction("Scale Max - &Wide", 0)); + + settings_videoMode->addAction(settings_videoMode_max_wideZoom = new RadioAction("Scale Max - Wide &Zoom", 0)); + settings_videoMode->addSeparator(); settings_videoMode->addAction(settings_videoMode_correctAspectRatio = new CheckAction("Correct &Aspect Ratio", 0)); @@ -267,6 +273,9 @@ MainWindow::MainWindow() { connect(settings_videoMode_3x, SIGNAL(triggered()), this, SLOT(setVideoMode3x())); connect(settings_videoMode_4x, SIGNAL(triggered()), this, SLOT(setVideoMode4x())); connect(settings_videoMode_5x, SIGNAL(triggered()), this, SLOT(setVideoMode5x())); + connect(settings_videoMode_max_normal, SIGNAL(triggered()), this, SLOT(setVideoModeMaxNormal())); + connect(settings_videoMode_max_wide, SIGNAL(triggered()), this, SLOT(setVideoModeMaxWide())); + connect(settings_videoMode_max_wideZoom, SIGNAL(triggered()), this, SLOT(setVideoModeMaxWideZoom())); connect(settings_videoMode_correctAspectRatio, SIGNAL(triggered()), this, SLOT(toggleAspectCorrection())); connect(settings_videoMode_ntsc, SIGNAL(triggered()), this, SLOT(setVideoNtsc())); connect(settings_videoMode_pal, SIGNAL(triggered()), this, SLOT(setVideoPal())); @@ -304,18 +313,18 @@ MainWindow::MainWindow() { void MainWindow::syncUi() { system_power->setEnabled(SNES::cartridge.loaded()); - system_power->setChecked (application.power == true); + system_power->setChecked(application.power == true); system_power->setEnabled(SNES::cartridge.loaded()); system_reset->setEnabled(SNES::cartridge.loaded() && application.power); system_port1_none->setChecked (config().input.port1 == ControllerPort1::None); - system_port1_gamepad->setChecked (config().input.port1 == ControllerPort1::Gamepad); + system_port1_gamepad->setChecked (config().input.port1 == ControllerPort1::Gamepad); system_port1_asciipad->setChecked (config().input.port1 == ControllerPort1::Asciipad); system_port1_multitap->setChecked (config().input.port1 == ControllerPort1::Multitap); system_port1_mouse->setChecked (config().input.port1 == ControllerPort1::Mouse); system_port2_none->setChecked (config().input.port2 == ControllerPort2::None); - system_port2_gamepad->setChecked (config().input.port2 == ControllerPort2::Gamepad); + system_port2_gamepad->setChecked (config().input.port2 == ControllerPort2::Gamepad); system_port2_asciipad->setChecked (config().input.port2 == ControllerPort2::Asciipad); system_port2_multitap->setChecked (config().input.port2 == ControllerPort2::Multitap); system_port2_mouse->setChecked (config().input.port2 == ControllerPort2::Mouse); @@ -323,11 +332,18 @@ void MainWindow::syncUi() { system_port2_justifier->setChecked (config().input.port2 == ControllerPort2::Justifier); system_port2_justifiers->setChecked(config().input.port2 == ControllerPort2::Justifiers); - settings_videoMode_1x->setChecked(config().video.context->multiplier == 1); - settings_videoMode_2x->setChecked(config().video.context->multiplier == 2); - settings_videoMode_3x->setChecked(config().video.context->multiplier == 3); - settings_videoMode_4x->setChecked(config().video.context->multiplier == 4); - settings_videoMode_5x->setChecked(config().video.context->multiplier == 5); + settings_videoMode_1x->setChecked (config().video.context->multiplier == 1); + settings_videoMode_2x->setChecked (config().video.context->multiplier == 2); + settings_videoMode_3x->setChecked (config().video.context->multiplier == 3); + settings_videoMode_4x->setChecked (config().video.context->multiplier == 4); + settings_videoMode_5x->setChecked (config().video.context->multiplier == 5); + settings_videoMode_max_normal->setChecked(config().video.context->multiplier == 6); + settings_videoMode_max_wide->setChecked (config().video.context->multiplier == 7); + settings_videoMode_max_wideZoom->setChecked (config().video.context->multiplier == 8); + + settings_videoMode_max_normal->setVisible(config().video.isFullscreen == true); + settings_videoMode_max_wide->setVisible (config().video.isFullscreen == true); + settings_videoMode_max_wideZoom->setVisible (config().video.isFullscreen == true); settings_videoMode_correctAspectRatio->setChecked(config().video.context->correctAspectRatio); settings_videoMode_ntsc->setChecked(config().video.context->region == 0); @@ -485,11 +501,14 @@ void MainWindow::quit() { application.terminate = true; } -void MainWindow::setVideoMode1x() { utility.setScale(1); } -void MainWindow::setVideoMode2x() { utility.setScale(2); } -void MainWindow::setVideoMode3x() { utility.setScale(3); } -void MainWindow::setVideoMode4x() { utility.setScale(4); } -void MainWindow::setVideoMode5x() { utility.setScale(5); } +void MainWindow::setVideoMode1x() { utility.setScale(1); } +void MainWindow::setVideoMode2x() { utility.setScale(2); } +void MainWindow::setVideoMode3x() { utility.setScale(3); } +void MainWindow::setVideoMode4x() { utility.setScale(4); } +void MainWindow::setVideoMode5x() { utility.setScale(5); } +void MainWindow::setVideoModeMaxNormal() { utility.setScale(6); } +void MainWindow::setVideoModeMaxWide() { utility.setScale(7); } +void MainWindow::setVideoModeMaxWideZoom() { utility.setScale(8); } void MainWindow::toggleAspectCorrection() { utility.toggleAspectCorrection(); } diff --git a/src/ui_qt/base/main.moc.hpp b/src/ui_qt/base/main.moc.hpp index 215b80ae..29743882 100644 --- a/src/ui_qt/base/main.moc.hpp +++ b/src/ui_qt/base/main.moc.hpp @@ -52,6 +52,9 @@ public: RadioAction *settings_videoMode_3x; RadioAction *settings_videoMode_4x; RadioAction *settings_videoMode_5x; + RadioAction *settings_videoMode_max_normal; + RadioAction *settings_videoMode_max_wide; + RadioAction *settings_videoMode_max_wideZoom; CheckAction *settings_videoMode_correctAspectRatio; RadioAction *settings_videoMode_ntsc; RadioAction *settings_videoMode_pal; @@ -123,6 +126,9 @@ public slots: void setVideoMode3x(); void setVideoMode4x(); void setVideoMode5x(); + void setVideoModeMaxNormal(); + void setVideoModeMaxWide(); + void setVideoModeMaxWideZoom(); void toggleAspectCorrection(); void setVideoNtsc(); void setVideoPal(); diff --git a/src/ui_qt/config.cpp b/src/ui_qt/config.cpp index 5c5cb870..e0a5b607 100644 --- a/src/ui_qt/config.cpp +++ b/src/ui_qt/config.cpp @@ -88,6 +88,11 @@ Configuration::Configuration() { attach(video.ntscAspectRatio = 54.0 / 47.0, "video.ntscAspectRatio", "NTSC aspect ratio (x / y)"); attach(video.palAspectRatio = 32.0 / 23.0, "video.palAspectRatio", "PAL aspect ratio (x / y)"); + attach(video.cropLeft = 0, "video.cropLeft"); + attach(video.cropTop = 0, "video.cropTop"); + attach(video.cropRight = 0, "video.cropRight"); + attach(video.cropBottom = 0, "video.cropBottom"); + attach(video.windowed.correctAspectRatio = true, "video.windowed.correctAspectRatio"); attach(video.windowed.multiplier = 2, "video.windowed.multiplier"); attach(video.windowed.region = 0, "video.windowed.region"); diff --git a/src/ui_qt/config.hpp b/src/ui_qt/config.hpp index 49cc2948..3b7d88ce 100644 --- a/src/ui_qt/config.hpp +++ b/src/ui_qt/config.hpp @@ -43,6 +43,11 @@ public: bool enableGammaRamp; double ntscAspectRatio, palAspectRatio; + unsigned cropLeft; + unsigned cropTop; + unsigned cropRight; + unsigned cropBottom; + struct Context { bool correctAspectRatio; unsigned multiplier, region; diff --git a/src/ui_qt/input/userinterface-videosettings.cpp b/src/ui_qt/input/userinterface-videosettings.cpp index 0bc6446d..20a55d80 100644 --- a/src/ui_qt/input/userinterface-videosettings.cpp +++ b/src/ui_qt/input/userinterface-videosettings.cpp @@ -112,4 +112,37 @@ struct Scale5x : HotkeyInput { } } scale5x; +struct ScaleMaxNormal : HotkeyInput { + void pressed() { + if(config().video.isFullscreen) utility.setScale(6); + } + + ScaleMaxNormal() : HotkeyInput("Scale Max - Normal", "input.userInterface.videoSettings.scaleMaxNormal") { + name = "Shift+KB0::Num6"; + userInterfaceVideoSettings.attach(this); + } +} scaleMaxNormal; + +struct ScaleMaxFill : HotkeyInput { + void pressed() { + if(config().video.isFullscreen) utility.setScale(7); + } + + ScaleMaxFill() : HotkeyInput("Scale Max - Fill", "input.userInterface.videoSettings.scaleMaxFill") { + name = "Shift+KB0::Num7"; + userInterfaceVideoSettings.attach(this); + } +} scaleMaxFill; + +struct ScaleMaxSmart : HotkeyInput { + void pressed() { + if(config().video.isFullscreen) utility.setScale(8); + } + + ScaleMaxSmart() : HotkeyInput("Scale Max - Smart", "input.userInterface.videoSettings.scaleMaxSmart") { + name = "Shift+KB0::Num8"; + userInterfaceVideoSettings.attach(this); + } +} scaleMaxSmart; + } diff --git a/src/ui_qt/interface.cpp b/src/ui_qt/interface.cpp index 7bd4a9d2..8dcf4dd8 100644 --- a/src/ui_qt/interface.cpp +++ b/src/ui_qt/interface.cpp @@ -1,12 +1,22 @@ Interface interface; void Interface::video_refresh(uint16_t *data, unsigned pitch, unsigned *line, unsigned width, unsigned height) { + //scale display.crop* values from percentage-based (0-100%) to exact pixel sizes (width, height) + unsigned cropLeft = (double)display.cropLeft / 100.0 * width; + unsigned cropTop = (double)display.cropTop / 100.0 * height; + unsigned cropRight = (double)display.cropRight / 100.0 * width; + unsigned cropBottom = (double)display.cropBottom / 100.0 * height; + + width -= (cropLeft + cropRight); + height -= (cropTop + cropBottom); + uint32_t *output; unsigned outwidth, outheight, outpitch; filter.size(outwidth, outheight, width, height); if(video.lock(output, outpitch, outwidth, outheight) == true) { - filter.render(output, outpitch, data, pitch, line, width, height); + data += cropTop * (pitch >> 1) + cropLeft; + filter.render(output, outpitch, data, pitch, line + cropTop, width, height); video.unlock(); video.refresh(); if(saveScreenshot == true) captureScreenshot(output, outpitch, outwidth, outheight); diff --git a/src/ui_qt/link/filter.cpp b/src/ui_qt/link/filter.cpp index 9f93f283..b89119a6 100644 --- a/src/ui_qt/link/filter.cpp +++ b/src/ui_qt/link/filter.cpp @@ -193,21 +193,21 @@ void Filter::render( outpitch >>= 2; for(unsigned y = 0; y < height; y++) { - if(width == 512 && line[y] == 256) { - for(unsigned x = 0; x < 256; x++) { - uint16_t p = *input++; - *output++ = colortable[p]; - *output++ = colortable[p]; + const uint16_t *in = input + y * pitch; + uint32_t *out = output + y * outpitch; + + if(width > 256 && line[y] <= 256) { + for(unsigned x = 0; x < line[y]; x++) { + uint16_t p = *in++; + *out++ = colortable[p]; + *out++ = colortable[p]; } - input += 256; } else { for(unsigned x = 0; x < width; x++) { - uint16_t p = *input++; - *output++ = colortable[p]; + uint16_t p = *in++; + *out++ = colortable[p]; } } - input += pitch - width; - output += outpitch - width; } } diff --git a/src/ui_qt/settings/pixelshader.cpp b/src/ui_qt/settings/pixelshader.cpp deleted file mode 100644 index 1eb8beb7..00000000 --- a/src/ui_qt/settings/pixelshader.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "pixelshader.moc" -PixelShaderWindow *pixelShaderWindow; - -PixelShaderWindow::PixelShaderWindow() { - layout = new QVBoxLayout; - layout->setMargin(0); - layout->setSpacing(Style::WidgetSpacing); - layout->setAlignment(Qt::AlignTop); - setLayout(layout); - - gridLayout = new QGridLayout; - gridLayout->setVerticalSpacing(0); - layout->addLayout(gridLayout); - - fragmentLabel = new QLabel("Fragment shader:"); - gridLayout->addWidget(fragmentLabel, 0, 0, 1, 3); - - fragmentPath = new QLineEdit; - gridLayout->addWidget(fragmentPath, 1, 0); - - fragmentSelect = new QPushButton("Select ..."); - gridLayout->addWidget(fragmentSelect, 1, 1); - - fragmentDefault = new QPushButton("Default"); - gridLayout->addWidget(fragmentDefault, 1, 2); - - vertexLabel = new QLabel("Vertex shader:"); - gridLayout->addWidget(vertexLabel, 2, 0, 1, 3); - - vertexPath = new QLineEdit; - gridLayout->addWidget(vertexPath, 3, 0); - - vertexSelect = new QPushButton("Select ..."); - gridLayout->addWidget(vertexSelect, 3, 1); - - vertexDefault = new QPushButton("Default"); - gridLayout->addWidget(vertexDefault, 3, 2); - - synchronize(); - - connect(fragmentSelect, SIGNAL(released()), this, SLOT(selectFragmentShader())); - connect(vertexSelect, SIGNAL(released()), this, SLOT(selectVertexShader())); - connect(fragmentDefault, SIGNAL(released()), this, SLOT(defaultFragmentShader())); - connect(vertexDefault, SIGNAL(released()), this, SLOT(defaultVertexShader())); -} - -void PixelShaderWindow::synchronize() { - fragmentPath->setText(config().path.fragmentShader); - vertexPath->setText(config().path.vertexShader); -} - -void PixelShaderWindow::selectFragmentShader() { - fileBrowser->onChange = (void*)0; - fileBrowser->onActivate = bind(&PixelShaderWindow::assignFragmentShader, this); - fileBrowser->onAccept = bind(&PixelShaderWindow::assignFragmentShader, this); - fileBrowser->setWindowTitle("Select Fragment Shader"); - fileBrowser->setPath(config().path.current.shader); - fileBrowser->setNameFilters("All files (*)"); - fileBrowser->showLoad(); -} - -void PixelShaderWindow::selectVertexShader() { - fileBrowser->onChange = (void*)0; - fileBrowser->onActivate = bind(&PixelShaderWindow::assignVertexShader, this); - fileBrowser->onAccept = bind(&PixelShaderWindow::assignVertexShader, this); - fileBrowser->setWindowTitle("Select Vertex Shader"); - fileBrowser->setPath(config().path.current.shader); - fileBrowser->setNameFilters("All files (*)"); - fileBrowser->showLoad(); -} - -void PixelShaderWindow::defaultFragmentShader() { assignFragmentShader(""); } -void PixelShaderWindow::defaultVertexShader() { assignVertexShader(""); } - -void PixelShaderWindow::assignFragmentShader(const string &filename) { - if(filename == "" || QDir(filename).exists() == false) { - config().path.fragmentShader = filename; - if(filename != "") config().path.current.shader = dir(filename); - synchronize(); - utility.updatePixelShader(); - } -} - -void PixelShaderWindow::assignVertexShader(const string &filename) { - if(filename == "" || QDir(filename).exists() == false) { - config().path.vertexShader = filename; - if(filename != "") config().path.current.shader = dir(filename); - synchronize(); - utility.updatePixelShader(); - } -} diff --git a/src/ui_qt/settings/pixelshader.moc.hpp b/src/ui_qt/settings/pixelshader.moc.hpp deleted file mode 100644 index 9b65ea4f..00000000 --- a/src/ui_qt/settings/pixelshader.moc.hpp +++ /dev/null @@ -1,29 +0,0 @@ -class PixelShaderWindow : public QWidget { - Q_OBJECT - -public: - QVBoxLayout *layout; - QGridLayout *gridLayout; - QLabel *fragmentLabel; - QLineEdit *fragmentPath; - QPushButton *fragmentSelect; - QPushButton *fragmentDefault; - QLabel *vertexLabel; - QLineEdit *vertexPath; - QPushButton *vertexSelect; - QPushButton *vertexDefault; - - void synchronize(); - PixelShaderWindow(); - -public slots: - void selectFragmentShader(); - void selectVertexShader(); - void defaultFragmentShader(); - void defaultVertexShader(); - - void assignFragmentShader(const string&); - void assignVertexShader(const string&); -}; - -extern PixelShaderWindow *pixelShaderWindow; diff --git a/src/ui_qt/settings/settings.cpp b/src/ui_qt/settings/settings.cpp index caf57dda..5ec4c8d5 100644 --- a/src/ui_qt/settings/settings.cpp +++ b/src/ui_qt/settings/settings.cpp @@ -1,6 +1,5 @@ #include "../ui-base.hpp" -#include "pixelshader.cpp" #include "video.cpp" #include "audio.cpp" #include "input.cpp" @@ -28,11 +27,36 @@ SettingsWindow::SettingsWindow() { pathSettingsWindow = new PathSettingsWindow; advancedSettingsWindow = new AdvancedSettingsWindow; + videoArea = new QScrollArea; + videoArea->setWidget(videoSettingsWindow); + videoArea->setFrameStyle(0); + videoArea->setWidgetResizable(true); + + audioArea = new QScrollArea; + audioArea->setWidget(audioSettingsWindow); + audioArea->setFrameStyle(0); + audioArea->setWidgetResizable(true); + + inputArea = new QScrollArea; + inputArea->setWidget(inputSettingsWindow); + inputArea->setFrameStyle(0); + inputArea->setWidgetResizable(true); + + pathArea = new QScrollArea; + pathArea->setWidget(pathSettingsWindow); + pathArea->setFrameStyle(0); + pathArea->setWidgetResizable(true); + + advancedArea = new QScrollArea; + advancedArea->setWidget(advancedSettingsWindow); + advancedArea->setFrameStyle(0); + advancedArea->setWidgetResizable(true); + tab = new QTabWidget; - tab->addTab(videoSettingsWindow, QIcon(":/16x16/video-display.png"), "Video"); - tab->addTab(audioSettingsWindow, QIcon(":/16x16/audio-volume-high.png"), "Audio"); - tab->addTab(inputSettingsWindow, QIcon(":/16x16/input-gaming.png"), "Input"); - tab->addTab(pathSettingsWindow, QIcon(":/16x16/folder.png"), "Paths"); - tab->addTab(advancedSettingsWindow, QIcon(":/16x16/preferences-system.png"), "Advanced"); + tab->addTab(videoArea, QIcon(":/16x16/video-display.png"), "Video"); + tab->addTab(audioArea, QIcon(":/16x16/audio-volume-high.png"), "Audio"); + tab->addTab(inputArea, QIcon(":/16x16/input-gaming.png"), "Input"); + tab->addTab(pathArea, QIcon(":/16x16/folder.png"), "Paths"); + tab->addTab(advancedArea, QIcon(":/16x16/preferences-system.png"), "Advanced"); layout->addWidget(tab); } diff --git a/src/ui_qt/settings/settings.moc.hpp b/src/ui_qt/settings/settings.moc.hpp index d371aef3..3a271e76 100644 --- a/src/ui_qt/settings/settings.moc.hpp +++ b/src/ui_qt/settings/settings.moc.hpp @@ -4,6 +4,11 @@ class SettingsWindow : public Window { public: QVBoxLayout *layout; QTabWidget *tab; + QScrollArea *videoArea; + QScrollArea *audioArea; + QScrollArea *inputArea; + QScrollArea *pathArea; + QScrollArea *advancedArea; SettingsWindow(); diff --git a/src/ui_qt/settings/video.cpp b/src/ui_qt/settings/video.cpp index e60a28e8..a2c22f8f 100644 --- a/src/ui_qt/settings/video.cpp +++ b/src/ui_qt/settings/video.cpp @@ -8,58 +8,61 @@ VideoSettingsWindow::VideoSettingsWindow() { layout->setAlignment(Qt::AlignTop); setLayout(layout); - sliders = new QGridLayout; - layout->addLayout(sliders); + colorLabel = new QLabel("Color Adjustment"); + layout->addWidget(colorLabel); + + colorLayout = new QGridLayout; + layout->addLayout(colorLayout); contrastLabel = new QLabel("Contrast adjust:"); - sliders->addWidget(contrastLabel, 0, 0); + colorLayout->addWidget(contrastLabel, 0, 0); contrastValue = new QLabel; contrastValue->setAlignment(Qt::AlignHCenter); contrastValue->setMinimumWidth(contrastValue->fontMetrics().width("+100%")); - sliders->addWidget(contrastValue, 0, 1); + colorLayout->addWidget(contrastValue, 0, 1); - contrast = new QSlider(Qt::Horizontal); - contrast->setMinimum(-95); - contrast->setMaximum(+95); - sliders->addWidget(contrast, 0, 2); + contrastSlider = new QSlider(Qt::Horizontal); + contrastSlider->setMinimum(-95); + contrastSlider->setMaximum(+95); + colorLayout->addWidget(contrastSlider, 0, 2); brightnessLabel = new QLabel("Brightness adjust:"); - sliders->addWidget(brightnessLabel, 1, 0); + colorLayout->addWidget(brightnessLabel, 1, 0); brightnessValue = new QLabel; brightnessValue->setAlignment(Qt::AlignHCenter); - sliders->addWidget(brightnessValue, 1, 1); + colorLayout->addWidget(brightnessValue, 1, 1); - brightness = new QSlider(Qt::Horizontal); - brightness->setMinimum(-95); - brightness->setMaximum(+95); - sliders->addWidget(brightness, 1, 2); + brightnessSlider = new QSlider(Qt::Horizontal); + brightnessSlider->setMinimum(-95); + brightnessSlider->setMaximum(+95); + colorLayout->addWidget(brightnessSlider, 1, 2); gammaLabel = new QLabel("Gamma adjust:"); - sliders->addWidget(gammaLabel, 2, 0); + colorLayout->addWidget(gammaLabel, 2, 0); gammaValue = new QLabel; gammaValue->setAlignment(Qt::AlignHCenter); - sliders->addWidget(gammaValue, 2, 1); + colorLayout->addWidget(gammaValue, 2, 1); - gamma = new QSlider(Qt::Horizontal); - gamma->setMinimum(-95); - gamma->setMaximum(+95); - sliders->addWidget(gamma, 2, 2); + gammaSlider = new QSlider(Qt::Horizontal); + gammaSlider->setMinimum(-95); + gammaSlider->setMaximum(+95); + colorLayout->addWidget(gammaSlider, 2, 2); scanlineLabel = new QLabel("Scanline adjust:"); - sliders->addWidget(scanlineLabel, 3, 0); + colorLayout->addWidget(scanlineLabel, 3, 0); scanlineValue = new QLabel; scanlineValue->setAlignment(Qt::AlignHCenter); - sliders->addWidget(scanlineValue, 3, 1); + colorLayout->addWidget(scanlineValue, 3, 1); - scanline = new QSlider(Qt::Horizontal); - scanline->setMinimum(0); - scanline->setMaximum(20); - scanline->setPageStep(4); - sliders->addWidget(scanline, 3, 2); + scanlineSlider = new QSlider(Qt::Horizontal); + scanlineSlider->setMinimum(0); + scanlineSlider->setMaximum(20); + scanlineSlider->setPageStep(4); + colorLayout->addWidget(scanlineSlider, 3, 2); options = new QHBoxLayout; layout->addLayout(options); @@ -68,38 +71,167 @@ VideoSettingsWindow::VideoSettingsWindow() { enableGammaRamp->setToolTip("Lower monitor gamma to more accurately match a CRT television"); options->addWidget(enableGammaRamp); - pixelShaderWindow = new PixelShaderWindow; - layout->addWidget(pixelShaderWindow); + cropLabel = new QLabel("Overscan Compensation"); + layout->addWidget(cropLabel); - connect(contrast, SIGNAL(valueChanged(int)), this, SLOT(contrastAdjust(int))); - connect(brightness, SIGNAL(valueChanged(int)), this, SLOT(brightnessAdjust(int))); - connect(gamma, SIGNAL(valueChanged(int)), this, SLOT(gammaAdjust(int))); - connect(scanline, SIGNAL(valueChanged(int)), this, SLOT(scanlineAdjust(int))); + cropLayout = new QGridLayout; + layout->addLayout(cropLayout); + + cropLeftLabel = new QLabel("Left:"); + cropLayout->addWidget(cropLeftLabel, 0, 0); + + cropLeftValue = new QLabel; + cropLeftValue->setAlignment(Qt::AlignHCenter); + cropLeftValue->setMinimumWidth(cropLeftValue->fontMetrics().width("+100%")); + cropLayout->addWidget(cropLeftValue, 0, 1); + + cropLeftSlider = new QSlider(Qt::Horizontal); + cropLeftSlider->setMinimum(0); + cropLeftSlider->setMaximum(20); + cropLayout->addWidget(cropLeftSlider, 0, 2); + + cropTopLabel = new QLabel("Top:"); + cropLayout->addWidget(cropTopLabel, 1, 0); + + cropTopValue = new QLabel; + cropTopValue->setAlignment(Qt::AlignHCenter); + cropLayout->addWidget(cropTopValue, 1, 1); + + cropTopSlider = new QSlider(Qt::Horizontal); + cropTopSlider->setMinimum(0); + cropTopSlider->setMaximum(20); + cropLayout->addWidget(cropTopSlider, 1, 2); + + cropRightLabel = new QLabel("Right:"); + cropLayout->addWidget(cropRightLabel, 2, 0); + + cropRightValue = new QLabel; + cropRightValue->setAlignment(Qt::AlignHCenter); + cropLayout->addWidget(cropRightValue, 2, 1); + + cropRightSlider = new QSlider(Qt::Horizontal); + cropRightSlider->setMinimum(0); + cropRightSlider->setMaximum(20); + cropLayout->addWidget(cropRightSlider, 2, 2); + + cropBottomLabel = new QLabel("Bottom:"); + cropLayout->addWidget(cropBottomLabel, 3, 0); + + cropBottomValue = new QLabel; + cropBottomValue->setAlignment(Qt::AlignHCenter); + cropLayout->addWidget(cropBottomValue, 3, 1); + + cropBottomSlider = new QSlider(Qt::Horizontal); + cropBottomSlider->setMinimum(0); + cropBottomSlider->setMaximum(20); + cropLayout->addWidget(cropBottomSlider, 3, 2); + + pixelShaderLabel = new QLabel("Pixel Shader"); + layout->addWidget(pixelShaderLabel); + + pixelShaderLayout = new QGridLayout; + layout->addLayout(pixelShaderLayout); + + fragmentShaderLabel = new QLabel("Fragment:"); + pixelShaderLayout->addWidget(fragmentShaderLabel, 0, 0); + + fragmentShaderValue = new QLineEdit; + pixelShaderLayout->addWidget(fragmentShaderValue, 0, 1); + + fragmentShaderSelect = new QPushButton("Select ..."); + pixelShaderLayout->addWidget(fragmentShaderSelect, 0, 2); + + fragmentShaderDefault = new QPushButton("Default"); + pixelShaderLayout->addWidget(fragmentShaderDefault, 0, 3); + + vertexShaderLabel = new QLabel("Vertex:"); + pixelShaderLayout->addWidget(vertexShaderLabel, 1, 0); + + vertexShaderValue = new QLineEdit; + pixelShaderLayout->addWidget(vertexShaderValue, 1, 1); + + vertexShaderSelect = new QPushButton("Select ..."); + pixelShaderLayout->addWidget(vertexShaderSelect, 1, 2); + + vertexShaderDefault = new QPushButton("Default"); + pixelShaderLayout->addWidget(vertexShaderDefault, 1, 3); + + connect(contrastSlider, SIGNAL(valueChanged(int)), this, SLOT(contrastAdjust(int))); + connect(brightnessSlider, SIGNAL(valueChanged(int)), this, SLOT(brightnessAdjust(int))); + connect(gammaSlider, SIGNAL(valueChanged(int)), this, SLOT(gammaAdjust(int))); + connect(scanlineSlider, SIGNAL(valueChanged(int)), this, SLOT(scanlineAdjust(int))); connect(enableGammaRamp, SIGNAL(stateChanged(int)), this, SLOT(gammaRampToggle(int))); + connect(cropLeftSlider, SIGNAL(valueChanged(int)), this, SLOT(cropLeftAdjust(int))); + connect(cropTopSlider, SIGNAL(valueChanged(int)), this, SLOT(cropTopAdjust(int))); + connect(cropRightSlider, SIGNAL(valueChanged(int)), this, SLOT(cropRightAdjust(int))); + connect(cropBottomSlider, SIGNAL(valueChanged(int)), this, SLOT(cropBottomAdjust(int))); + connect(fragmentShaderSelect, SIGNAL(released()), this, SLOT(selectFragmentShader())); + connect(fragmentShaderDefault, SIGNAL(released()), this, SLOT(defaultFragmentShader())); + connect(vertexShaderSelect, SIGNAL(released()), this, SLOT(selectVertexShader())); + connect(vertexShaderDefault, SIGNAL(released()), this, SLOT(defaultVertexShader())); syncUi(); } +void VideoSettingsWindow::synchronizePixelShaderSettings() { + if(!video.cap(Video::FragmentShader) && !video.cap(Video::VertexShader)) { + pixelShaderLabel->hide(); + } + + if(!video.cap(Video::FragmentShader)) { + fragmentShaderLabel->hide(); + fragmentShaderValue->hide(); + fragmentShaderSelect->hide(); + fragmentShaderDefault->hide(); + } + + if(!video.cap(Video::VertexShader)) { + vertexShaderLabel->hide(); + vertexShaderValue->hide(); + vertexShaderSelect->hide(); + vertexShaderDefault->hide(); + } +} + void VideoSettingsWindow::syncUi() { int n; n = config().video.contrastAdjust; contrastValue->setText(string() << (n > 0 ? "+" : "") << n << "%"); - contrast->setSliderPosition(n); + contrastSlider->setSliderPosition(n); n = config().video.brightnessAdjust; brightnessValue->setText(string() << (n > 0 ? "+" : "") << n << "%"); - brightness->setSliderPosition(n); + brightnessSlider->setSliderPosition(n); n = config().video.gammaAdjust; gammaValue->setText(string() << (n > 0 ? "+" : "") << n << "%"); - gamma->setSliderPosition(n); + gammaSlider->setSliderPosition(n); n = config().video.scanlineAdjust; scanlineValue->setText(string() << n << "%"); - scanline->setSliderPosition(n / 5); + scanlineSlider->setSliderPosition(n / 5); enableGammaRamp->setChecked(config().video.enableGammaRamp); + + n = config().video.cropLeft; + cropLeftValue->setText(string() << n << "%"); + cropLeftSlider->setSliderPosition(n); + + n = config().video.cropTop; + cropTopValue->setText(string() << n << "%"); + cropTopSlider->setSliderPosition(n); + + n = config().video.cropRight; + cropRightValue->setText(string() << n << "%"); + cropRightSlider->setSliderPosition(n); + + n = config().video.cropBottom; + cropBottomValue->setText(string() << n << "%"); + cropBottomSlider->setSliderPosition(n); + + fragmentShaderValue->setText(config().path.fragmentShader); + vertexShaderValue->setText(config().path.vertexShader); } void VideoSettingsWindow::contrastAdjust(int value) { @@ -131,3 +263,68 @@ void VideoSettingsWindow::gammaRampToggle(int state) { syncUi(); utility.updateColorFilter(); } + +void VideoSettingsWindow::cropLeftAdjust(int state) { + config().video.cropLeft = state; + if(config().video.context->multiplier != 8) display.cropLeft = state; + syncUi(); +} + +void VideoSettingsWindow::cropTopAdjust(int state) { + config().video.cropTop = state; + if(config().video.context->multiplier != 8) display.cropTop = state; + syncUi(); +} + +void VideoSettingsWindow::cropRightAdjust(int state) { + config().video.cropRight = state; + if(config().video.context->multiplier != 8) display.cropRight = state; + syncUi(); +} + +void VideoSettingsWindow::cropBottomAdjust(int state) { + config().video.cropBottom = state; + if(config().video.context->multiplier != 8) display.cropBottom = state; + syncUi(); +} + +void VideoSettingsWindow::selectFragmentShader() { + fileBrowser->onChange = (void*)0; + fileBrowser->onActivate = bind(&VideoSettingsWindow::assignFragmentShader, this); + fileBrowser->onAccept = bind(&VideoSettingsWindow::assignFragmentShader, this); + fileBrowser->setWindowTitle("Select Fragment Shader"); + fileBrowser->setPath(config().path.current.shader); + fileBrowser->setNameFilters("All files (*)"); + fileBrowser->showLoad(); +} + +void VideoSettingsWindow::selectVertexShader() { + fileBrowser->onChange = (void*)0; + fileBrowser->onActivate = bind(&VideoSettingsWindow::assignVertexShader, this); + fileBrowser->onAccept = bind(&VideoSettingsWindow::assignVertexShader, this); + fileBrowser->setWindowTitle("Select Vertex Shader"); + fileBrowser->setPath(config().path.current.shader); + fileBrowser->setNameFilters("All files (*)"); + fileBrowser->showLoad(); +} + +void VideoSettingsWindow::defaultFragmentShader() { assignFragmentShader(""); } +void VideoSettingsWindow::defaultVertexShader() { assignVertexShader(""); } + +void VideoSettingsWindow::assignFragmentShader(const string &filename) { + if(filename == "" || QDir(filename).exists() == false) { + config().path.fragmentShader = filename; + if(filename != "") config().path.current.shader = dir(filename); + syncUi(); + utility.updatePixelShader(); + } +} + +void VideoSettingsWindow::assignVertexShader(const string &filename) { + if(filename == "" || QDir(filename).exists() == false) { + config().path.vertexShader = filename; + if(filename != "") config().path.current.shader = dir(filename); + syncUi(); + utility.updatePixelShader(); + } +} diff --git a/src/ui_qt/settings/video.moc.hpp b/src/ui_qt/settings/video.moc.hpp index 2343bccc..eca1d834 100644 --- a/src/ui_qt/settings/video.moc.hpp +++ b/src/ui_qt/settings/video.moc.hpp @@ -3,31 +3,69 @@ class VideoSettingsWindow : public QWidget { public: QVBoxLayout *layout; - QGridLayout *sliders; + QLabel *colorLabel; + QGridLayout *colorLayout; QLabel *contrastLabel; QLabel *contrastValue; - QSlider *contrast; + QSlider *contrastSlider; QLabel *brightnessLabel; QLabel *brightnessValue; - QSlider *brightness; + QSlider *brightnessSlider; QLabel *gammaLabel; QLabel *gammaValue; - QSlider *gamma; + QSlider *gammaSlider; QLabel *scanlineLabel; QLabel *scanlineValue; - QSlider *scanline; + QSlider *scanlineSlider; QHBoxLayout *options; QCheckBox *enableGammaRamp; + QLabel *cropLabel; + QGridLayout *cropLayout; + QLabel *cropLeftLabel; + QLabel *cropLeftValue; + QSlider *cropLeftSlider; + QLabel *cropTopLabel; + QLabel *cropTopValue; + QSlider *cropTopSlider; + QLabel *cropRightLabel; + QLabel *cropRightValue; + QSlider *cropRightSlider; + QLabel *cropBottomLabel; + QLabel *cropBottomValue; + QSlider *cropBottomSlider; + QLabel *pixelShaderLabel; + QGridLayout *pixelShaderLayout; + QLabel *fragmentShaderLabel; + QLineEdit *fragmentShaderValue; + QPushButton *fragmentShaderSelect; + QPushButton *fragmentShaderDefault; + QLabel *vertexShaderLabel; + QLineEdit *vertexShaderValue; + QPushButton *vertexShaderSelect; + QPushButton *vertexShaderDefault; + void synchronizePixelShaderSettings(); void syncUi(); VideoSettingsWindow(); -public slots: +private slots: void contrastAdjust(int); void brightnessAdjust(int); void gammaAdjust(int); void scanlineAdjust(int); void gammaRampToggle(int); + void cropLeftAdjust(int); + void cropTopAdjust(int); + void cropRightAdjust(int); + void cropBottomAdjust(int); + void selectFragmentShader(); + void selectVertexShader(); + void defaultFragmentShader(); + void defaultVertexShader(); + +private: + void assignFragmentShader(const string &filename); + void assignVertexShader(const string &filename); }; extern VideoSettingsWindow *videoSettingsWindow; diff --git a/src/ui_qt/tools/tools.cpp b/src/ui_qt/tools/tools.cpp index fbc22d28..6300196a 100644 --- a/src/ui_qt/tools/tools.cpp +++ b/src/ui_qt/tools/tools.cpp @@ -23,9 +23,24 @@ ToolsWindow::ToolsWindow() { cheatFinderWindow = new CheatFinderWindow; stateManagerWindow = new StateManagerWindow; + cheatEditorArea = new QScrollArea; + cheatEditorArea->setWidget(cheatEditorWindow); + cheatEditorArea->setFrameStyle(0); + cheatEditorArea->setWidgetResizable(true); + + cheatFinderArea = new QScrollArea; + cheatFinderArea->setWidget(cheatFinderWindow); + cheatFinderArea->setFrameStyle(0); + cheatFinderArea->setWidgetResizable(true); + + stateManagerArea = new QScrollArea; + stateManagerArea->setWidget(stateManagerWindow); + stateManagerArea->setFrameStyle(0); + stateManagerArea->setWidgetResizable(true); + tab = new QTabWidget; - tab->addTab(cheatEditorWindow, QIcon(":/16x16/accessories-text-editor.png"), "Cheat Editor"); - tab->addTab(cheatFinderWindow, QIcon(":/16x16/system-search.png"), "Cheat Finder"); - tab->addTab(stateManagerWindow, QIcon(":/16x16/system-file-manager.png"), "State Manager"); + tab->addTab(cheatEditorArea, QIcon(":/16x16/accessories-text-editor.png"), "Cheat Editor"); + tab->addTab(cheatFinderArea, QIcon(":/16x16/system-search.png"), "Cheat Finder"); + tab->addTab(stateManagerArea, QIcon(":/16x16/system-file-manager.png"), "State Manager"); layout->addWidget(tab); } diff --git a/src/ui_qt/tools/tools.moc.hpp b/src/ui_qt/tools/tools.moc.hpp index 8c84b525..597869da 100644 --- a/src/ui_qt/tools/tools.moc.hpp +++ b/src/ui_qt/tools/tools.moc.hpp @@ -4,6 +4,9 @@ class ToolsWindow : public Window { public: QVBoxLayout *layout; QTabWidget *tab; + QScrollArea *cheatEditorArea; + QScrollArea *cheatFinderArea; + QScrollArea *stateManagerArea; ToolsWindow(); diff --git a/src/ui_qt/ui-base.hpp b/src/ui_qt/ui-base.hpp index 2f0c5d85..0761c8b5 100644 --- a/src/ui_qt/ui-base.hpp +++ b/src/ui_qt/ui-base.hpp @@ -63,7 +63,6 @@ using namespace ruby; #include "movie/movie.hpp" #include "settings/settings.moc.hpp" -#include "settings/pixelshader.moc.hpp" #include "settings/video.moc.hpp" #include "settings/audio.moc.hpp" #include "settings/input.moc.hpp" diff --git a/src/ui_qt/utility/window.cpp b/src/ui_qt/utility/window.cpp index 2acc9ceb..5489c72f 100644 --- a/src/ui_qt/utility/window.cpp +++ b/src/ui_qt/utility/window.cpp @@ -37,10 +37,25 @@ void Utility::constrainSize(unsigned &x, unsigned &y, unsigned max) { } void Utility::resizeMainWindow() { + //process all pending events to ensure window size is correct (after fullscreen state change, etc) + usleep(2000); + QApplication::processEvents(); + + unsigned screenWidth, screenHeight; + if(config().video.isFullscreen == false) { + screenWidth = QApplication::desktop()->availableGeometry(mainWindow).width(); + screenHeight = QApplication::desktop()->availableGeometry(mainWindow).height(); + } else { + screenWidth = mainWindow->canvasContainer->size().width(); + screenHeight = mainWindow->canvasContainer->size().height(); + } + unsigned region = config().video.context->region; unsigned multiplier = config().video.context->multiplier; - unsigned width = 256 * multiplier; - unsigned height = (region == 0 ? 224 : 239) * multiplier; + unsigned &width = display.outputWidth; + unsigned &height = display.outputHeight; + width = 256 * multiplier; + height = (region == 0 ? 224 : 239) * multiplier; if(config().video.context->correctAspectRatio) { if(region == 0) { @@ -50,42 +65,53 @@ void Utility::resizeMainWindow() { } } - //at 5x scale, it is possible to correct the aspect ratio while maintaining - //an even number of pixels for every column and every row; very important for - //point / nearest-neighbor scaling ... - // - //NTSC: 1471x1120 -> 1536x1120 (6x5 scale) - //PAL : 1781x1195 -> 1792x1195 (7x5 scale) - if(multiplier == 5 && config().video.context->correctAspectRatio) { - width = 256 * (region == 0 ? 6 : 7); - height = (region == 0 ? 224 : 239) * 5; - } + display.cropLeft = config().video.cropLeft; + display.cropTop = config().video.cropTop; + display.cropRight = config().video.cropRight; + display.cropBottom = config().video.cropBottom; + + //ensure window size will not be larger than viewable desktop area + constrainSize(height, width, screenHeight); + constrainSize(width, height, screenWidth); if(config().video.isFullscreen == false) { - //get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.) - QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow); - - //ensure window size will not be larger than viewable desktop area - constrainSize(height, width, deskRect.height()); //- frameHeight); - constrainSize(width, height, deskRect.width()); //- frameWidth ); - mainWindow->canvas->setFixedSize(width, height); mainWindow->show(); } else { - for(unsigned i = 0; i < 2; i++) { - unsigned iWidth = width, iHeight = height; - - constrainSize(iHeight, iWidth, mainWindow->canvasContainer->size().height()); - constrainSize(iWidth, iHeight, mainWindow->canvasContainer->size().width()); - - //center canvas onscreen; ensure it is not larger than viewable area - mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - mainWindow->canvas->setFixedSize(iWidth, iHeight); - mainWindow->canvas->setMinimumSize(0, 0); - - usleep(2000); - QApplication::processEvents(); + if(multiplier == 6) { + //Scale Max - Normal + width = (double)width * (double)screenHeight / (double)height; + height = screenHeight; } + + if(multiplier == 7) { + //Scale Max - Wide + width = screenWidth; + height = screenHeight; + } + + if(multiplier == 8) { + //Scale Max - Wide Zoom + //1. scale width and height proportionally until width of screen is completely filled + //2. determine how much height goes out of screen by + //3. cut half of the above value out of the visible input display region + //this results in a 50% compromise between correct aspect ratio and fill mode; + //while cropping out only 50% as much height as a fully proportional zoom would + width = (double)width * (double)screenHeight / (double)height; + height = screenHeight; + unsigned widthDifference = screenWidth - width; + unsigned adjustedHeight = (double)height * (double)(width + widthDifference) / (double)(width); + unsigned heightDifference = adjustedHeight - height; + width = screenWidth; + display.cropLeft = 0; + display.cropTop = 100.0 / (double)height * (heightDifference / 4); + display.cropRight = 0; + display.cropBottom = 100.0 / (double)height * (heightDifference / 4); + } + + mainWindow->canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + mainWindow->canvas->setFixedSize(width, height); + mainWindow->canvas->setMinimumSize(0, 0); } //workaround for Qt/Xlib bug: diff --git a/supergameboy.dll b/supergameboy.dll deleted file mode 100644 index eda4b205..00000000 Binary files a/supergameboy.dll and /dev/null differ diff --git a/supergameboy/nall/platform.hpp b/supergameboy/nall/platform.hpp index 5d2bd6ab..68ed37ce 100644 --- a/supergameboy/nall/platform.hpp +++ b/supergameboy/nall/platform.hpp @@ -1,6 +1,8 @@ #ifndef NALL_PLATFORM_HPP #define NALL_PLATFORM_HPP +#include + //========================= //standard platform headers //========================= @@ -50,7 +52,7 @@ #define getcwd _getcwd #define ftruncate _chsize #define putenv _putenv - #define mkdir(n, m) mkdir(n) + #define mkdir(n, m) _wmkdir(nall::utf16_t(n)) #define rmdir _rmdir #define vsnprintf _vsnprintf #define usleep(n) Sleep(n / 1000) diff --git a/supergameboy/nall/qt/Makefile b/supergameboy/nall/qt/Makefile index 6e148e42..69e84960 100644 --- a/supergameboy/nall/qt/Makefile +++ b/supergameboy/nall/qt/Makefile @@ -21,7 +21,7 @@ ifeq ($(platform),x) qtinc := `pkg-config --cflags $(qtlibs)` qtlib := `pkg-config --libs $(qtlibs)` else ifeq ($(platform),osx) - qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers + qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers) qtlib := -L/Library/Frameworks qtlib += $(foreach lib,$(qtlibs),-framework $(lib)) diff --git a/supergameboy/nall/qt/file-dialog.moc.hpp b/supergameboy/nall/qt/file-dialog.moc.hpp index ff833fcf..bcccfaf5 100644 --- a/supergameboy/nall/qt/file-dialog.moc.hpp +++ b/supergameboy/nall/qt/file-dialog.moc.hpp @@ -342,6 +342,7 @@ inline FileDialog::FileDialog() { fileSystemModel->setNameFilterDisables(false); fileView = new FileView; + fileView->setMinimumWidth(320); fileView->setModel(fileSystemModel); fileView->setIconSize(QSize(16, 16)); browseLayout->addWidget(fileView);