client sizing / AR revisions

This commit is contained in:
zeromus 2014-07-20 06:51:31 +00:00
parent 20fb404d2e
commit 6f919c64a7
3 changed files with 160 additions and 93 deletions

View File

@ -291,18 +291,101 @@ namespace BizHawk.Client.EmuHawk
/// </summary>
public Size CalculateClientSize(IVideoProvider videoProvider, int zoom)
{
var fvp = new FakeVideoProvider ();
fvp.BufferWidth = videoProvider.BufferWidth;
fvp.BufferHeight = videoProvider.BufferHeight;
fvp.VirtualWidth = videoProvider.VirtualWidth;
fvp.VirtualHeight = videoProvider.VirtualHeight;
int bufferWidth = videoProvider.BufferWidth;
int bufferHeight = videoProvider.BufferHeight;
int virtualWidth = videoProvider.VirtualWidth;
int 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);
//zero 27-may-2014 - this code is now slightly suspicious.. but no proof we need to get rid of it
//zero 02-jun-2014 - now, I suspect it is more important
if (Global.Config.DispObeyAR && Global.Config.DispFixAspectRatio)
chain_outsize = new Size(fvp.VirtualWidth * zoom, fvp.VirtualHeight * zoom);
bool ar_active = Global.Config.DispFixAspectRatio;
bool ar_system = Global.Config.DispObeyAR;
bool ar_unity = !ar_system;
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
{
@ -313,20 +396,8 @@ namespace BizHawk.Client.EmuHawk
var filterProgram = UpdateSourceInternal(job);
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;
}

View File

@ -52,14 +52,11 @@ namespace BizHawk.Client.EmuHawk.Filters
float widthScale = (float)targetWidth / sourceWidth;
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)
{
widthScale = (float)targetWidth / textureSize.Width;
heightScale = (float)targetHeight / textureSize.Height;
}
if (maintainAspect)
if (maintainAspect
//zero 20-jul-2014 - hacks upon hacks, this function needs rewriting
&& !maintainInteger
)
{
if (widthScale > heightScale) widthScale = heightScale;
if (heightScale > widthScale) heightScale = widthScale;
@ -67,73 +64,72 @@ namespace BizHawk.Client.EmuHawk.Filters
if (maintainInteger)
{
//don't distort the original texture
float apparentWidth = sourceWidth * widthScale;
float apparentHeight = sourceHeight * heightScale;
widthScale = (apparentWidth / textureWidth);
heightScale = (apparentHeight / textureHeight);
//just totally different code
//apply the zooming algorithm (pasted and reworked, for now)
//zero 27-may-2014 - no longer relevant, but this is sneaky, so leaving it as a reminder for now
//prevent dysfunctional reduction to 0x
//if (widthScale == 0) widthScale = 1;
//if (heightScale == 0) heightScale = 1;
REDO:
Vector2 VS = new Vector2(virtualWidth, virtualHeight);
Vector2 BS = new Vector2(textureWidth, textureHeight);
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
apparentWidth = textureWidth * widthScale;
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)
for(;;)
{
//try truncating this scale, or reducing it by 1 if it's already truncated
float floored = (float)Math.Floor(widthScale);
float next;
if (widthScale == floored)
next = widthScale - 1;
else next = floored;
float tryAnotherAR = (next*textureWidth)/(heightScale*textureHeight);
if(Math.Abs(tryAnotherAR-goalAr) < Math.Abs(haveAr-goalAr))
//TODO - would be good not to run this per frame....
Vector2[] trials = new[] {
PS + new Vector2(1, 0),
PS + new Vector2(0, 1),
PS + new Vector2(1, 1)
};
bool[] trials_limited = new bool[3] { false,false,false};
int bestIndex = -1;
float bestValue = 1000.0f;
for (int t = 0; t < trials.Length; t++)
{
widthScale = next;
goto REDO;
Vector2 vTrial = trials[t];
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);
if (Math.Abs(tryAnotherAR - goalAr) < Math.Abs(haveAr - goalAr))
{
heightScale = next;
goto REDO;
}
//last result was best, so bail out
if (bestIndex == -1)
break;
//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
if (Math.Floor(heightScale) != heightScale && heightScale >= 1)
{
heightScale = (float)Math.Floor(heightScale);
goto REDO;
}
if (Math.Floor(widthScale) != widthScale && widthScale >= 1)
{
widthScale = (float)Math.Floor(widthScale);
goto REDO;
}
vw = (int)(widthScale * textureWidth);
vh = (int)(heightScale * textureHeight);
vw = (int)(PS.X * textureWidth);
vh = (int)(PS.Y * textureHeight);
widthScale = PS.X;
heightScale = PS.Y;
}
else
{
@ -141,7 +137,7 @@ namespace BizHawk.Client.EmuHawk.Filters
vh = (int)(heightScale * sourceHeight);
}
//determine letterboxing parameters
vx = (targetWidth - vw) / 2;
vy = (targetHeight - vh) / 2;
WidthScale = widthScale;

View File

@ -255,10 +255,10 @@
this.rbUseSystem.AutoSize = true;
this.rbUseSystem.Location = new System.Drawing.Point(6, 42);
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.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.CheckedChanged += new System.EventHandler(this.rbUseSystem_CheckedChanged);
//
@ -268,7 +268,7 @@
this.grpARSelection.Controls.Add(this.rbUseSystem);
this.grpARSelection.Location = new System.Drawing.Point(21, 177);
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.TabStop = false;
this.grpARSelection.Text = "Aspect Ratio Selection";