client sizing / AR revisions
This commit is contained in:
parent
20fb404d2e
commit
6f919c64a7
|
@ -291,18 +291,101 @@ namespace BizHawk.Client.EmuHawk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Size CalculateClientSize(IVideoProvider videoProvider, int zoom)
|
public Size CalculateClientSize(IVideoProvider videoProvider, int zoom)
|
||||||
{
|
{
|
||||||
var fvp = new FakeVideoProvider ();
|
int bufferWidth = videoProvider.BufferWidth;
|
||||||
fvp.BufferWidth = videoProvider.BufferWidth;
|
int bufferHeight = videoProvider.BufferHeight;
|
||||||
fvp.BufferHeight = videoProvider.BufferHeight;
|
int virtualWidth = videoProvider.VirtualWidth;
|
||||||
fvp.VirtualWidth = videoProvider.VirtualWidth;
|
int virtualHeight = videoProvider.VirtualHeight;
|
||||||
fvp.VirtualHeight = videoProvider.VirtualHeight;
|
|
||||||
|
//test
|
||||||
|
//Console.WriteLine("DISPZOOM " + zoom);
|
||||||
|
|
||||||
|
//old stuff
|
||||||
|
var fvp = new FakeVideoProvider();
|
||||||
|
fvp.BufferWidth = bufferWidth;
|
||||||
|
fvp.BufferHeight = bufferHeight;
|
||||||
|
fvp.VirtualWidth = virtualWidth;
|
||||||
|
fvp.VirtualHeight = virtualHeight;
|
||||||
|
|
||||||
Size chain_outsize = new Size(fvp.BufferWidth * zoom, fvp.BufferHeight * zoom);
|
Size chain_outsize = new Size(fvp.BufferWidth * zoom, fvp.BufferHeight * zoom);
|
||||||
|
|
||||||
//zero 27-may-2014 - this code is now slightly suspicious.. but no proof we need to get rid of it
|
bool ar_active = Global.Config.DispFixAspectRatio;
|
||||||
//zero 02-jun-2014 - now, I suspect it is more important
|
bool ar_system = Global.Config.DispObeyAR;
|
||||||
if (Global.Config.DispObeyAR && Global.Config.DispFixAspectRatio)
|
bool ar_unity = !ar_system;
|
||||||
chain_outsize = new Size(fvp.VirtualWidth * zoom, fvp.VirtualHeight * zoom);
|
bool ar_integer = Global.Config.DispFixScaleInteger;
|
||||||
|
|
||||||
|
if (ar_active)
|
||||||
|
{
|
||||||
|
if (ar_system)
|
||||||
|
{
|
||||||
|
if (ar_integer)
|
||||||
|
{
|
||||||
|
Vector2 VS = new Vector2(virtualWidth, virtualHeight);
|
||||||
|
Vector2 BS = new Vector2(bufferWidth, bufferHeight);
|
||||||
|
Vector2 AR = Vector2.Divide(VS, BS);
|
||||||
|
float target_par = (AR.X / AR.Y);
|
||||||
|
Vector2 PS = new Vector2(1, 1); //this would malfunction for AR <= 0.5 or AR >= 2.0
|
||||||
|
|
||||||
|
//here's how we define zooming, in this case:
|
||||||
|
//make sure each step is an increment of zoom for at least one of the dimensions (or maybe both of them)
|
||||||
|
//look for the increment which helps the AR the best
|
||||||
|
//TODO - this cant possibly support scale factors like 1.5x
|
||||||
|
//TODO - also, this might be messing up zooms and stuff, we might need to run this on the output size of the filter chain
|
||||||
|
for (int i = 1; i < zoom;i++)
|
||||||
|
{
|
||||||
|
//would not be good to run this per frame, but it seems to only run when the resolution changes, etc.
|
||||||
|
Vector2[] trials = new [] {
|
||||||
|
PS + new Vector2(1, 0),
|
||||||
|
PS + new Vector2(0, 1),
|
||||||
|
PS + new Vector2(1, 1)
|
||||||
|
};
|
||||||
|
int bestIndex = -1;
|
||||||
|
float bestValue = 1000.0f;
|
||||||
|
for (int t = 0; t < trials.Length; t++)
|
||||||
|
{
|
||||||
|
//I.
|
||||||
|
float test_ar = trials[t].X / trials[t].Y;
|
||||||
|
|
||||||
|
//II.
|
||||||
|
//Vector2 calc = Vector2.Multiply(trials[t], VS);
|
||||||
|
//float test_ar = calc.X / calc.Y;
|
||||||
|
|
||||||
|
//not clear which approach is superior
|
||||||
|
float deviation_linear = Math.Abs(test_ar - target_par);
|
||||||
|
float deviation_geom = test_ar / target_par;
|
||||||
|
if (deviation_geom < 1) deviation_geom = 1.0f / deviation_geom;
|
||||||
|
|
||||||
|
float value = deviation_linear;
|
||||||
|
if (value < bestValue)
|
||||||
|
{
|
||||||
|
bestIndex = t;
|
||||||
|
bestValue = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//is it possible to get here without selecting one? doubtful.
|
||||||
|
PS = trials[bestIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
chain_outsize = new Size((int)(bufferWidth * PS.X), (int)(bufferHeight * PS.Y));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//obey the AR, but allow free scaling: just zoom the virtual size
|
||||||
|
chain_outsize = new Size(virtualWidth * zoom, virtualHeight * zoom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//ar_unity:
|
||||||
|
//just choose to zoom the buffer (make no effort to incorporate AR)
|
||||||
|
chain_outsize = new Size(bufferWidth * zoom, bufferHeight * zoom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//!ar_active:
|
||||||
|
//just choose to zoom the buffer (make no effort to incorporate AR)
|
||||||
|
chain_outsize = new Size(bufferWidth * zoom, bufferHeight * zoom);
|
||||||
|
}
|
||||||
|
|
||||||
var job = new JobInfo
|
var job = new JobInfo
|
||||||
{
|
{
|
||||||
|
@ -313,20 +396,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
var filterProgram = UpdateSourceInternal(job);
|
var filterProgram = UpdateSourceInternal(job);
|
||||||
|
|
||||||
var size = filterProgram.Filters[filterProgram.Filters.Count - 1].FindOutput().SurfaceFormat.Size;
|
var size = filterProgram.Filters[filterProgram.Filters.Count - 1].FindOutput().SurfaceFormat.Size;
|
||||||
|
|
||||||
//zero 22-may-2014 - added this to combat problem where nes would default to having sidebars
|
|
||||||
//this would use the actual chain output size. this is undesireable, in the following scenario:
|
|
||||||
//load a nes game at 2x with system-preferred and integer AR enabled, and there will be sidebars.
|
|
||||||
//the sidebars were created by this, so we can peek into it and remove the sidebars.
|
|
||||||
//Only do this if integer fixing is enabled, since only in that case do we have discardable sidebars.
|
|
||||||
//Otherwise discarding the 'sidebars' would result in cropping image.
|
|
||||||
//This is getting complicated..
|
|
||||||
if (Global.Config.DispFixScaleInteger)
|
|
||||||
{
|
|
||||||
var fp = filterProgram["presentation"] as Filters.FinalPresentation;
|
|
||||||
size = fp.GetContentSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Console.WriteLine("Selecting size " + size.ToString());
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,11 @@ namespace BizHawk.Client.EmuHawk.Filters
|
||||||
|
|
||||||
float widthScale = (float)targetWidth / sourceWidth;
|
float widthScale = (float)targetWidth / sourceWidth;
|
||||||
float heightScale = (float)targetHeight / sourceHeight;
|
float heightScale = (float)targetHeight / sourceHeight;
|
||||||
//zero 22-may-2014 - added this to combat problem where nes would default to having sidebars
|
|
||||||
if (Global.Config.DispFixScaleInteger)
|
if (maintainAspect
|
||||||
{
|
//zero 20-jul-2014 - hacks upon hacks, this function needs rewriting
|
||||||
widthScale = (float)targetWidth / textureSize.Width;
|
&& !maintainInteger
|
||||||
heightScale = (float)targetHeight / textureSize.Height;
|
)
|
||||||
}
|
|
||||||
|
|
||||||
if (maintainAspect)
|
|
||||||
{
|
{
|
||||||
if (widthScale > heightScale) widthScale = heightScale;
|
if (widthScale > heightScale) widthScale = heightScale;
|
||||||
if (heightScale > widthScale) heightScale = widthScale;
|
if (heightScale > widthScale) heightScale = widthScale;
|
||||||
|
@ -67,73 +64,72 @@ namespace BizHawk.Client.EmuHawk.Filters
|
||||||
|
|
||||||
if (maintainInteger)
|
if (maintainInteger)
|
||||||
{
|
{
|
||||||
//don't distort the original texture
|
//just totally different code
|
||||||
float apparentWidth = sourceWidth * widthScale;
|
//apply the zooming algorithm (pasted and reworked, for now)
|
||||||
float apparentHeight = sourceHeight * heightScale;
|
|
||||||
widthScale = (apparentWidth / textureWidth);
|
|
||||||
heightScale = (apparentHeight / textureHeight);
|
|
||||||
|
|
||||||
//zero 27-may-2014 - no longer relevant, but this is sneaky, so leaving it as a reminder for now
|
Vector2 VS = new Vector2(virtualWidth, virtualHeight);
|
||||||
//prevent dysfunctional reduction to 0x
|
Vector2 BS = new Vector2(textureWidth, textureHeight);
|
||||||
//if (widthScale == 0) widthScale = 1;
|
Vector2 AR = Vector2.Divide(VS, BS);
|
||||||
//if (heightScale == 0) heightScale = 1;
|
float target_par = (AR.X / AR.Y);
|
||||||
|
Vector2 PS = new Vector2(1, 1); //this would malfunction for AR <= 0.5 or AR >= 2.0
|
||||||
REDO:
|
|
||||||
|
|
||||||
apparentWidth = textureWidth * widthScale;
|
for(;;)
|
||||||
apparentHeight = textureHeight * heightScale;
|
|
||||||
|
|
||||||
//in case we've exaggerated the aspect ratio too far beyond the goal by our blunt integerizing, heres a chance to fix it by reducing one of the dimensions
|
|
||||||
float goalAr = ((float)virtualWidth)/virtualHeight;
|
|
||||||
float haveAr = apparentWidth / apparentHeight;
|
|
||||||
if (widthScale>1)
|
|
||||||
{
|
{
|
||||||
//try truncating this scale, or reducing it by 1 if it's already truncated
|
//TODO - would be good not to run this per frame....
|
||||||
float floored = (float)Math.Floor(widthScale);
|
Vector2[] trials = new[] {
|
||||||
float next;
|
PS + new Vector2(1, 0),
|
||||||
if (widthScale == floored)
|
PS + new Vector2(0, 1),
|
||||||
next = widthScale - 1;
|
PS + new Vector2(1, 1)
|
||||||
else next = floored;
|
};
|
||||||
|
bool[] trials_limited = new bool[3] { false,false,false};
|
||||||
float tryAnotherAR = (next*textureWidth)/(heightScale*textureHeight);
|
int bestIndex = -1;
|
||||||
if(Math.Abs(tryAnotherAR-goalAr) < Math.Abs(haveAr-goalAr))
|
float bestValue = 1000.0f;
|
||||||
|
for (int t = 0; t < trials.Length; t++)
|
||||||
{
|
{
|
||||||
widthScale = next;
|
Vector2 vTrial = trials[t];
|
||||||
goto REDO;
|
trials_limited[t] = false;
|
||||||
|
|
||||||
|
//check whether this is going to exceed our allotted area
|
||||||
|
int test_vw = (int)(vTrial.X * textureWidth);
|
||||||
|
int test_vh = (int)(vTrial.Y * textureHeight);
|
||||||
|
if (test_vw > targetWidth) trials_limited[t] = true;
|
||||||
|
if (test_vh > targetHeight) trials_limited[t] = true;
|
||||||
|
|
||||||
|
//I.
|
||||||
|
float test_ar = vTrial.X / vTrial.Y;
|
||||||
|
|
||||||
|
//II.
|
||||||
|
//Vector2 calc = Vector2.Multiply(trials[t], VS);
|
||||||
|
//float test_ar = calc.X / calc.Y;
|
||||||
|
|
||||||
|
//not clear which approach is superior
|
||||||
|
float deviation_linear = Math.Abs(test_ar - target_par);
|
||||||
|
float deviation_geom = test_ar / target_par;
|
||||||
|
if (deviation_geom < 1) deviation_geom = 1.0f / deviation_geom;
|
||||||
|
|
||||||
|
float value = deviation_linear;
|
||||||
|
if (value < bestValue)
|
||||||
|
{
|
||||||
|
bestIndex = t;
|
||||||
|
bestValue = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (heightScale > 1)
|
|
||||||
{
|
|
||||||
//try truncating this scale, or reducing it by 1 if it's already truncated
|
|
||||||
float floored = (float)Math.Floor(heightScale);
|
|
||||||
float next;
|
|
||||||
if (heightScale == floored)
|
|
||||||
next = heightScale - 1;
|
|
||||||
else next = floored;
|
|
||||||
|
|
||||||
float tryAnotherAR = (widthScale*textureWidth) / (next*textureHeight);
|
//last result was best, so bail out
|
||||||
if (Math.Abs(tryAnotherAR - goalAr) < Math.Abs(haveAr - goalAr))
|
if (bestIndex == -1)
|
||||||
{
|
break;
|
||||||
heightScale = next;
|
|
||||||
goto REDO;
|
//if the winner ran off the edge, bail out
|
||||||
}
|
if (trials_limited[bestIndex])
|
||||||
|
break;
|
||||||
|
|
||||||
|
PS = trials[bestIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
//we're not allowed to get out of here with non-integer scales, so if that's happened, back in for another loop we go
|
vw = (int)(PS.X * textureWidth);
|
||||||
if (Math.Floor(heightScale) != heightScale && heightScale >= 1)
|
vh = (int)(PS.Y * textureHeight);
|
||||||
{
|
widthScale = PS.X;
|
||||||
heightScale = (float)Math.Floor(heightScale);
|
heightScale = PS.Y;
|
||||||
goto REDO;
|
|
||||||
}
|
|
||||||
if (Math.Floor(widthScale) != widthScale && widthScale >= 1)
|
|
||||||
{
|
|
||||||
widthScale = (float)Math.Floor(widthScale);
|
|
||||||
goto REDO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vw = (int)(widthScale * textureWidth);
|
|
||||||
vh = (int)(heightScale * textureHeight);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -141,7 +137,7 @@ namespace BizHawk.Client.EmuHawk.Filters
|
||||||
vh = (int)(heightScale * sourceHeight);
|
vh = (int)(heightScale * sourceHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//determine letterboxing parameters
|
||||||
vx = (targetWidth - vw) / 2;
|
vx = (targetWidth - vw) / 2;
|
||||||
vy = (targetHeight - vh) / 2;
|
vy = (targetHeight - vh) / 2;
|
||||||
WidthScale = widthScale;
|
WidthScale = widthScale;
|
||||||
|
|
|
@ -255,10 +255,10 @@
|
||||||
this.rbUseSystem.AutoSize = true;
|
this.rbUseSystem.AutoSize = true;
|
||||||
this.rbUseSystem.Location = new System.Drawing.Point(6, 42);
|
this.rbUseSystem.Location = new System.Drawing.Point(6, 42);
|
||||||
this.rbUseSystem.Name = "rbUseSystem";
|
this.rbUseSystem.Name = "rbUseSystem";
|
||||||
this.rbUseSystem.Size = new System.Drawing.Size(167, 17);
|
this.rbUseSystem.Size = new System.Drawing.Size(320, 17);
|
||||||
this.rbUseSystem.TabIndex = 12;
|
this.rbUseSystem.TabIndex = 12;
|
||||||
this.rbUseSystem.TabStop = true;
|
this.rbUseSystem.TabStop = true;
|
||||||
this.rbUseSystem.Text = "Use system\'s recommendation";
|
this.rbUseSystem.Text = "Use system\'s recommendation (e.g. 2x1 pixels, for better AR fit)";
|
||||||
this.rbUseSystem.UseVisualStyleBackColor = true;
|
this.rbUseSystem.UseVisualStyleBackColor = true;
|
||||||
this.rbUseSystem.CheckedChanged += new System.EventHandler(this.rbUseSystem_CheckedChanged);
|
this.rbUseSystem.CheckedChanged += new System.EventHandler(this.rbUseSystem_CheckedChanged);
|
||||||
//
|
//
|
||||||
|
@ -268,7 +268,7 @@
|
||||||
this.grpARSelection.Controls.Add(this.rbUseSystem);
|
this.grpARSelection.Controls.Add(this.rbUseSystem);
|
||||||
this.grpARSelection.Location = new System.Drawing.Point(21, 177);
|
this.grpARSelection.Location = new System.Drawing.Point(21, 177);
|
||||||
this.grpARSelection.Name = "grpARSelection";
|
this.grpARSelection.Name = "grpARSelection";
|
||||||
this.grpARSelection.Size = new System.Drawing.Size(264, 71);
|
this.grpARSelection.Size = new System.Drawing.Size(342, 71);
|
||||||
this.grpARSelection.TabIndex = 13;
|
this.grpARSelection.TabIndex = 13;
|
||||||
this.grpARSelection.TabStop = false;
|
this.grpARSelection.TabStop = false;
|
||||||
this.grpARSelection.Text = "Aspect Ratio Selection";
|
this.grpARSelection.Text = "Aspect Ratio Selection";
|
||||||
|
|
Loading…
Reference in New Issue