Create a new project to house the IGL WinForms controls (Bizware.Graphics.Controls), thus allowing for Bizware.Graphics to be netstandard2.0
also move GDIPlus IGL stuff over from BizwareGL to Bizware.Graphics
This commit is contained in:
parent
9139870e7e
commit
72cc192661
|
@ -27,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.Bizware.Input", "sr
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.Bizware.Graphics", "src\BizHawk.Bizware.Graphics\BizHawk.Bizware.Graphics.csproj", "{368BC91D-48CD-492A-B6CF-B5B77F7FE7D4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.Bizware.Graphics.Controls", "src\BizHawk.Bizware.Graphics.Controls\BizHawk.Bizware.Graphics.Controls.csproj", "{3D050D35-B57D-4D14-BE0F-FD63552DADB0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.Bizware.BizwareGL", "src\BizHawk.Bizware.BizwareGL\BizHawk.Bizware.BizwareGL.csproj", "{658BB7AA-74A1-496F-A6AA-B7D3DD9C7CBE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.BizInvoke", "src\BizHawk.BizInvoke\BizHawk.BizInvoke.csproj", "{E5D76DC1-84A8-47AF-BE25-E76F06D2FBBC}"
|
||||
|
@ -83,6 +85,10 @@ Global
|
|||
{368BC91D-48CD-492A-B6CF-B5B77F7FE7D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{368BC91D-48CD-492A-B6CF-B5B77F7FE7D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{368BC91D-48CD-492A-B6CF-B5B77F7FE7D4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D050D35-B57D-4D14-BE0F-FD63552DADB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D050D35-B57D-4D14-BE0F-FD63552DADB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D050D35-B57D-4D14-BE0F-FD63552DADB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D050D35-B57D-4D14-BE0F-FD63552DADB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{658BB7AA-74A1-496F-A6AA-B7D3DD9C7CBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{658BB7AA-74A1-496F-A6AA-B7D3DD9C7CBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{658BB7AA-74A1-496F-A6AA-B7D3DD9C7CBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
|
@ -270,7 +270,5 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// Frees the provided vertex layout. For internal use only.
|
||||
/// </summary>
|
||||
void Internal_FreeVertexLayout(VertexLayout vertexLayout);
|
||||
|
||||
IGraphicsControl Internal_CreateGraphicsControl();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
#if false
|
||||
using System.Drawing.Drawing2D;
|
||||
#endif
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
{
|
||||
public class RenderTargetWrapper : IDisposable
|
||||
{
|
||||
public RenderTargetWrapper(
|
||||
Func<BufferedGraphicsContext> getBufferedGraphicsContext,
|
||||
IGraphicsControl control = null)
|
||||
{
|
||||
_getBufferedGraphicsContext = getBufferedGraphicsContext;
|
||||
Control = control;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
MyBufferedGraphics?.Dispose();
|
||||
}
|
||||
|
||||
private readonly Func<BufferedGraphicsContext> _getBufferedGraphicsContext;
|
||||
|
||||
/// <summary>
|
||||
/// the control associated with this render target (if any)
|
||||
/// </summary>
|
||||
private readonly IGraphicsControl Control;
|
||||
|
||||
/// <summary>
|
||||
/// the offscreen render target, if that's what this is representing
|
||||
/// </summary>
|
||||
public RenderTarget Target;
|
||||
|
||||
public BufferedGraphics MyBufferedGraphics;
|
||||
|
||||
public Graphics refGraphics; // ?? hacky?
|
||||
|
||||
public void CreateGraphics()
|
||||
{
|
||||
Rectangle r;
|
||||
if (Control != null)
|
||||
{
|
||||
r = Control.ClientRectangle;
|
||||
refGraphics = Control.CreateGraphics();
|
||||
}
|
||||
else
|
||||
{
|
||||
var tw = (GDIPTextureWrapper)Target.Texture2d.Opaque;
|
||||
r = Target.Texture2d.Rectangle;
|
||||
refGraphics = Graphics.FromImage(tw.SDBitmap);
|
||||
}
|
||||
|
||||
MyBufferedGraphics?.Dispose();
|
||||
MyBufferedGraphics = _getBufferedGraphicsContext().Allocate(refGraphics, r);
|
||||
#if false
|
||||
MyBufferedGraphics.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
|
||||
|
||||
// not sure about this stuff...
|
||||
// it will wreck alpha blending, for one thing
|
||||
MyBufferedGraphics.Graphics.CompositingMode = CompositingMode.SourceCopy;
|
||||
MyBufferedGraphics.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<Import Project="../MainSlnCommon.props" />
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Nullable>disable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Graphics/BizHawk.Bizware.Graphics.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics.Controls
|
||||
{
|
||||
internal sealed class D3D9Control : GraphicsControl
|
||||
{
|
||||
private readonly Func<IntPtr, D3D9SwapChain> _createSwapChain;
|
||||
private D3D9SwapChain _swapChain;
|
||||
private bool Vsync;
|
||||
|
||||
public D3D9Control(Func<IntPtr, D3D9SwapChain> createSwapChain)
|
||||
{
|
||||
_createSwapChain = createSwapChain;
|
||||
|
||||
SetStyle(ControlStyles.Opaque, true);
|
||||
SetStyle(ControlStyles.UserPaint, true);
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||
SetStyle(ControlStyles.UserMouse, true);
|
||||
DoubleBuffered = false;
|
||||
}
|
||||
|
||||
protected override Size DefaultSize => new(1, 1);
|
||||
|
||||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
base.OnHandleCreated(e);
|
||||
_swapChain = _createSwapChain(Handle);
|
||||
}
|
||||
|
||||
protected override void OnHandleDestroyed(EventArgs e)
|
||||
{
|
||||
base.OnHandleDestroyed(e);
|
||||
_swapChain.Dispose();
|
||||
_swapChain = null;
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
_swapChain.Refresh(Vsync);
|
||||
}
|
||||
|
||||
public override void SetVsync(bool state)
|
||||
{
|
||||
if (Vsync != state)
|
||||
{
|
||||
Vsync = state;
|
||||
_swapChain.Refresh(Vsync);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Begin()
|
||||
=> _swapChain.SetBackBuffer();
|
||||
|
||||
public override void End()
|
||||
=> _swapChain.SetBackBuffer();
|
||||
|
||||
public override void SwapBuffers()
|
||||
=> _swapChain.PresentBuffer();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using SDGraphics = System.Drawing.Graphics;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics.Controls
|
||||
{
|
||||
internal sealed class GDIPlusControl : GraphicsControl
|
||||
{
|
||||
public GDIPlusControl(Func<Func<(SDGraphics Graphics, Rectangle Rectangle)>, GDIPlusRenderTarget> createControlRenderTarget)
|
||||
{
|
||||
RenderTarget = createControlRenderTarget(GetControlRenderContext);
|
||||
|
||||
SetStyle(ControlStyles.UserPaint, true);
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||
SetStyle(ControlStyles.Opaque, true);
|
||||
SetStyle(ControlStyles.UserMouse, true);
|
||||
}
|
||||
|
||||
private (SDGraphics Graphics, Rectangle Rectangle) GetControlRenderContext()
|
||||
=> (CreateGraphics(), ClientRectangle);
|
||||
|
||||
/// <summary>
|
||||
/// The render target for rendering to this control
|
||||
/// </summary>
|
||||
private GDIPlusRenderTarget RenderTarget { get; }
|
||||
|
||||
public override void SetVsync(bool state)
|
||||
{
|
||||
// not really supported now...
|
||||
}
|
||||
|
||||
public override void Begin()
|
||||
=> RenderTarget.CreateGraphics();
|
||||
|
||||
public override void End()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
RenderTarget.CreateGraphics();
|
||||
}
|
||||
|
||||
public override void SwapBuffers()
|
||||
{
|
||||
if (RenderTarget.BufferedGraphics == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var g = CreateGraphics();
|
||||
// not sure we had proof we needed this but it cant hurt
|
||||
g.CompositingMode = CompositingMode.SourceCopy;
|
||||
g.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
RenderTarget.BufferedGraphics.Render(g);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +1,14 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
namespace BizHawk.Bizware.Graphics.Controls
|
||||
{
|
||||
internal class OpenGLControl : Control, IGraphicsControl
|
||||
internal sealed class OpenGLControl : GraphicsControl
|
||||
{
|
||||
public SDL2OpenGLContext Context { get; private set; }
|
||||
|
||||
public RenderTargetWrapper RenderTargetWrapper
|
||||
{
|
||||
get => throw new NotImplementedException();
|
||||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public OpenGLControl()
|
||||
{
|
||||
// according to OpenTK, these are the styles we want to set
|
||||
|
@ -75,23 +68,23 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
public void SetVsync(bool state)
|
||||
public override void SetVsync(bool state)
|
||||
{
|
||||
MakeContextCurrent();
|
||||
Context.SetVsync(state);
|
||||
}
|
||||
|
||||
public void Begin()
|
||||
public override void Begin()
|
||||
{
|
||||
MakeContextCurrent();
|
||||
}
|
||||
|
||||
public void End()
|
||||
public override void End()
|
||||
{
|
||||
SDL2OpenGLContext.MakeNoneCurrent();
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
public override void SwapBuffers()
|
||||
{
|
||||
MakeContextCurrent();
|
||||
Context.SwapBuffers();
|
|
@ -1,40 +1,32 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
namespace BizHawk.Bizware.Graphics.Controls
|
||||
{
|
||||
public interface IGraphicsControl : IDisposable
|
||||
public abstract class GraphicsControl : Control
|
||||
{
|
||||
Rectangle ClientRectangle { get; }
|
||||
|
||||
RenderTargetWrapper RenderTargetWrapper { get; set; }
|
||||
|
||||
Graphics CreateGraphics();
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether presentation operations on this control will vsync
|
||||
/// </summary>
|
||||
void SetVsync(bool state);
|
||||
public abstract void SetVsync(bool state);
|
||||
|
||||
/// <summary>
|
||||
/// Swaps the buffers for this control
|
||||
/// </summary>
|
||||
void SwapBuffers();
|
||||
public abstract void SwapBuffers();
|
||||
|
||||
/// <summary>
|
||||
/// Makes this control current for rendering operations.
|
||||
/// Note that at this time, the window size shouldn't change until End() or else something bad might happen
|
||||
/// Please be aware that this might change the rendering context, meaning that some things you set without calling Begin/End might not be affected
|
||||
/// </summary>
|
||||
void Begin();
|
||||
public abstract void Begin();
|
||||
|
||||
/// <summary>
|
||||
/// Ends rendering on the specified control.
|
||||
/// NOTE: DO NOT EXPECT TO SEE BEGIN/END CALLED IN PAIRS, STRICTLY.
|
||||
/// this is more about GL context management than anything else.
|
||||
/// See GLManager for details.
|
||||
/// In particular, don't expect to have End() called before doing certain things. Maybe use SwapBuffers instead
|
||||
/// </summary>
|
||||
void End();
|
||||
public abstract void End();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A factory for creating a GraphicsControl based on an IGL
|
||||
/// </summary>
|
||||
public static class GraphicsControlFactory
|
||||
{
|
||||
public static GraphicsControl CreateGraphicsControl(IGL gl)
|
||||
{
|
||||
GraphicsControl ret = gl switch
|
||||
{
|
||||
IGL_OpenGL => new OpenGLControl(),
|
||||
IGL_D3D9 d3d9 => new D3D9Control(d3d9.CreateSwapChain),
|
||||
IGL_GDIPlus gdiPlus => new GDIPlusControl(gdiPlus.CreateControlRenderTarget),
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
|
||||
// IGLs need the window handle in order to do things, so best create the control immediately
|
||||
ret.CreateControl();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<Import Project="../MainSlnCommon.props" />
|
||||
<PropertyGroup>
|
||||
|
@ -8,9 +8,7 @@
|
|||
<Nullable>disable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<PackageReference Include="Silk.NET.OpenGL.Legacy" Version="2.17.1" />
|
||||
<PackageReference Include="Silk.NET.OpenGL.Legacy.Extensions.EXT" Version="2.17.1" />
|
||||
<PackageReference Include="SharpDX.Direct3D9" Version="4.2.0" />
|
||||
<PackageReference Include="ppy.SDL2-CS" Version="1.0.630-alpha" ExcludeAssets="native;contentFiles" />
|
||||
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj" />
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Common;
|
||||
|
||||
using SharpDX.Direct3D9;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
internal sealed class D3D9Control : Control, IGraphicsControl
|
||||
{
|
||||
private readonly IGL_D3D9 _owner;
|
||||
internal SwapChain SwapChain;
|
||||
internal bool Vsync;
|
||||
|
||||
public D3D9Control(IGL_D3D9 owner)
|
||||
{
|
||||
_owner = owner;
|
||||
|
||||
SetStyle(ControlStyles.Opaque, true);
|
||||
SetStyle(ControlStyles.UserPaint, true);
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||
SetStyle(ControlStyles.UserMouse, true);
|
||||
DoubleBuffered = false;
|
||||
}
|
||||
|
||||
public RenderTargetWrapper RenderTargetWrapper
|
||||
{
|
||||
get => throw new NotImplementedException();
|
||||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
base.OnHandleCreated(e);
|
||||
_owner.RefreshControlSwapChain(this);
|
||||
}
|
||||
|
||||
protected override void OnHandleDestroyed(EventArgs e)
|
||||
{
|
||||
base.OnHandleDestroyed(e);
|
||||
IGL_D3D9.FreeControlSwapChain(this);
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
_owner.RefreshControlSwapChain(this);
|
||||
}
|
||||
|
||||
public void SetVsync(bool state)
|
||||
{
|
||||
Vsync = state;
|
||||
_owner.RefreshControlSwapChain(this);
|
||||
}
|
||||
|
||||
public void Begin()
|
||||
=> _owner.BeginControl(this);
|
||||
|
||||
public void End()
|
||||
=> _owner.EndControl(this);
|
||||
|
||||
public void SwapBuffers()
|
||||
=> _owner.SwapControl(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
|
||||
using SharpDX;
|
||||
using SharpDX.Direct3D9;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
public sealed class D3D9SwapChain : IDisposable
|
||||
{
|
||||
private const int D3DERR_DEVICELOST = unchecked((int)0x88760868);
|
||||
|
||||
private readonly Device _device;
|
||||
private readonly Func<PresentParameters, SwapChain> _resetDeviceCallback;
|
||||
private readonly Func<PresentParameters, SwapChain> _resetSwapChainCallback;
|
||||
|
||||
private SwapChain _swapChain;
|
||||
|
||||
internal D3D9SwapChain(Device device, SwapChain swapChain,
|
||||
Func<PresentParameters, SwapChain> resetDeviceCallback, Func<PresentParameters, SwapChain> resetSwapChainCallback)
|
||||
{
|
||||
_device = device;
|
||||
_swapChain = swapChain;
|
||||
_resetDeviceCallback = resetDeviceCallback;
|
||||
_resetSwapChainCallback = resetSwapChainCallback;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_swapChain?.Dispose();
|
||||
_swapChain = null;
|
||||
}
|
||||
|
||||
public void SetBackBuffer()
|
||||
{
|
||||
using var surface = _swapChain.GetBackBuffer(0);
|
||||
_device.SetRenderTarget(0, surface);
|
||||
_device.DepthStencilSurface = null;
|
||||
}
|
||||
|
||||
public void PresentBuffer()
|
||||
{
|
||||
SetBackBuffer();
|
||||
|
||||
try
|
||||
{
|
||||
_swapChain.Present(Present.None);
|
||||
}
|
||||
catch (SharpDXException ex)
|
||||
{
|
||||
if (ex.ResultCode.Code == D3DERR_DEVICELOST)
|
||||
{
|
||||
var pp = _swapChain.PresentParameters;
|
||||
pp.BackBufferWidth = pp.BackBufferHeight = 0;
|
||||
_swapChain = _resetDeviceCallback(pp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh(bool vsync)
|
||||
{
|
||||
var pp = _swapChain.PresentParameters;
|
||||
pp.BackBufferWidth = pp.BackBufferHeight = 0;
|
||||
pp.PresentationInterval = vsync ? PresentInterval.One : PresentInterval.Immediate;
|
||||
_swapChain = _resetSwapChainCallback(pp);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,9 +12,7 @@ using BizHawk.Bizware.BizwareGL;
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Common.StringExtensions;
|
||||
|
||||
using SharpDX;
|
||||
using SharpDX.Direct3D9;
|
||||
using SharpDX.Mathematics.Interop;
|
||||
|
||||
using static SDL2.SDL;
|
||||
|
||||
|
@ -28,17 +26,16 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
public EDispMethod DispMethodEnum => EDispMethod.D3D9;
|
||||
|
||||
private const int D3DERR_DEVICELOST = unchecked((int)0x88760868);
|
||||
private const int D3DERR_DEVICENOTRESET = unchecked((int)0x88760869);
|
||||
|
||||
private Device _device;
|
||||
private SwapChain _controlSwapchain;
|
||||
|
||||
private IntPtr _offscreenSdl2Window;
|
||||
private IntPtr OffscreenNativeWindow;
|
||||
|
||||
// rendering state
|
||||
private Pipeline _currPipeline;
|
||||
private D3D9Control _currentControl;
|
||||
|
||||
// misc state
|
||||
private CacheBlendState _rsBlendNoneVerbatim, _rsBlendNoneOpaque, _rsBlendNormal;
|
||||
|
@ -110,15 +107,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
_device = new(d3d9, 0, DeviceType.Hardware, pp.DeviceWindowHandle, flags, pp);
|
||||
}
|
||||
|
||||
private void DestroyDevice()
|
||||
{
|
||||
if (_device != null)
|
||||
{
|
||||
_device.Dispose();
|
||||
_device = null;
|
||||
}
|
||||
}
|
||||
|
||||
private PresentParameters MakePresentParameters()
|
||||
{
|
||||
return new()
|
||||
|
@ -128,14 +116,15 @@ namespace BizHawk.Bizware.Graphics
|
|||
DeviceWindowHandle = OffscreenNativeWindow,
|
||||
Windowed = true,
|
||||
PresentationInterval = PresentInterval.Immediate,
|
||||
EnableAutoDepthStencil = false
|
||||
};
|
||||
}
|
||||
|
||||
private void ResetDevice(D3D9Control control)
|
||||
private SwapChain ResetDevice(PresentParameters swapChainPresentParameters)
|
||||
{
|
||||
SuspendRenderTargets();
|
||||
FreeControlSwapChain(control);
|
||||
_controlSwapchain.Dispose();
|
||||
|
||||
var pp = MakePresentParameters();
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
@ -149,7 +138,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
try
|
||||
{
|
||||
var pp = MakePresentParameters();
|
||||
_device.Reset(pp);
|
||||
break;
|
||||
}
|
||||
|
@ -162,19 +150,55 @@ namespace BizHawk.Bizware.Graphics
|
|||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
RefreshControlSwapChain(control);
|
||||
ResumeRenderTargets();
|
||||
_controlSwapchain = new(_device, swapChainPresentParameters);
|
||||
|
||||
return _controlSwapchain;
|
||||
}
|
||||
|
||||
private SwapChain ResetSwapChain(PresentParameters pp)
|
||||
{
|
||||
_controlSwapchain.Dispose();
|
||||
_controlSwapchain = new(_device, pp);
|
||||
return _controlSwapchain;
|
||||
}
|
||||
|
||||
public D3D9SwapChain CreateSwapChain(IntPtr handle)
|
||||
{
|
||||
if (_controlSwapchain != null)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(IGL_D3D9)} can only have 1 control swap chain");
|
||||
}
|
||||
|
||||
var pp = new PresentParameters
|
||||
{
|
||||
BackBufferCount = 1,
|
||||
BackBufferFormat = Format.X8R8G8B8,
|
||||
SwapEffect = SwapEffect.Discard,
|
||||
DeviceWindowHandle = handle,
|
||||
Windowed = true,
|
||||
PresentationInterval = PresentInterval.Immediate
|
||||
};
|
||||
|
||||
_controlSwapchain = new(_device, pp);
|
||||
return new(_device, _controlSwapchain, ResetDevice, ResetSwapChain);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DestroyDevice();
|
||||
if (_device != null)
|
||||
{
|
||||
_device.Dispose();
|
||||
_device = null;
|
||||
}
|
||||
|
||||
if (_offscreenSdl2Window != IntPtr.Zero)
|
||||
{
|
||||
SDL_DestroyWindow(_offscreenSdl2Window);
|
||||
_offscreenSdl2Window = OffscreenNativeWindow = IntPtr.Zero;
|
||||
}
|
||||
|
||||
_controlSwapchain = null;
|
||||
}
|
||||
|
||||
public void ClearColor(Color color)
|
||||
|
@ -670,7 +694,8 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
var tex = new Texture(_device, width, height, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
|
||||
var tw = new TextureWrapper { Texture = tex };
|
||||
return new(this, tw, width, height);
|
||||
var ret = new Texture2d(this, tw, width, height);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
|
||||
|
@ -792,46 +817,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
SetViewport(size.Width, size.Height);
|
||||
}
|
||||
|
||||
internal void BeginControl(D3D9Control control)
|
||||
{
|
||||
_currentControl = control;
|
||||
|
||||
// this dispose isn't strictly needed but it seems benign
|
||||
using var surface = control.SwapChain.GetBackBuffer(0);
|
||||
_device.SetRenderTarget(0, surface);
|
||||
}
|
||||
|
||||
/// <exception cref="InvalidOperationException"><paramref name="control"/> does not match control passed to <see cref="BeginControl"/></exception>
|
||||
internal void EndControl(D3D9Control control)
|
||||
{
|
||||
if (control != _currentControl)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(control)} does not match control passed to {nameof(BeginControl)}");
|
||||
}
|
||||
|
||||
using var surface = control.SwapChain.GetBackBuffer(0);
|
||||
_device.SetRenderTarget(0, surface);
|
||||
|
||||
_currentControl = null;
|
||||
}
|
||||
|
||||
internal void SwapControl(D3D9Control control)
|
||||
{
|
||||
EndControl(control);
|
||||
|
||||
try
|
||||
{
|
||||
control.SwapChain.Present(Present.None);
|
||||
}
|
||||
catch (SharpDXException ex)
|
||||
{
|
||||
if (ex.ResultCode.Code == D3DERR_DEVICELOST)
|
||||
{
|
||||
ResetDevice(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void FreeRenderTarget(RenderTarget rt)
|
||||
{
|
||||
var tw = (TextureWrapper)rt.Texture2d.Opaque;
|
||||
|
@ -850,13 +835,11 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
|
||||
private Texture CreateRenderTargetTexture(int w, int h)
|
||||
{
|
||||
return new(_device, w, h, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default);
|
||||
}
|
||||
=> new(_device, w, h, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default);
|
||||
|
||||
private void SuspendRenderTargets()
|
||||
{
|
||||
foreach (var tw in _renderTargets.Select(rt => (TextureWrapper)rt.Opaque))
|
||||
foreach (var tw in _renderTargets.Select(tex => (TextureWrapper)tex.Opaque))
|
||||
{
|
||||
tw.Texture.Dispose();
|
||||
tw.Texture = null;
|
||||
|
@ -876,52 +859,19 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
if (rt == null)
|
||||
{
|
||||
// this dispose is needed for correct device resets, I have no idea why
|
||||
// don't try caching it either
|
||||
using var surface = _currentControl.SwapChain.GetBackBuffer(0);
|
||||
_device.SetRenderTarget(0, surface);
|
||||
using var bb = _controlSwapchain.GetBackBuffer(0);
|
||||
_device.SetRenderTarget(0, bb);
|
||||
_device.DepthStencilSurface = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// dispose doesn't seem necessary for reset here...
|
||||
var tw = (TextureWrapper)rt.Opaque;
|
||||
_device.SetRenderTarget(0, tw.Texture.GetSurfaceLevel(0));
|
||||
using var texSurface = tw.Texture.GetSurfaceLevel(0);
|
||||
_device.SetRenderTarget(0, texSurface);
|
||||
_device.DepthStencilSurface = null;
|
||||
}
|
||||
|
||||
internal static void FreeControlSwapChain(D3D9Control control)
|
||||
{
|
||||
control.SwapChain?.Dispose();
|
||||
control.SwapChain = null;
|
||||
}
|
||||
|
||||
internal void RefreshControlSwapChain(D3D9Control control)
|
||||
{
|
||||
FreeControlSwapChain(control);
|
||||
|
||||
var pp = new PresentParameters
|
||||
{
|
||||
BackBufferWidth = Math.Max(1, control.ClientSize.Width),
|
||||
BackBufferHeight = Math.Max(1, control.ClientSize.Height),
|
||||
BackBufferCount = 1,
|
||||
BackBufferFormat = Format.X8R8G8B8,
|
||||
SwapEffect = SwapEffect.Discard,
|
||||
DeviceWindowHandle = control.Handle,
|
||||
Windowed = true,
|
||||
PresentationInterval = control.Vsync ? PresentInterval.One : PresentInterval.Immediate
|
||||
};
|
||||
|
||||
control.SwapChain = new(_device, pp);
|
||||
}
|
||||
|
||||
public IGraphicsControl Internal_CreateGraphicsControl()
|
||||
{
|
||||
var ret = new D3D9Control(this);
|
||||
ret.CreateControl();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private delegate void DrawPrimitiveUPDelegate(Device device, PrimitiveType primitiveType, int primitiveCount, IntPtr vertexStreamZeroDataRef, int vertexStreamZeroStride);
|
||||
|
||||
private static readonly Lazy<DrawPrimitiveUPDelegate> _drawPrimitiveUP = new(() =>
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
using SDGraphics = System.Drawing.Graphics;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
public class GDIPlusRenderTarget : IDisposable
|
||||
{
|
||||
internal GDIPlusRenderTarget(Func<BufferedGraphicsContext> getBufferedGraphicsContext,
|
||||
Func<(SDGraphics Graphics, Rectangle Rectangle)> getControlRenderContext = null)
|
||||
{
|
||||
_getBufferedGraphicsContext = getBufferedGraphicsContext;
|
||||
_getControlRenderContext = getControlRenderContext;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_getControlRenderContext != null)
|
||||
{
|
||||
CurGraphics?.Dispose();
|
||||
}
|
||||
|
||||
BufferedGraphics?.Dispose();
|
||||
}
|
||||
|
||||
private readonly Func<BufferedGraphicsContext> _getBufferedGraphicsContext;
|
||||
|
||||
/// <summary>
|
||||
/// get Graphics and Rectangle from a control, if any
|
||||
/// </summary>
|
||||
private readonly Func<(SDGraphics, Rectangle)> _getControlRenderContext;
|
||||
|
||||
/// <summary>
|
||||
/// the offscreen render target, if that's what this is representing
|
||||
/// </summary>
|
||||
public RenderTarget Target;
|
||||
|
||||
public SDGraphics CurGraphics;
|
||||
public BufferedGraphics BufferedGraphics;
|
||||
|
||||
public void CreateGraphics()
|
||||
{
|
||||
Rectangle r;
|
||||
if (_getControlRenderContext != null)
|
||||
{
|
||||
(CurGraphics, r) = _getControlRenderContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
var gtex = (GDIPlusTexture)Target.Texture2d.Opaque;
|
||||
CurGraphics?.Dispose();
|
||||
CurGraphics = SDGraphics.FromImage(gtex.SDBitmap);
|
||||
r = Target.Texture2d.Rectangle;
|
||||
}
|
||||
|
||||
BufferedGraphics?.Dispose();
|
||||
BufferedGraphics = _getBufferedGraphicsContext().Allocate(CurGraphics, r);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
public class GDIPTextureWrapper : IDisposable
|
||||
public class GDIPlusTexture : IDisposable
|
||||
{
|
||||
public Bitmap SDBitmap;
|
||||
public TextureMinFilter MinFilter = TextureMinFilter.Nearest;
|
||||
|
@ -11,11 +13,8 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
if (SDBitmap != null)
|
||||
{
|
||||
SDBitmap.Dispose();
|
||||
SDBitmap = null;
|
||||
}
|
||||
SDBitmap?.Dispose();
|
||||
SDBitmap = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,26 +4,20 @@ using System.Drawing;
|
|||
using System.Drawing.Imaging;
|
||||
using System.Numerics;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
using SDGraphics = System.Drawing.Graphics;
|
||||
|
||||
//TODO - maybe a layer to cache Graphics parameters (notably, filtering) ?
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
public class IGL_GdiPlus : IGL
|
||||
public class IGL_GDIPlus : IGL
|
||||
{
|
||||
public EDispMethod DispMethodEnum => EDispMethod.GdiPlus;
|
||||
|
||||
#if false
|
||||
// rendering state
|
||||
private RenderTarget _currRenderTarget;
|
||||
#endif
|
||||
|
||||
private readonly Func<IGL_GdiPlus, IGraphicsControl> _createGLControlWrapper;
|
||||
|
||||
public IGL_GdiPlus(Func<IGL_GdiPlus, IGraphicsControl> createGLControlWrapper)
|
||||
=> _createGLControlWrapper = createGLControlWrapper;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
MyBufferedGraphicsContext.Dispose();
|
||||
BufferedGraphicsContext.Dispose();
|
||||
}
|
||||
|
||||
public void ClearColor(Color color)
|
||||
|
@ -39,8 +33,8 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void FreeTexture(Texture2d tex)
|
||||
{
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
tw.Dispose();
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
gtex.Dispose();
|
||||
}
|
||||
|
||||
public Shader CreateFragmentShader(string source, string entry, bool required)
|
||||
|
@ -99,7 +93,6 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void SetPipelineUniform(PipelineUniform uniform, bool value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4x4 mat, bool transpose)
|
||||
|
@ -128,20 +121,19 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void SetPipelineUniformSampler(PipelineUniform uniform, Texture2d tex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetMinFilter(Texture2d texture, TextureMinFilter minFilter)
|
||||
=> ((GDIPTextureWrapper) texture.Opaque).MinFilter = minFilter;
|
||||
=> ((GDIPlusTexture) texture.Opaque).MinFilter = minFilter;
|
||||
|
||||
public void SetMagFilter(Texture2d texture, TextureMagFilter magFilter)
|
||||
=> ((GDIPTextureWrapper) texture.Opaque).MagFilter = magFilter;
|
||||
=> ((GDIPlusTexture) texture.Opaque).MagFilter = magFilter;
|
||||
|
||||
public Texture2d LoadTexture(Bitmap bitmap)
|
||||
{
|
||||
var sdBitmap = (Bitmap)bitmap.Clone();
|
||||
var tw = new GDIPTextureWrapper { SDBitmap = sdBitmap };
|
||||
return new(this, tw, bitmap.Width, bitmap.Height);
|
||||
var gtex = new GDIPlusTexture { SDBitmap = sdBitmap };
|
||||
return new(this, gtex, bitmap.Width, bitmap.Height);
|
||||
}
|
||||
|
||||
public Texture2d LoadTexture(Stream stream)
|
||||
|
@ -161,27 +153,27 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void LoadTextureData(Texture2d tex, BitmapBuffer bmp)
|
||||
{
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
bmp.ToSysdrawingBitmap(tw.SDBitmap);
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
bmp.ToSysdrawingBitmap(gtex.SDBitmap);
|
||||
}
|
||||
|
||||
public Texture2d LoadTexture(BitmapBuffer bmp)
|
||||
{
|
||||
// definitely needed (by TextureFrugalizer at least)
|
||||
var sdBitmap = bmp.ToSysdrawingBitmap();
|
||||
var tw = new GDIPTextureWrapper { SDBitmap = sdBitmap };
|
||||
return new(this, tw, bmp.Width, bmp.Height);
|
||||
var gtex = new GDIPlusTexture { SDBitmap = sdBitmap };
|
||||
return new(this, gtex, bmp.Width, bmp.Height);
|
||||
}
|
||||
|
||||
public BitmapBuffer ResolveTexture2d(Texture2d tex)
|
||||
{
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
var blow = new BitmapLoadOptions
|
||||
{
|
||||
AllowWrap = false // must be an independent resource
|
||||
};
|
||||
|
||||
var bb = new BitmapBuffer(tw.SDBitmap, blow);
|
||||
var bb = new BitmapBuffer(gtex.SDBitmap, blow);
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
@ -212,16 +204,6 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
// on account of gdi+ working internally with a default view exactly like we want, we don't need to setup a new one here
|
||||
// furthermore, we _cant_, without inverting the GuiView and GuiProjection before drawing, to completely undo it
|
||||
// this might be feasible, but its kind of slow and annoying and worse, seemingly numerically unstable
|
||||
#if false
|
||||
if (autoFlip && _currRenderTarget != null)
|
||||
{
|
||||
Matrix4 ret = Matrix4.Identity;
|
||||
ret.M22 = -1;
|
||||
ret.M42 = dims.Height;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return Matrix4x4.Identity;
|
||||
}
|
||||
|
||||
|
@ -237,16 +219,6 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
SetViewport(size.Width, size.Height);
|
||||
}
|
||||
|
||||
public void BeginControl(IGraphicsControl control)
|
||||
{
|
||||
CurrentControl = control;
|
||||
}
|
||||
|
||||
public void EndControl()
|
||||
{
|
||||
CurrentControl = null;
|
||||
}
|
||||
|
||||
public void BeginScene()
|
||||
{
|
||||
|
@ -254,37 +226,28 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void EndScene()
|
||||
{
|
||||
//maybe an inconsistent semantic with other implementations..
|
||||
//but accomplishes the needed goal of getting the current RT to render
|
||||
// maybe an inconsistent semantic with other implementations..
|
||||
// but accomplishes the needed goal of getting the current RT to render
|
||||
BindRenderTarget(null);
|
||||
}
|
||||
|
||||
public IGraphicsControl Internal_CreateGraphicsControl()
|
||||
{
|
||||
var ret = _createGLControlWrapper(this);
|
||||
// create a render target for this control
|
||||
var rtw = new RenderTargetWrapper(() => MyBufferedGraphicsContext, ret);
|
||||
ret.RenderTargetWrapper = rtw;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void FreeRenderTarget(RenderTarget rt)
|
||||
{
|
||||
var rtw = (RenderTargetWrapper)rt.Opaque;
|
||||
rtw.Dispose();
|
||||
var grt = (GDIPlusRenderTarget)rt.Opaque;
|
||||
grt.Dispose();
|
||||
}
|
||||
|
||||
public RenderTarget CreateRenderTarget(int w, int h)
|
||||
{
|
||||
var tw = new GDIPTextureWrapper
|
||||
var gtex = new GDIPlusTexture
|
||||
{
|
||||
SDBitmap = new(w, h, PixelFormat.Format32bppArgb)
|
||||
};
|
||||
var tex = new Texture2d(this, tw, w, h);
|
||||
var tex = new Texture2d(this, gtex, w, h);
|
||||
|
||||
var rtw = new RenderTargetWrapper(() => MyBufferedGraphicsContext);
|
||||
var rt = new RenderTarget(this, rtw, tex);
|
||||
rtw.Target = rt;
|
||||
var grt = new GDIPlusRenderTarget(() => BufferedGraphicsContext);
|
||||
var rt = new RenderTarget(this, grt, tex);
|
||||
grt.Target = rt;
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
@ -296,56 +259,41 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
_currOffscreenGraphics = null;
|
||||
}
|
||||
|
||||
#if false
|
||||
_currRenderTarget = rt;
|
||||
if (CurrentRenderTargetWrapper != null)
|
||||
{
|
||||
if (CurrentRenderTargetWrapper == CurrentControl.RenderTargetWrapper)
|
||||
{
|
||||
// don't do anything til swapbuffers
|
||||
}
|
||||
else
|
||||
{
|
||||
// CurrentRenderTargetWrapper.MyBufferedGraphics.Render();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rt == null)
|
||||
{
|
||||
// null means to use the default RT for the current control
|
||||
CurrentRenderTargetWrapper = CurrentControl.RenderTargetWrapper;
|
||||
CurrentRenderTarget = _controlRenderTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tw = (GDIPTextureWrapper)rt.Texture2d.Opaque;
|
||||
CurrentRenderTargetWrapper = (RenderTargetWrapper)rt.Opaque;
|
||||
_currOffscreenGraphics = Graphics.FromImage(tw.SDBitmap);
|
||||
#if false
|
||||
if (CurrentRenderTargetWrapper.MyBufferedGraphics == null)
|
||||
{
|
||||
CurrentRenderTargetWrapper.CreateGraphics();
|
||||
}
|
||||
#endif
|
||||
var gtex = (GDIPlusTexture)rt.Texture2d.Opaque;
|
||||
CurrentRenderTarget = (GDIPlusRenderTarget)rt.Opaque;
|
||||
_currOffscreenGraphics = SDGraphics.FromImage(gtex.SDBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private Graphics _currOffscreenGraphics;
|
||||
private GDIPlusRenderTarget _controlRenderTarget;
|
||||
|
||||
public Graphics GetCurrentGraphics()
|
||||
public GDIPlusRenderTarget CreateControlRenderTarget(Func<(SDGraphics Graphics, Rectangle Rectangle)> getControlRenderContext)
|
||||
{
|
||||
if (_currOffscreenGraphics != null)
|
||||
if (_controlRenderTarget != null)
|
||||
{
|
||||
return _currOffscreenGraphics;
|
||||
throw new InvalidOperationException($"{nameof(IGL_GDIPlus)} can only have one control render target");
|
||||
}
|
||||
|
||||
var rtw = CurrentRenderTargetWrapper;
|
||||
return rtw.MyBufferedGraphics.Graphics;
|
||||
_controlRenderTarget = new(() => BufferedGraphicsContext, getControlRenderContext);
|
||||
return _controlRenderTarget;
|
||||
}
|
||||
|
||||
public IGraphicsControl CurrentControl;
|
||||
public RenderTargetWrapper CurrentRenderTargetWrapper;
|
||||
private SDGraphics _currOffscreenGraphics;
|
||||
|
||||
public readonly BufferedGraphicsContext MyBufferedGraphicsContext = new();
|
||||
public SDGraphics GetCurrentGraphics()
|
||||
{
|
||||
return _currOffscreenGraphics ?? CurrentRenderTarget.BufferedGraphics.Graphics;
|
||||
}
|
||||
|
||||
public GDIPlusRenderTarget CurrentRenderTarget;
|
||||
|
||||
public readonly BufferedGraphicsContext BufferedGraphicsContext = new();
|
||||
}
|
||||
}
|
|
@ -78,13 +78,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
}
|
||||
|
||||
public IGraphicsControl Internal_CreateGraphicsControl()
|
||||
{
|
||||
var ret = new OpenGLControl();
|
||||
ret.CreateControl(); // DisplayManager relies on this context being active for creating the GuiRenderer
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void FreeTexture(Texture2d tex)
|
||||
{
|
||||
GL.DeleteTexture((uint)tex.Opaque);
|
||||
|
|
|
@ -6,14 +6,18 @@ using System.Drawing.Drawing2D;
|
|||
using System.Drawing.Imaging;
|
||||
using System.Numerics;
|
||||
|
||||
namespace BizHawk.Bizware.BizwareGL
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
using SDGraphics = System.Drawing.Graphics;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
public class GDIPlusGuiRenderer : IGuiRenderer
|
||||
{
|
||||
private readonly IGL_GdiPlus Gdi;
|
||||
private readonly IGL_GDIPlus _gdi;
|
||||
|
||||
public GDIPlusGuiRenderer(IGL_GdiPlus gl)
|
||||
=> Gdi = gl;
|
||||
public GDIPlusGuiRenderer(IGL_GDIPlus gdi)
|
||||
=> _gdi = gdi;
|
||||
|
||||
private readonly Vector4[] CornerColors =
|
||||
{
|
||||
|
@ -129,7 +133,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
Begin();
|
||||
|
||||
CurrentBlendState = Gdi.BlendNormal;
|
||||
CurrentBlendState = _gdi.BlendNormal;
|
||||
|
||||
Projection = Owner.CreateGuiProjectionMatrix(width, height);
|
||||
Modelview = Owner.CreateGuiViewMatrix(width, height);
|
||||
|
@ -166,8 +170,8 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public void DrawSubrect(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1)
|
||||
{
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
var g = Gdi.GetCurrentGraphics();
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
var g = _gdi.GetCurrentGraphics();
|
||||
|
||||
PrepDraw(g, tex);
|
||||
SetupMatrix(g);
|
||||
|
@ -184,11 +188,10 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
new(x, y+h),
|
||||
};
|
||||
|
||||
g.DrawImage(tw.SDBitmap, destPoints, new(x0, y0, x1 - x0, y1 - y0), GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.DrawImage(gtex.SDBitmap, destPoints, new(x0, y0, x1 - x0, y1 - y0), GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.Transform = new(); // .Reset() doesnt work?
|
||||
}
|
||||
|
||||
|
||||
public void Draw(Art art) { DrawInternal(art, 0, 0, art.Width, art.Height, false, false); }
|
||||
public void Draw(Art art, float x, float y) { DrawInternal(art, x, y, art.Width, art.Height, false, false); }
|
||||
public void Draw(Art art, float x, float y, float width, float height) { DrawInternal(art, x, y, width, height, false, false); }
|
||||
|
@ -202,9 +205,9 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
DrawInternal(art, x, y, width, height);
|
||||
}
|
||||
|
||||
private void PrepDraw(Graphics g, Texture2d tex)
|
||||
private void PrepDraw(SDGraphics g, Texture2d tex)
|
||||
{
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
var tw = (GDIPlusTexture)tex.Opaque;
|
||||
|
||||
// TODO - we can support bicubic for the final presentation...
|
||||
if ((int)tw.MagFilter != (int)tw.MinFilter)
|
||||
|
@ -219,12 +222,10 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
_ => g.InterpolationMode
|
||||
};
|
||||
|
||||
if (CurrentBlendState == Gdi.BlendNormal)
|
||||
if (CurrentBlendState == _gdi.BlendNormal)
|
||||
{
|
||||
g.CompositingMode = CompositingMode.SourceOver;
|
||||
g.CompositingQuality = CompositingQuality.Default; // ?
|
||||
|
||||
// CurrentImageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap);
|
||||
}
|
||||
else
|
||||
// if (CurrentBlendState == Gdi.BlendNoneCopy)
|
||||
|
@ -239,7 +240,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
}
|
||||
}
|
||||
|
||||
private void SetupMatrix(Graphics g)
|
||||
private void SetupMatrix(SDGraphics g)
|
||||
{
|
||||
// projection is always identity, so who cares i guess
|
||||
// var mat = Projection.Top * Modelview.Top;
|
||||
|
@ -259,7 +260,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
private void DrawInternal(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1)
|
||||
{
|
||||
var g = Gdi.GetCurrentGraphics();
|
||||
var g = _gdi.GetCurrentGraphics();
|
||||
PrepDraw(g, tex);
|
||||
|
||||
SetupMatrix(g);
|
||||
|
@ -278,9 +279,9 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
var sw = sx2 - sx;
|
||||
var sh = sy2 - sy;
|
||||
|
||||
var tw = (GDIPTextureWrapper)tex.Opaque;
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
g.PixelOffsetMode = PixelOffsetMode.Half;
|
||||
g.DrawImage(tw.SDBitmap, destPoints, new(sx, sy, sw, sh), GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.DrawImage(gtex.SDBitmap, destPoints, new(sx, sy, sw, sh), GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.Transform = new(); // .Reset() doesn't work ? ?
|
||||
}
|
||||
|
||||
|
@ -290,6 +291,6 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
public IGL Owner => Gdi;
|
||||
public IGL Owner => _gdi;
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Audio/BizHawk.Bizware.Audio.csproj" />
|
||||
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Input/BizHawk.Bizware.Input.csproj" />
|
||||
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Graphics/BizHawk.Bizware.Graphics.csproj" />
|
||||
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Graphics.Controls/BizHawk.Bizware.Graphics.Controls.csproj" />
|
||||
<ProjectReference Include="$(ProjectDir)../BizHawk.WinForms.Controls/BizHawk.WinForms.Controls.csproj" />
|
||||
<Compile Remove="Properties/Settings.Designer.cs" />
|
||||
<Content Include="images/logo.ico" />
|
||||
|
@ -260,9 +261,7 @@
|
|||
<Compile Update="CustomControls/RepeatButton.cs" SubType="Component" />
|
||||
<Compile Update="CustomControls/TransparentTrackbar.cs" SubType="Component" />
|
||||
<Compile Update="CustomControls/ViewportPanel.cs" SubType="Component" />
|
||||
<Compile Update="GraphicsImplementations/GLControlWrapper_GdiPlus.cs" SubType="Component" />
|
||||
<Compile Update="GraphicsImplementations/GLControlWrapper_SlimDX9.cs" SubType="Component" />
|
||||
<Compile Update="GraphicsImplementations/GraphicsControl.cs" SubType="UserControl" />
|
||||
<Compile Update="GraphicsImplementations/GraphicsControl_TK.cs" SubType="UserControl" />
|
||||
<Compile Update="GraphicsImplementations/RetainedGraphicsControl.cs" SubType="UserControl" />
|
||||
<Compile Update="LogWindow.cs" SubType="Form" />
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Diagnostics;
|
|||
using System.Drawing;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Bizware.Graphics.Controls;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public class GLControlWrapper_GdiPlus : Control, IGraphicsControl
|
||||
{
|
||||
public GLControlWrapper_GdiPlus(IGL_GdiPlus gdi)
|
||||
{
|
||||
_gdi = gdi;
|
||||
SetStyle(ControlStyles.UserPaint, true);
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||
SetStyle(ControlStyles.Opaque, true);
|
||||
SetStyle(ControlStyles.UserMouse, true);
|
||||
}
|
||||
|
||||
private readonly IGL_GdiPlus _gdi;
|
||||
|
||||
/// <summary>
|
||||
/// the render target for rendering to this control
|
||||
/// </summary>
|
||||
public RenderTargetWrapper RenderTargetWrapper { get; set; }
|
||||
|
||||
public void SetVsync(bool state)
|
||||
{
|
||||
// not really supported now...
|
||||
}
|
||||
|
||||
public void Begin()
|
||||
{
|
||||
_gdi.BeginControl(this);
|
||||
RenderTargetWrapper.CreateGraphics();
|
||||
|
||||
#if false
|
||||
using (var g = CreateGraphics())
|
||||
{
|
||||
MyBufferedGraphics = _gdi.MyBufferedGraphicsContext.Allocate(g, ClientRectangle);
|
||||
}
|
||||
|
||||
MyBufferedGraphics.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
|
||||
|
||||
// not sure about this stuff...
|
||||
// it will wreck alpha blending, for one thing
|
||||
MyBufferedGraphics.Graphics.CompositingMode = CompositingMode.SourceCopy;
|
||||
MyBufferedGraphics.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
_gdi.EndControl();
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
{
|
||||
if (RenderTargetWrapper.MyBufferedGraphics == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (var g = CreateGraphics())
|
||||
{
|
||||
// not sure we had proof we needed this but it cant hurt
|
||||
g.CompositingMode = CompositingMode.SourceCopy;
|
||||
g.CompositingQuality = CompositingQuality.HighSpeed;
|
||||
RenderTargetWrapper.MyBufferedGraphics.Render(g);
|
||||
}
|
||||
|
||||
// not too sure about this.. i think we have to re-allocate it so we can support a changed window size. did we do this at the right time anyway?
|
||||
// maybe I should try caching harder, I hate to reallocate these constantly
|
||||
RenderTargetWrapper.CreateGraphics();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
using System.Windows.Forms;
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// a base class for deriving/wrapping from a IGraphicsControl.
|
||||
/// This is to work around the annoyance that we cant inherit from a control whose type is unknown (it would be delivered by the selected BizwareGL driver)
|
||||
/// and so we have to resort to composition and c# sucks and events suck.
|
||||
/// </summary>
|
||||
public class GraphicsControl : UserControl
|
||||
{
|
||||
public GraphicsControl(IGL owner)
|
||||
{
|
||||
IGL = owner;
|
||||
|
||||
SetStyle(ControlStyles.Opaque, true);
|
||||
SetStyle(ControlStyles.UserPaint, true);
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||
SetStyle(ControlStyles.UserMouse, true);
|
||||
|
||||
_igc = owner.Internal_CreateGraphicsControl();
|
||||
_managed = (Control)_igc;
|
||||
_managed.Dock = DockStyle.Fill;
|
||||
Controls.Add(_managed);
|
||||
|
||||
// pass through these events to the form. I tried really hard to find a better way, but there is none.
|
||||
// (don't use HTTRANSPARENT, it isn't portable, I would assume)
|
||||
_managed.MouseDoubleClick += (_, e) => OnMouseDoubleClick(e);
|
||||
_managed.MouseClick += (_, e) => OnMouseClick(e);
|
||||
_managed.MouseEnter += (_, e) => OnMouseEnter(e);
|
||||
_managed.MouseLeave += (_, e) => OnMouseLeave(e);
|
||||
_managed.MouseMove += (_, e) => OnMouseMove(e);
|
||||
|
||||
//the GraphicsControl is occupying all of our area. So we pretty much never get paint events ourselves.
|
||||
//So lets capture its paint event and use it for ourselves (it doesn't know how to do anything, anyway)
|
||||
_managed.Paint += GraphicsControl_Paint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this is the main window, things may be special
|
||||
/// </summary>
|
||||
public bool MainWindow;
|
||||
|
||||
private void GraphicsControl_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
OnPaint(e);
|
||||
}
|
||||
|
||||
public readonly IGL IGL;
|
||||
|
||||
private readonly IGraphicsControl _igc;
|
||||
private readonly Control _managed;
|
||||
|
||||
public virtual void SetVsync(bool state) { _igc.SetVsync(state); }
|
||||
public virtual void SwapBuffers() { _igc.SwapBuffers(); }
|
||||
public virtual void Begin() { _igc.Begin(); }
|
||||
public virtual void End() { _igc.End(); }
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public static class IGLExtensions
|
||||
{
|
||||
public static IGuiRenderer CreateRenderer(this IGL gl)
|
||||
=> gl is IGL_GdiPlus gdipImpl
|
||||
=> gl is IGL_GDIPlus gdipImpl
|
||||
? new GDIPlusGuiRenderer(gdipImpl)
|
||||
: new GuiRenderer(gl); // This implementation doesn't seem to require any OpenGL-specific (or D3D-specific) behaviour; can it be used with IGL_GdiPlus too? If so, is GDIPlusGuiRenderer only kept around because it's faster? --yoshi
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Bizware.Graphics;
|
||||
using BizHawk.Bizware.Graphics.Controls;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -10,10 +12,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
public class RetainedGraphicsControl : GraphicsControl
|
||||
{
|
||||
public RetainedGraphicsControl(IGL gl)
|
||||
: base(gl)
|
||||
{
|
||||
_gl = gl;
|
||||
_guiRenderer = new GuiRenderer(gl);
|
||||
_graphicsControl = GraphicsControlFactory.CreateGraphicsControl(gl);
|
||||
_guiRenderer = new(gl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -38,13 +40,26 @@ namespace BizHawk.Client.EmuHawk
|
|||
private bool _retain = true;
|
||||
|
||||
private readonly IGL _gl;
|
||||
private readonly GraphicsControl _graphicsControl;
|
||||
private RenderTarget _rt;
|
||||
private readonly GuiRenderer _guiRenderer;
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
// todo - check whether we're begun?
|
||||
_graphicsControl.Begin();
|
||||
Draw();
|
||||
_graphicsControl.End();
|
||||
}
|
||||
|
||||
public override void SetVsync(bool state)
|
||||
=> _graphicsControl.SetVsync(state);
|
||||
|
||||
public override void Begin()
|
||||
{
|
||||
base.Begin();
|
||||
|
||||
_graphicsControl.Begin();
|
||||
|
||||
if (_retain)
|
||||
{
|
||||
// TODO - frugalize me
|
||||
|
@ -54,13 +69,28 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
public override void End()
|
||||
{
|
||||
base.OnPaint(e);
|
||||
// todo - check whether we're begun?
|
||||
base.Begin();
|
||||
if (_retain)
|
||||
{
|
||||
_rt.Unbind();
|
||||
}
|
||||
|
||||
_graphicsControl.End();
|
||||
}
|
||||
|
||||
public override void SwapBuffers()
|
||||
{
|
||||
// if we're not retaining, then we haven't been collecting into a framebuffer. just swap it
|
||||
if (!_retain)
|
||||
{
|
||||
_graphicsControl.SwapBuffers();
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're retaining, then we cant draw until we unbind! its semantically a bit odd, but we expect users to call SwapBuffers() before end, so we cant unbind in End() even thoug hit makes a bit more sense.
|
||||
_rt.Unbind();
|
||||
Draw();
|
||||
base.End();
|
||||
}
|
||||
|
||||
private void Draw()
|
||||
|
@ -74,31 +104,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
_guiRenderer.SetBlendState(_gl.BlendNoneCopy);
|
||||
_guiRenderer.Draw(_rt.Texture2d);
|
||||
_guiRenderer.End();
|
||||
base.SwapBuffers();
|
||||
}
|
||||
|
||||
public override void SwapBuffers()
|
||||
{
|
||||
// if we're not retaining, then we haven't been collecting into a framebuffer. just swap it
|
||||
if (!_retain)
|
||||
{
|
||||
base.SwapBuffers();
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're retaining, then we cant draw until we unbind! its semantically a bit odd, but we expect users to call SwapBuffers() before end, so we cant unbind in End() even thoug hit makes a bit more sense.
|
||||
_rt.Unbind();
|
||||
Draw();
|
||||
}
|
||||
|
||||
public override void End()
|
||||
{
|
||||
if (_retain)
|
||||
{
|
||||
_rt.Unbind();
|
||||
}
|
||||
|
||||
base.End();
|
||||
_graphicsControl.SwapBuffers();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -446,17 +446,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
// TODO GL - a lot of disorganized wiring-up here
|
||||
// installed separately on Unix (via package manager or from https://developer.nvidia.com/cg-toolkit-download), look in $PATH
|
||||
_presentationPanel = new PresentationPanel(
|
||||
_presentationPanel = new(
|
||||
Config,
|
||||
GL,
|
||||
ToggleFullscreen,
|
||||
MainForm_MouseClick,
|
||||
MainForm_MouseMove,
|
||||
MainForm_MouseWheel)
|
||||
{
|
||||
GraphicsControl = { MainWindow = true }
|
||||
};
|
||||
DisplayManager = new DisplayManager(Config, Emulator, InputManager, MovieSession, GL, _presentationPanel, () => DisableSecondaryThrottling);
|
||||
MainForm_MouseWheel);
|
||||
|
||||
DisplayManager = new(Config, Emulator, InputManager, MovieSession, GL, _presentationPanel, () => DisableSecondaryThrottling);
|
||||
Controls.Add(_presentationPanel);
|
||||
Controls.SetChildIndex(_presentationPanel, 0);
|
||||
|
||||
|
|
|
@ -4,11 +4,12 @@ using System.Windows.Forms;
|
|||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Bizware.Graphics.Controls;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// Thinly wraps a BizwareGL.GraphicsControl for EmuHawk's needs
|
||||
/// Thinly wraps a GraphicsControl for EmuHawk's needs
|
||||
/// </summary>
|
||||
public class PresentationPanel
|
||||
{
|
||||
|
@ -28,11 +29,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
_fullscreenToggleCallback = fullscreenToggleCallback;
|
||||
|
||||
GraphicsControl = new GraphicsControl(gl)
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
BackColor = Color.Black
|
||||
};
|
||||
GraphicsControl = GraphicsControlFactory.CreateGraphicsControl(gl);
|
||||
GraphicsControl.Dock = DockStyle.Fill;
|
||||
GraphicsControl.BackColor = Color.Black;
|
||||
|
||||
// pass through these events to the form. we might need a more scalable solution for mousedown etc. for zapper and whatnot.
|
||||
// http://stackoverflow.com/questions/547172/pass-through-mouse-events-to-parent-control (HTTRANSPARENT)
|
||||
|
@ -43,15 +42,20 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
GraphicsControl.Dispose();
|
||||
}
|
||||
|
||||
//graphics resources
|
||||
public GraphicsControl GraphicsControl;
|
||||
// graphics resources
|
||||
public readonly GraphicsControl GraphicsControl;
|
||||
|
||||
public Control Control => GraphicsControl;
|
||||
public static implicit operator Control(PresentationPanel self) { return self.GraphicsControl; }
|
||||
|
@ -61,7 +65,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
// allow suppression of the toggle.. but if shift is pressed, always do the toggle
|
||||
bool allowSuppress = Control.ModifierKeys != Keys.Shift;
|
||||
var allowSuppress = Control.ModifierKeys != Keys.Shift;
|
||||
if (_config.DispChromeAllowDoubleClickFullscreen || !allowSuppress)
|
||||
{
|
||||
_fullscreenToggleCallback(allowSuppress);
|
||||
|
|
|
@ -242,9 +242,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
default:
|
||||
case EDispMethod.GdiPlus:
|
||||
static GLControlWrapper_GdiPlus CreateGLControlWrapper(IGL_GdiPlus self) => new(self); // inlining as lambda causes crash, don't wanna know why --yoshi
|
||||
// if this fails, we're screwed
|
||||
return new IGL_GdiPlus(CreateGLControlWrapper);
|
||||
return new IGL_GDIPlus();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue