Update to bsnes v060 release.

This is a long-term stable release. A full changelog will be available at the forum link below later in the day. Also, please note that I have merged all of the various distributions into two packages. The Windows binary package now contains both the profile-optimized (fast) build, and the debugger build. The source code package now contains sources for bsnes, snesreader, snesfilter and supergameboy.
Changelog:
    - added Direct3D HLSL pixel shader support [mudlord]
    - fixed a signal issue that caused loading games to take 1-2 seconds longer in v059
    - 21fx API revised to its final form, S-MSU (public documentation pending)
    - worked around QTBUG-7188 to fix multi-file 7-zip file listbox to update when scrolling
    - added scale max - normal, wide, and wide zoom modes to fullscreen mode
    - added overscan cropping tool (needed for wide zoom mode; useful for developers simulating games on a real TV)
    - added "go up one folder" button to file load dialog
    - added group (un)assignment to the input settings window
    - now honors input.allowInvalidInput setting; defaults to false [Jonas Quinn]
    - cheat code editor grays out empty slots
    - cheat code editor adds "clear selected" button to quickly erase multiple cheat codes
    - to load folders as game images, folders must end in .sfc, .bs, .st, .gb now
    - debugger: added S-CPU (H)DMA registers; S-SMP registers; S-DSP registers to properties list
    - snesfilter: HQ2x filter is now multi-threaded (scales infinitely: the more cores you have, the less overhead required)
    - pixelshaders: added screen curvature shader to simulate curved CRT tubes
    - source: lots of code cleanup, as always
This commit is contained in:
byuu 2010-02-09 00:58:03 +00:00
parent a9943ab4f4
commit a8263afc24
56 changed files with 979 additions and 339 deletions

Binary file not shown.

Binary file not shown.

BIN
bsnes.exe

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,25 @@
texture rubyTexture;
float4 vec;
sampler s0 = sampler_state { texture = <rubyTexture>; };
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(); }
}

View File

@ -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;
}

26
pixelshaders/HQ2x/vertex Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,8 @@
//Pixellate shader
//license: GPL
//author: Fes
void main() {
gl_Position = ftransform();
gl_TexCoord[0] = gl_MultiTexCoord0;
}

View File

@ -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;
}

View File

@ -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
}

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,8 @@
#ifndef NALL_PLATFORM_HPP
#define NALL_PLATFORM_HPP
#include <nall/utf8.hpp>
//=========================
//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)

View File

@ -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))

View File

@ -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);

Binary file not shown.

View File

@ -1,6 +1,8 @@
#ifndef NALL_PLATFORM_HPP
#define NALL_PLATFORM_HPP
#include <nall/utf8.hpp>
//=========================
//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)

View File

@ -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))

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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))

View File

@ -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);

View File

@ -1,10 +1,14 @@
#undef interface
#define interface struct
#include <d3d9.h>
#include <d3dx9.h>
#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<const char*>(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<D3DPOOL>(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<D3DPOOL>(flags.t_pool), &texture, NULL);
}
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);
}
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);
}
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,23 +268,53 @@ 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;
}
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<D3DTEXTUREFILTERTYPE>(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();
}
if(settings.synchronize) {
while(true) {
@ -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;

View File

@ -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];

View File

@ -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;

View File

@ -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();

View File

@ -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)) {
unsigned size = file::size(filename);
string text;
text << "<small><table>";
text << "<tr><td><b>Title: </b></td><td>" << info.name << "</td></tr>";
text << "<tr><td><b>Region: </b></td><td>" << info.region << "</td></tr>";
text << "<tr><td><b>ROM: </b></td><td>" << info.romSize * 8 / 1024 / 1024 << "mbit</td></tr>";
text << "<tr><td><b>RAM: </b></td><td>";
info.ramSize ? text << info.ramSize * 8 / 1024 << "kbit</td></tr>" : text << "None</td></tr>";
text << "</table></small>";
previewInfo->setText(text);
}
string info;
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(file::exists(filename)) {
if(striend(filename, ".sfc")) {
Cartridge::Information cartinfo;
if(cartridge.information(filename, cartinfo)) {
info << "<small><table>";
info << "<tr><td><b>Title: </b></td><td>" << cartinfo.name << "</td></tr>";
info << "<tr><td><b>Region: </b></td><td>" << cartinfo.region << "</td></tr>";
info << "<tr><td><b>ROM: </b></td><td>" << cartinfo.romSize * 8 / 1024 / 1024 << "mbit</td></tr>";
info << "<tr><td><b>RAM: </b></td><td>";
cartinfo.ramSize ? info << cartinfo.ramSize * 8 / 1024 << "kbit</td></tr>" : info << "None</td></tr>";
info << "</table></small>";
}
} else if(striend(filename, ".st")) {
unsigned size = file::size(filename);
info << "<small><table>";
info << "<tr><td><b>ROM: </b></td><td>" << size * 8 / 1024 / 1024 << "mbit</td></tr>";
info << "</table></small>";
}
}
if(info == "") info = "<small><font color='#808080'>No preview available</font></small>";
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);
}
}

View File

@ -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;

View File

@ -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,7 +313,7 @@ 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);
@ -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);
@ -490,6 +506,9 @@ 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(); }

View File

@ -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();

View File

@ -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");

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -4,6 +4,11 @@ class SettingsWindow : public Window {
public:
QVBoxLayout *layout;
QTabWidget *tab;
QScrollArea *videoArea;
QScrollArea *audioArea;
QScrollArea *inputArea;
QScrollArea *pathArea;
QScrollArea *advancedArea;
SettingsWindow();

View File

@ -8,58 +8,61 @@ VideoSettingsWindow::VideoSettingsWindow() {
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
sliders = new QGridLayout;
layout->addLayout(sliders);
colorLabel = new QLabel("<b>Color Adjustment</b>");
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("<b>Overscan Compensation</b>");
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("<b>Pixel Shader</b>");
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();
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -4,6 +4,9 @@ class ToolsWindow : public Window {
public:
QVBoxLayout *layout;
QTabWidget *tab;
QScrollArea *cheatEditorArea;
QScrollArea *cheatFinderArea;
QScrollArea *stateManagerArea;
ToolsWindow();

View File

@ -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"

View File

@ -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;
}
if(config().video.isFullscreen == false) {
//get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
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, deskRect.height()); //- frameHeight);
constrainSize(width, height, deskRect.width()); //- frameWidth );
constrainSize(height, width, screenHeight);
constrainSize(width, height, screenWidth);
if(config().video.isFullscreen == false) {
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:

Binary file not shown.

View File

@ -1,6 +1,8 @@
#ifndef NALL_PLATFORM_HPP
#define NALL_PLATFORM_HPP
#include <nall/utf8.hpp>
//=========================
//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)

View File

@ -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))

View File

@ -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);