diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d419ce197 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ImGui.NET"] + path = lib/ImGui.NET + url = https://github.com/ff-meli/ImGui.NET.git diff --git a/Dalamud.Injector/Dalamud.Injector.csproj b/Dalamud.Injector/Dalamud.Injector.csproj index 0ac4cccf8..d0901d863 100644 --- a/Dalamud.Injector/Dalamud.Injector.csproj +++ b/Dalamud.Injector/Dalamud.Injector.csproj @@ -23,7 +23,7 @@ - + diff --git a/Dalamud.Injector/Program.cs b/Dalamud.Injector/Program.cs index db9ceb692..6d7ad17c3 100644 --- a/Dalamud.Injector/Program.cs +++ b/Dalamud.Injector/Program.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Windows.Forms; using Dalamud.DiscordBot; using Dalamud.Game.Chat; @@ -34,6 +35,7 @@ namespace Dalamud.Injector { process = Process.Start( "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\ffxiv_dx11.exe", "DEV.TestSID=0 DEV.UseSqPack=1 DEV.DataPathType=1 DEV.LobbyHost01=127.0.0.1 DEV.LobbyPort01=54994 DEV.LobbyHost02=127.0.0.1 DEV.LobbyPort02=54994 DEV.LobbyHost03=127.0.0.1 DEV.LobbyPort03=54994 DEV.LobbyHost04=127.0.0.1 DEV.LobbyPort04=54994 DEV.LobbyHost05=127.0.0.1 DEV.LobbyPort05=54994 DEV.LobbyHost06=127.0.0.1 DEV.LobbyPort06=54994 DEV.LobbyHost07=127.0.0.1 DEV.LobbyPort07=54994 DEV.LobbyHost08=127.0.0.1 DEV.LobbyPort08=54994 SYS.Region=0 language=1 version=1.0.0.0 DEV.MaxEntitledExpansionID=2 DEV.GMServerHost=127.0.0.1 DEV.GameQuitMessageBox=0"); + Thread.Sleep(10000); break; default: process = Process.GetProcessById(pid); diff --git a/Dalamud.sln b/Dalamud.sln index ac5182893..596579eec 100644 --- a/Dalamud.sln +++ b/Dalamud.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud", "Dalamud\Dalamud. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.Injector", "Dalamud.Injector\Dalamud.Injector.csproj", "{5B832F73-5F54-4ADC-870F-D0095EF72C9A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImGui.NET-472", "lib\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj", "{0483026E-C6CE-4B1A-AA68-46544C08140B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,6 +33,14 @@ Global {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.Build.0 = Release|Any CPU {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.ActiveCfg = Release|x64 {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.Build.0 = Release|x64 + {0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.ActiveCfg = Debug|Any CPU + {0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.Build.0 = Debug|Any CPU + {0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.Build.0 = Release|Any CPU + {0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.ActiveCfg = Release|Any CPU + {0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index 23174f86a..8d5bbe5b9 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -14,7 +14,9 @@ using Dalamud.Game.ClientState.Actors.Types; using Dalamud.Game.ClientState.Actors.Types.NonPlayer; using Dalamud.Game.Command; using Dalamud.Game.Internal; +using Dalamud.Game.Internal.DXGI; using Dalamud.Game.Internal.Gui; +using Dalamud.Game.Internal.Network; using Dalamud.Game.Network; using Dalamud.Plugin; using Serilog; @@ -49,6 +51,8 @@ namespace Dalamud { internal readonly WinSockHandlers WinSock2; + internal readonly SwapChain deviceHandler; + public Dalamud(DalamudStartInfo info) { this.StartInfo = info; this.Configuration = DalamudConfiguration.Load(info.ConfigurationPath); @@ -81,6 +85,8 @@ namespace Dalamud { this.WinSock2 = new WinSockHandlers(); + this.deviceHandler = new SwapChain(this, this.sigScanner); + try { this.PluginManager.LoadPlugins(); } catch (Exception ex) { diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 7d65ccb68..3d07c6589 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -1,7 +1,7 @@  AnyCPU - net471 + net48 8.0 AnyCPU;x64 @@ -41,13 +41,19 @@ - + + + + + + + diff --git a/Dalamud/Game/Internal/DXGI/ImGuiImplDx11.cs b/Dalamud/Game/Internal/DXGI/ImGuiImplDx11.cs new file mode 100644 index 000000000..a51216719 --- /dev/null +++ b/Dalamud/Game/Internal/DXGI/ImGuiImplDx11.cs @@ -0,0 +1,450 @@ +using ImGuiNET; +using SharpDX; +using SharpDX.Direct3D; +using SharpDX.Direct3D11; +using SharpDX.DXGI; +using SharpDX.Mathematics.Interop; +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Buffer = SharpDX.Direct3D11.Buffer; +using Device = SharpDX.Direct3D11.Device; +using MapFlags = SharpDX.Direct3D11.MapFlags; + +namespace Dalamud.Game.Internal.DXGI +{ + /// + /// Currently undocumented because it is a horrible mess. + /// A near-direct port of https://github.com/ocornut/imgui/blob/master/examples/imgui_impl_dx11.cpp + /// State backup was removed because ImGui does it poorly and SharpDX makes it worse; state caching should + /// be the responsibility of the main render application anyway (which for most uses of this class does not + /// exist at all) + /// + public class ImGuiImplDx11 + { + private IntPtr _renderNamePtr; + private Device _device; + private DeviceContext _deviceContext; + private ShaderResourceView _fontResourceView; + private SamplerState _fontSampler; + private VertexShader _vertexShader; + private PixelShader _pixelShader; + private InputLayout _inputLayout; + private Buffer _vertexConstantBuffer; + private BlendState _blendState; + private RasterizerState _rasterizerState; + private DepthStencilState _depthStencilState; + private Buffer _vertexBuffer; + private Buffer _indexBuffer; + private int _vertexBufferSize; + private int _indexBufferSize; + private VertexBufferBinding _vertexBinding; + // so we don't make a temporary object every frame + private RawColor4 _blendColor = new RawColor4(0, 0, 0, 0); + + public void SetupRenderState(ImDrawDataPtr drawData) + { + // Setup viewport + _deviceContext.Rasterizer.SetViewport(0, 0, drawData.DisplaySize.X, drawData.DisplaySize.Y); + + // Setup shader and vertex buffers + _deviceContext.InputAssembler.InputLayout = _inputLayout; + _vertexBinding.Buffer = _vertexBuffer; + _deviceContext.InputAssembler.SetVertexBuffers(0, _vertexBinding); + _deviceContext.InputAssembler.SetIndexBuffer(_indexBuffer, Format.R16_UInt, 0); + _deviceContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; + _deviceContext.VertexShader.Set(_vertexShader); + _deviceContext.VertexShader.SetConstantBuffer(0, _vertexConstantBuffer); + _deviceContext.PixelShader.Set(_pixelShader); + _deviceContext.PixelShader.SetSampler(0, _fontSampler); + _deviceContext.GeometryShader.Set(null); + _deviceContext.HullShader.Set(null); + _deviceContext.DomainShader.Set(null); + _deviceContext.ComputeShader.Set(null); + + // Setup blend state + _deviceContext.OutputMerger.BlendState = _blendState; + _deviceContext.OutputMerger.BlendFactor = _blendColor; + _deviceContext.OutputMerger.DepthStencilState = _depthStencilState; + _deviceContext.Rasterizer.State = _rasterizerState; + } + + public void RenderDrawData(ImDrawDataPtr drawData) + { + // Avoid rendering when minimized + if (drawData.DisplaySize.X <= 0 || drawData.DisplaySize.Y <= 0) + { + return; + } + + if (!drawData.Valid || drawData.CmdListsCount == 0) + { + return; + } + + //drawData.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale); + + // Create and grow vertex/index buffers if needed + if (_vertexBuffer == null || _vertexBufferSize < drawData.TotalVtxCount) + { + _vertexBuffer?.Dispose(); + _vertexBufferSize = drawData.TotalVtxCount + 5000; + + _vertexBuffer = new Buffer(_device, new BufferDescription + { + Usage = ResourceUsage.Dynamic, + SizeInBytes = Unsafe.SizeOf() * _vertexBufferSize, + BindFlags = BindFlags.VertexBuffer, + CpuAccessFlags = CpuAccessFlags.Write, + OptionFlags = ResourceOptionFlags.None + }); + + // (Re)make this here rather than every frame + _vertexBinding = new VertexBufferBinding + { + Buffer = _vertexBuffer, + Stride = Unsafe.SizeOf(), + Offset = 0 + }; + } + + if (_indexBuffer == null || _indexBufferSize < drawData.TotalIdxCount) + { + _indexBuffer?.Dispose(); + _indexBufferSize = drawData.TotalIdxCount + 10000; + + _indexBuffer = new Buffer(_device, new BufferDescription + { + Usage = ResourceUsage.Dynamic, + SizeInBytes = sizeof(ushort) * _indexBufferSize, // ImGui.NET doesn't provide an ImDrawIdx, but their sample uses ushort + BindFlags = BindFlags.IndexBuffer, + CpuAccessFlags = CpuAccessFlags.Write + }); + } + + // Upload vertex/index data into a single contiguous GPU buffer + int vertexOffset = 0, indexOffset = 0; + var vertexData = _deviceContext.MapSubresource(_vertexBuffer, 0, MapMode.WriteDiscard, MapFlags.None).DataPointer; + var indexData = _deviceContext.MapSubresource(_indexBuffer, 0, MapMode.WriteDiscard, MapFlags.None).DataPointer; + + for (int n = 0; n < drawData.CmdListsCount; n++) + { + var cmdList = drawData.CmdListsRange[n]; + unsafe + { + System.Buffer.MemoryCopy(cmdList.VtxBuffer.Data.ToPointer(), + (ImDrawVert*)vertexData + vertexOffset, + Unsafe.SizeOf() * _vertexBufferSize, + Unsafe.SizeOf() * cmdList.VtxBuffer.Size); + + System.Buffer.MemoryCopy(cmdList.IdxBuffer.Data.ToPointer(), + (ushort*)indexData + indexOffset, + sizeof(ushort) * _indexBufferSize, + sizeof(ushort) * cmdList.IdxBuffer.Size); + + vertexOffset += cmdList.VtxBuffer.Size; + indexOffset += cmdList.IdxBuffer.Size; + } + } + _deviceContext.UnmapSubresource(_vertexBuffer, 0); + _deviceContext.UnmapSubresource(_indexBuffer, 0); + + // Setup orthographic projection matrix into our constant buffer + // Our visible imgui space lies from drawData.DisplayPos (top left) to drawData.DisplayPos+drawData.DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + var L = drawData.DisplayPos.X; + var R = drawData.DisplayPos.X + drawData.DisplaySize.X; + var T = drawData.DisplayPos.Y; + var B = drawData.DisplayPos.Y + drawData.DisplaySize.Y; + var mvp = new float[] + { + 2f/(R-L), 0, 0, 0, + 0, 2f/(T-B), 0, 0, + 0, 0, 0.5f, 0, + (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1f + }; + + var constantBuffer = _deviceContext.MapSubresource(_vertexConstantBuffer, 0, MapMode.WriteDiscard, MapFlags.None).DataPointer; + unsafe + { + fixed (void* mvpPtr = mvp) + { + System.Buffer.MemoryCopy(mvpPtr, constantBuffer.ToPointer(), 16 * sizeof(float), 16 * sizeof(float)); + } + } + _deviceContext.UnmapSubresource(_vertexConstantBuffer, 0); + + // Setup desired DX state + SetupRenderState(drawData); + + // Render command lists + // (Because we merged all buffers into a single one, we maintain our own offset into them) + vertexOffset = 0; + indexOffset = 0; + var clipOff = drawData.DisplayPos; + for (int n = 0; n < drawData.CmdListsCount; n++) + { + var cmdList = drawData.CmdListsRange[n]; + for (int cmd = 0; cmd < cmdList.CmdBuffer.Size; cmd++) + { + var pcmd = cmdList.CmdBuffer[cmd]; + if (pcmd.UserCallback != IntPtr.Zero) + { + // TODO + throw new NotImplementedException(); + } + else + { + // Apply scissor/clipping rectangle + _deviceContext.Rasterizer.SetScissorRectangle((int)(pcmd.ClipRect.X - clipOff.X), (int)(pcmd.ClipRect.Y - clipOff.Y), (int)(pcmd.ClipRect.Z - clipOff.X), (int)(pcmd.ClipRect.W - clipOff.Y)); + + // Bind texture, Draw + // TODO: might be nice to store samplers for loaded textures so that we can look them up and apply them here + // rather than just always using the font sampler + var textureSrv = ShaderResourceView.FromPointer(pcmd.TextureId); + _deviceContext.PixelShader.SetShaderResource(0, textureSrv); + _deviceContext.DrawIndexed((int)pcmd.ElemCount, (int)(pcmd.IdxOffset + indexOffset), (int)(pcmd.VtxOffset + vertexOffset)); + } + } + + indexOffset += cmdList.IdxBuffer.Size; + vertexOffset += cmdList.VtxBuffer.Size; + } + } + + public void CreateFontsTexture() + { + var io = ImGui.GetIO(); + + // Build texture atlas + io.Fonts.GetTexDataAsRGBA32(out IntPtr fontPixels, out int fontWidth, out int fontHeight, out int fontBytesPerPixel); + + // Upload texture to graphics system + var texDesc = new Texture2DDescription + { + Width = fontWidth, + Height = fontHeight, + MipLevels = 1, + ArraySize = 1, + Format = Format.R8G8B8A8_UNorm, + SampleDescription = new SampleDescription(1, 0), + Usage = ResourceUsage.Immutable, + BindFlags = BindFlags.ShaderResource, + CpuAccessFlags = CpuAccessFlags.None, + OptionFlags = ResourceOptionFlags.None + }; + + using (var fontTexture = new Texture2D(_device, texDesc, new DataRectangle(fontPixels, fontWidth * fontBytesPerPixel))) + { + // Create texture view + _fontResourceView = new ShaderResourceView(_device, fontTexture, new ShaderResourceViewDescription + { + Format = texDesc.Format, + Dimension = ShaderResourceViewDimension.Texture2D, + Texture2D = { MipLevels = texDesc.MipLevels } + }); + } + + // Store our identifier + io.Fonts.SetTexID(_fontResourceView.NativePointer); + io.Fonts.ClearTexData(); + + // Create texture sampler + _fontSampler = new SamplerState(_device, new SamplerStateDescription + { + Filter = Filter.MinMagMipLinear, + AddressU = TextureAddressMode.Wrap, + AddressV = TextureAddressMode.Wrap, + AddressW = TextureAddressMode.Wrap, + MipLodBias = 0, + ComparisonFunction = Comparison.Always, + MinimumLod = 0, + MaximumLod = 0 + }); + } + + public bool CreateDeviceObjects() + { + if (_device == null) + { + return false; + } + + if (_fontSampler != null) + { + InvalidateDeviceObjects(); + } + + // Create the vertex shader + byte[] shaderData; + + var assembly = Assembly.GetExecutingAssembly(); + using (var stream = assembly.GetManifestResourceStream("imgui-vertex.hlsl.bytes")) + { + shaderData = new byte[stream.Length]; + stream.Read(shaderData, 0, shaderData.Length); + } + + _vertexShader = new VertexShader(_device, shaderData); + + // Create the input layout + _inputLayout = new InputLayout(_device, shaderData, new[] + { + new InputElement("POSITION", 0, Format.R32G32_Float, 0), + new InputElement("TEXCOORD", 0, Format.R32G32_Float, 0), + new InputElement("COLOR", 0, Format.R8G8B8A8_UNorm, 0) + }); + + // Create the constant buffer + _vertexConstantBuffer = new Buffer(_device, new BufferDescription + { + Usage = ResourceUsage.Dynamic, + BindFlags = BindFlags.ConstantBuffer, + CpuAccessFlags = CpuAccessFlags.Write, + OptionFlags = ResourceOptionFlags.None, + SizeInBytes = 16 * sizeof(float) + }); + + // Create the pixel shader + using (var stream = assembly.GetManifestResourceStream("imgui-frag.hlsl.bytes")) + { + shaderData = new byte[stream.Length]; + stream.Read(shaderData, 0, shaderData.Length); + } + + _pixelShader = new PixelShader(_device, shaderData); + + // Create the blending setup + // ...of course this was setup in a way that can't be done inline + var blendStateDesc = new BlendStateDescription(); + blendStateDesc.AlphaToCoverageEnable = false; + blendStateDesc.RenderTarget[0].IsBlendEnabled = true; + blendStateDesc.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha; + blendStateDesc.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha; + blendStateDesc.RenderTarget[0].BlendOperation = BlendOperation.Add; + blendStateDesc.RenderTarget[0].SourceAlphaBlend = BlendOption.InverseSourceAlpha; + blendStateDesc.RenderTarget[0].DestinationAlphaBlend = BlendOption.Zero; + blendStateDesc.RenderTarget[0].AlphaBlendOperation = BlendOperation.Add; + blendStateDesc.RenderTarget[0].RenderTargetWriteMask = ColorWriteMaskFlags.All; + _blendState = new BlendState(_device, blendStateDesc); + + // Create the rasterizer state + _rasterizerState = new RasterizerState(_device, new RasterizerStateDescription + { + FillMode = FillMode.Solid, + CullMode = CullMode.None, + IsScissorEnabled = true, + IsDepthClipEnabled = true + }); + + // Create the depth-stencil State + _depthStencilState = new DepthStencilState(_device, new DepthStencilStateDescription + { + IsDepthEnabled = false, + DepthWriteMask = DepthWriteMask.All, + DepthComparison = Comparison.Always, + IsStencilEnabled = false, + FrontFace = + { + FailOperation = StencilOperation.Keep, + DepthFailOperation = StencilOperation.Keep, + PassOperation = StencilOperation.Keep, + Comparison = Comparison.Always + }, + BackFace = + { + FailOperation = StencilOperation.Keep, + DepthFailOperation = StencilOperation.Keep, + PassOperation = StencilOperation.Keep, + Comparison = Comparison.Always + } + }); + + CreateFontsTexture(); + + return true; + } + + public void InvalidateDeviceObjects() + { + if (_device == null) + { + return; + } + + _fontSampler?.Dispose(); + _fontSampler = null; + + _fontResourceView?.Dispose(); + _fontResourceView = null; + ImGui.GetIO().Fonts.SetTexID(IntPtr.Zero); + + _indexBuffer?.Dispose(); + _indexBuffer = null; + + _vertexBuffer?.Dispose(); + _vertexBuffer = null; + + _blendState?.Dispose(); + _blendState = null; + + _depthStencilState?.Dispose(); + _depthStencilState = null; + + _rasterizerState?.Dispose(); + _rasterizerState = null; + + _pixelShader?.Dispose(); + _pixelShader = null; + + _vertexConstantBuffer?.Dispose(); + _vertexConstantBuffer = null; + + _inputLayout?.Dispose(); + _inputLayout = null; + + _vertexShader?.Dispose(); + _vertexShader = null; + } + + public void Init(Device dev, DeviceContext ctx) + { + ImGui.GetIO().BackendFlags = ImGui.GetIO().BackendFlags | ImGuiBackendFlags.RendererHasVtxOffset; + + // BackendRendererName is readonly (and null) in ImGui.NET for some reason, but we can hack it via its internal pointer + _renderNamePtr = Marshal.StringToHGlobalAnsi("imgui_impl_dx11_c#"); + unsafe + { + ImGui.GetIO().NativePtr->BackendRendererName = (byte*)_renderNamePtr.ToPointer(); + } + + _device = dev; + _deviceContext = ctx; + + // SharpDX also doesn't allow reference managment + } + + public void Shutdown() + { + InvalidateDeviceObjects(); + + // we don't own these, so no Dispose() + _device = null; + _deviceContext = null; + + if (_renderNamePtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(_renderNamePtr); + _renderNamePtr = IntPtr.Zero; + } + } + + public void NewFrame() + { + if (_fontSampler == null) + { + CreateDeviceObjects(); + } + } + } +} diff --git a/Dalamud/Game/Internal/DXGI/SwapChain.cs b/Dalamud/Game/Internal/DXGI/SwapChain.cs new file mode 100644 index 000000000..f49fc7647 --- /dev/null +++ b/Dalamud/Game/Internal/DXGI/SwapChain.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Dalamud.Hooking; +using ImGuiNET; +using Serilog; +using SharpDX.Direct3D11; + +namespace Dalamud.Game.Internal.DXGI { + public sealed class SwapChain : IDisposable { + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr PresentDelegate(IntPtr swapChain, uint a2, uint a3); + + private readonly Hook presentHook; + + private SwapChainAddressResolver Address { get; } + + private readonly Dalamud dalamud; + + private const string deviceguid = "3d3e0379-f9de-4d58-bb6c-18d62992f1a6"; + + public SwapChain(Dalamud dalamud, SigScanner scanner) { + this.dalamud = dalamud; + Address = new SwapChainAddressResolver(); + Address.Setup(scanner); + + Log.Verbose("===== S W A P C H A I N ====="); + Log.Verbose("Present address {Present}", Address.Present); + + this.presentHook = + new Hook(Address.Present, + new PresentDelegate(PresentDetour), + this); + Enable(); + } + + public void Enable() { + this.presentHook.Enable(); + } + + public void Dispose() { + this.presentHook.Dispose(); + } + + private ImGuiImplDx11 impl; + + private IntPtr PresentDetour(IntPtr swapChain, uint a2, uint a3) { + + + if (this.impl == null) { + var ret = this.presentHook.Original(swapChain, a2, a3); + + Log.Debug($"CDXGISwapChain::Present: swapChain->{swapChain.ToInt64():X} a2->{a2:X} a3->{a3:X} RET=>{ret.ToInt64():X}"); + + var s = new SharpDX.DXGI.SwapChain(swapChain); + var d = s.GetDevice(); + var ctx = d.ImmediateContext; + //s.GetDevice(Guid.Parse(deviceguid), out var device); + + Log.Verbose($"DEVICE: {d.NativePointer.ToInt64():X} CONTEXT: {ctx.NativePointer.ToInt64():X}"); + + ImGui.CreateContext(); + ImGui.StyleColorsDark(); + + this.impl = new ImGuiImplDx11(); + this.impl.Init(d, d.ImmediateContext); + + Log.Debug("Init OK"); + + return ret; + } else { + this.impl.NewFrame(); + Log.Debug("IMPL NewFrame OK"); + ImGui.NewFrame(); + Log.Debug("NewFrame OK"); + + ImGui.ShowDemoWindow(); + Log.Debug("ShowDemoWindow OK"); + + ImGui.Render(); + Log.Debug("Render OK"); + + this.impl.RenderDrawData(ImGui.GetDrawData()); + Log.Debug("RenderDrawData OK"); + + return this.presentHook.Original(swapChain, a2, a3); + } + } + } +} diff --git a/Dalamud/Game/Internal/DXGI/SwapChainAddressResolver.cs b/Dalamud/Game/Internal/DXGI/SwapChainAddressResolver.cs new file mode 100644 index 000000000..95f6dd924 --- /dev/null +++ b/Dalamud/Game/Internal/DXGI/SwapChainAddressResolver.cs @@ -0,0 +1,20 @@ +using System; +using System.Diagnostics; +using System.Linq; +using Serilog; + +namespace Dalamud.Game.Internal.DXGI +{ + public sealed class SwapChainAddressResolver : BaseAddressResolver { + public IntPtr Present { get; private set; } + + protected override void Setup64Bit(SigScanner sig) { + var module = Process.GetCurrentProcess().Modules.Cast().First(m => m.ModuleName == "dxgi.dll"); + + Log.Debug($"Found DXGI: {module.BaseAddress.ToInt64():X}"); + + var scanner = new SigScanner(module); + Present = scanner.ScanModule("48 89 5C 24 ?? 48 89 74 24 ?? 55 57 41 56 48 8D 6C 24 ??"); + } + } +} diff --git a/lib/ImGui.NET b/lib/ImGui.NET new file mode 160000 index 000000000..85b836ac6 --- /dev/null +++ b/lib/ImGui.NET @@ -0,0 +1 @@ +Subproject commit 85b836ac617a39560043c4add1e82e14ef0b1157