From 6f919c64a7fdd93ace26e6c28cf30181cebb9d40 Mon Sep 17 00:00:00 2001 From: zeromus Date: Sun, 20 Jul 2014 06:51:31 +0000 Subject: [PATCH] client sizing / AR revisions --- .../DisplayManager/DisplayManager.cs | 115 ++++++++++++--- .../DisplayManager/Filters/Gui.cs | 132 +++++++++--------- .../config/DisplayConfigLite.Designer.cs | 6 +- 3 files changed, 160 insertions(+), 93 deletions(-) diff --git a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs index 8a2f1c6bb2..cc33871f4f 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs @@ -291,18 +291,101 @@ namespace BizHawk.Client.EmuHawk /// 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; } diff --git a/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs b/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs index abe0e45356..b6a203457f 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/Filters/Gui.cs @@ -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; diff --git a/BizHawk.Client.EmuHawk/config/DisplayConfigLite.Designer.cs b/BizHawk.Client.EmuHawk/config/DisplayConfigLite.Designer.cs index b33de12ebd..35f36708b9 100644 --- a/BizHawk.Client.EmuHawk/config/DisplayConfigLite.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/DisplayConfigLite.Designer.cs @@ -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";