diff --git a/GlitchyEngine/src/Application.bf b/GlitchyEngine/src/Application.bf index 999a33a..ca173b2 100644 --- a/GlitchyEngine/src/Application.bf +++ b/GlitchyEngine/src/Application.bf @@ -2,6 +2,12 @@ using System; using GlitchyEngine.Events; using GlitchyEngine.Platform.DX11; using GlitchyEngine.ImGui; +using GlitchyEngine.Math; +using DirectX.D3D11; +using DirectX.Common; +using DirectX.D3DCompiler; +using System.Diagnostics; +using GlitchyEngine.Renderer; namespace GlitchyEngine { @@ -34,6 +40,156 @@ namespace GlitchyEngine _imGuiLayer = new ImGuiLayer(); PushOverlay(_imGuiLayer); + + MakeTestTriangle(); + } + + struct VertexColor : IVertexData + { + public Vector3 Position; + public Color Color; + + public this() => this = default; + + public this(Vector3 pos, Color color) + { + Position = pos; + Color = color; + } + + //public static readonly InputElementDescription[] InputLayout ~ delete _; + + public static readonly VertexLayout VertexLayout ~ delete _; + + public static VertexLayout IVertexData.VertexLayout => VertexLayout; + + static this() + { + //VertexLayout = new VertexLayout(); + } + } + + VertexBuffer _vertexBuffer ~ delete _; + IndexBuffer _indexBuffer ~ delete _; + + ID3D11VertexShader* _vertexShader ~ _?.Release(); + ID3D11PixelShader* _pixelShader ~ _?.Release(); + ID3D11InputLayout* _inputLayout ~ _?.Release(); + + ID3D11RasterizerState* _rasterizerState ~ _?.Release(); + + private Vector3 CircleCoord(float angle) + { + return .(Math.Cos(angle), Math.Sin(angle), 0); + } + + private void MakeTestTriangle() + { + // Compile vertex shader + ID3DBlob* vsCode = null; + ID3DBlob* errorBlob = null; + var result = D3DCompiler.D3DCompileFromFile("content\\basicShader.hlsl".ToScopedNativeWChar!(), null, .StandardInclude, "VS", "vs_5_0", .Debug, .None, &vsCode, &errorBlob); + + if(result.Failed || errorBlob != null) + { + Debug.Write("ERROR: Failed to compile Vertex Shader: {}", result); + //ErrorPrinter.PrintErrorBlob(errorBlob); + Runtime.FatalError("Failed to compile Vertex Shader"); + } + + result = Dx11Cheater.Device.CreateVertexShader(vsCode.GetBufferPointer(), vsCode.GetBufferSize(), null, &_vertexShader); + + if(result.Failed) + { + Debug.Write("ERROR: Failed to create Vertex Shader: {}", result); + Runtime.FatalError("Failed to create Vertex Shader"); + } + + // Create Input Layout + + InputElementDescription[2] elementDescs = .( + InputElementDescription("POSITION", 0, .R32G32B32_Float, 0), + InputElementDescription("COLOR", 0, .R8G8B8A8_UNorm, 0) + ); + + result = Dx11Cheater.Device.CreateInputLayout(&elementDescs, (.)elementDescs.Count, vsCode.GetBufferPointer(), vsCode.GetBufferSize(), &_inputLayout); + + vsCode.Release(); + + if(result.Failed) + { + Debug.Write("ERROR: Failed to create input layout: {}", result); + Runtime.FatalError("Failed to create input layout"); + } + + // + // Load pixel shader + // + + ID3DBlob* psCode = null; + + result = D3DCompiler.D3DCompileFromFile("content\\basicShader.hlsl".ToScopedNativeWChar!(), null, .StandardInclude, "PS", "ps_5_0", .Debug, .None, &psCode, &errorBlob); + + if(result.Failed || errorBlob != null) + { + Debug.Write("ERROR: Failed to compile Pixel Shader: {}", result); + //ErrorPrinter.PrintErrorBlob(errorBlob); + Runtime.FatalError("Failed to compile Pixel Shader"); + } + + result = Dx11Cheater.Device.CreatePixelShader(psCode.GetBufferPointer(), psCode.GetBufferSize(), null, &_pixelShader); + + psCode.Release(); + + if(result.Failed) + { + Debug.Write("ERROR: Failed to create Pixel Shader: {}", result); + Runtime.FatalError("Failed to create Pixel Shader"); + } + + float pO3 = Math.PI_f / 3.0f; + VertexColor[?] vertices = .( + VertexColor(.Zero, Color(255,255,255)), + VertexColor(CircleCoord(0), Color(255, 0, 0)), + VertexColor(CircleCoord(pO3), Color(255,255, 0)), + VertexColor(CircleCoord(pO3*2), Color( 0,255, 0)), + VertexColor(CircleCoord(Math.PI_f), Color( 0,255,255)), + VertexColor(CircleCoord(-pO3*2), Color( 0, 0,255)), + VertexColor(CircleCoord(-pO3), Color(255, 0,255)), + ); + + _vertexBuffer = new VertexBuffer(Window.Context, (.)vertices.Count, .Immutable); + _vertexBuffer.SetData(vertices); + + uint16[?] indices = .( + 0, 1, 2, + 0, 2, 3, + 0, 3, 4, + 0, 4, 5, + 0, 5, 6, + 0, 6, 1); + + _indexBuffer = new IndexBuffer(Window.Context, (.)indices.Count, .Immutable); + _indexBuffer.SetData(indices); + + if(result.Failed) + { + Debug.Write("ERROR: Failed to create Vertex Buffer: {}", result); + Runtime.FatalError(); + } + + // Create rasterizer state + RasterizerStateDescription rsDesc = .(); + rsDesc.CullMode = .Back; + rsDesc.FillMode = .Solid; + rsDesc.FrontCounterClockwise = true; + + result = Dx11Cheater.Device.CreateRasterizerState(ref rsDesc, &_rasterizerState); + if(result.Failed) + { + Debug.Write("ERROR: Failed to create Rasterizer State: {}", result); + Runtime.FatalError("Failed to create Rasterizer State"); + } } public void OnEvent(Event e) @@ -57,16 +213,38 @@ namespace GlitchyEngine Input.NewFrame(); - DirectX.ImmediateContext.ClearRenderTargetView(DirectX.BackBufferTarget, .(1, 0, 1)); + _window.Context.ClearRenderTarget(null, .(0.2f, 0.2f, 0.2f)); for(Layer layer in _layerStack) layer.Update(_gameTime); - + _window.Update(); + + _window.Context.SetRenderTarget(null); + _window.Context.BindRenderTargets(); + + Window.Context.SetVertexBuffer(0, _vertexBuffer); + Window.Context.SetIndexBuffer(_indexBuffer); + + var _immediateContext = Dx11Cheater.ImmediateContext; + + _immediateContext.InputAssembler.SetInputLayout(_inputLayout); + _immediateContext.InputAssembler.SetPrimitiveTopology(.TriangleList); + + _immediateContext.VertexShader.SetShader(_vertexShader, null, 0); + + _immediateContext.Rasterizer.SetState(_rasterizerState); + + + _immediateContext.Rasterizer.SetViewports(1, &Dx11Cheater.BackbufferViewport); + + _immediateContext.PixelShader.SetShader(_pixelShader, null, 0); + + Window.Context.DrawIndexed(3 * 6); _imGuiLayer.ImGuiRender(); - DirectX.Present(); + Window.Context.SwapChain.Present(); } } diff --git a/GlitchyEngine/src/ImGui/ImGuiLayer.bf b/GlitchyEngine/src/ImGui/ImGuiLayer.bf index 89e1e5c..e3609f7 100644 --- a/GlitchyEngine/src/ImGui/ImGuiLayer.bf +++ b/GlitchyEngine/src/ImGui/ImGuiLayer.bf @@ -4,6 +4,7 @@ using GlitchyEngine.Events; // Temporary using GlitchyEngine.Platform.DX11; +//using GlitchyEngine.Platform.DX11.Renderer; namespace GlitchyEngine.ImGui { @@ -40,8 +41,12 @@ namespace GlitchyEngine.ImGui #if GE_WINDOWS // Todo: temporary, needs to be platform independent ImGuiImplWin32.Init((Windows.HWnd)(int)Application.Get().Window.NativeWindow); - ImGuiImplDX11.Init(Platform.DX11.DirectX.Device, Platform.DX11.DirectX.ImmediateContext); + + var context = Application.Get().Window.Context; + + ImGuiImplDX11.Init(context.[Friend]nativeDevice, context.[Friend]nativeContext); #endif + } public override void OnDetach() @@ -174,8 +179,10 @@ namespace GlitchyEngine.ImGui public void Begin() { - var v = DirectX.ImmediateContext; - v.OutputMerger.SetRenderTargets(1, &DirectX.BackBufferTarget, null); + // Todo: + //var v = DirectX.ImmediateContext; + //v.OutputMerger.SetRenderTargets(1, &DirectX.BackBufferTarget, null); + Application.Get().Window.Context.SetRenderTarget(null); ImGuiImplDX11.NewFrame(); ImGuiImplWin32.NewFrame(); diff --git a/GlitchyEngine/src/Math/MathDefs.bf b/GlitchyEngine/src/Math/MathDefs.bf new file mode 100644 index 0000000..604ccc4 --- /dev/null +++ b/GlitchyEngine/src/Math/MathDefs.bf @@ -0,0 +1,14 @@ +namespace GlitchyEngine.Math +{ + typealias Color = DirectX.Color; + typealias ColorRGB = DirectX.ColorRGB; + typealias ColorRGBA = DirectX.ColorRGBA; + + typealias Vector2 = DirectX.Math.Vector2; + typealias Vector3 = DirectX.Math.Vector3; + typealias Vector4 = DirectX.Math.Vector4; + + typealias Matrix3x3 = DirectX.Math.Matrix3x3; + typealias Matrix4x3 = DirectX.Math.Matrix4x3; + typealias Matrix = DirectX.Math.Matrix; +} diff --git a/GlitchyEngine/src/Math/Point.bf b/GlitchyEngine/src/Math/Point.bf index 535f52c..91ae8fb 100644 --- a/GlitchyEngine/src/Math/Point.bf +++ b/GlitchyEngine/src/Math/Point.bf @@ -2,6 +2,7 @@ using System; namespace GlitchyEngine.Math { + /** * A 2D point represented by two 32bit integers. */ @@ -126,4 +127,5 @@ namespace GlitchyEngine.Math // public override void ToString(String strBuffer) => strBuffer.AppendF("X={0} Y={1}", X, Y); } + } diff --git a/GlitchyEngine/src/Platform/DX11/DirectX.bf b/GlitchyEngine/src/Platform/DX11/DirectX.bf deleted file mode 100644 index 8a6e47e..0000000 --- a/GlitchyEngine/src/Platform/DX11/DirectX.bf +++ /dev/null @@ -1,169 +0,0 @@ -using System; -using DirectX; -using DirectX.D3D11; -using DirectX.Common; -using System.Diagnostics; -using DirectX.DXGI; -using DirectX.DXGI.DXGI1_2; -using DirectX.D3D11.SDKLayers; -using static System.Windows; - -namespace GlitchyEngine.Platform.DX11 -{ - public static class DirectX - { - public static ID3D11Device* Device; - public static ID3D11DeviceContext* ImmediateContext; - public static ID3D11Debug* DebugDevice; - - public static IDXGIDevice* DxgiDevice; - public static IDXGISwapChain1* SwapChain; - - public static ID3D11RenderTargetView* BackBufferTarget; - public static Viewport BackBufferViewport; - - static HWnd _windowHandle; - - static ~this() - { - Shutdown(); - } - - public static void Init(HWnd windowHandle, uint32 width, uint32 height) - { - _windowHandle = windowHandle; - - InitDevice(); - UpdateSwapchain(width, height); - } - - /** - * Initializes the Device and ImmediateContext. - */ - static void InitDevice() - { - Device?.Release(); - Device = null; - - ImmediateContext?.Release(); - ImmediateContext = null; - - Log.EngineLogger.Trace("Creating D3D11 Device and Context..."); - - DeviceCreationFlags deviceFlags = .None; -#if DEBUG - deviceFlags |= .Debug; -#endif - - FeatureLevel[] levels = scope .(.Level_11_0); - - var deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &Device, let deviceLevel, &ImmediateContext); - Debug.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message(0x{(int32)deviceResult}): {deviceResult}"); - -#if DEBUG - if(Device.QueryInterface(out DebugDevice).Succeeded) - { - ID3D11InfoQueue* infoQueue; - if(Device.QueryInterface(out infoQueue).Succeeded) - { - infoQueue.SetBreakOnSeverity(.Corruption, true); - infoQueue.SetBreakOnSeverity(.Error, true); - - infoQueue.Release(); - } - } -#endif - - Log.EngineLogger.Trace("D3D11 Device and Context created (Feature level: {})", deviceLevel); - } - - static uint32 _width, _height; - - /** - * Initializes the swapchain. - */ - public static void UpdateSwapchain(uint32 width, uint32 height) - { - if(_width == width && _height == height) - return; - - _width = width; - _height = height; - - Log.EngineLogger.Trace("Updating swap chain ({}, {})", width, height); - - uint32 backBufferCount = 2; - Format backBufferFormat = .R8G8B8A8_UNorm; - Format backBufferViewFormat = .R8G8B8A8_UNorm; // _SRGB - - if(SwapChain != null) - { - BackBufferTarget.Release(); - - var resizeResult = SwapChain.ResizeBuffers(backBufferCount, width, height, backBufferFormat, .None); - Debug.Assert(resizeResult.Succeeded, scope $"Failed to resize swap chain. Message({(int32)resizeResult}):{resizeResult}"); - } - else - { - Device.QueryInterface(out DxgiDevice); - - DxgiDevice.GetAdapter(let adapter); - adapter.GetParent(let factory); - adapter.Release(); - - SwapChainDescription1 swDesc = .(); - swDesc.Width = width; - swDesc.Height = height; - swDesc.Format = backBufferFormat; - swDesc.SampleDescription = .(1, 0); - swDesc.BufferUsage = .RenderTargetOutput; - swDesc.BufferCount = backBufferCount; - swDesc.SwapEffect = .FlipDiscard; - - SwapChainFullscreenDescription fsSwapChainDesc = .(); - fsSwapChainDesc.Windowed = true; - - var createResult = factory.CreateSwapChainForHwnd((.)Device, _windowHandle, ref swDesc, &fsSwapChainDesc, null, &SwapChain); - Debug.Assert(createResult.Succeeded, scope $"Failed to create swap chain. Message({(int32)createResult}):{createResult}"); - - factory.Release(); - } - - SwapChain.GetBuffer(0, let backBuffer); - - RenderTargetViewDescription rtvDesc = .(backBuffer, .Texture2D, backBufferViewFormat); - Device.CreateRenderTargetView(backBuffer, &rtvDesc, &BackBufferTarget); - - BackBufferViewport = Viewport(0, 0, width, height, 0.0f, 1.0f); - - backBuffer.Release(); - } - - public static void Shutdown() - { - Device?.Release(); - Device = null; - - ImmediateContext?.Release(); - ImmediateContext = null; - - DxgiDevice?.Release(); - DxgiDevice = null; - - SwapChain?.Release(); - SwapChain = null; - - BackBufferTarget?.Release(); - BackBufferTarget = null; - - DebugDevice.ReportLiveDeviceObjects(.Detail); - DebugDevice?.Release(); - DebugDevice = null; - } - - public static void Present() - { - SwapChain.Present(Application.Get().Window.IsVSync ? 1 : 0, .None); - } - } -} diff --git a/GlitchyEngine/src/Platform/DX11/Dx11Cheater.bf b/GlitchyEngine/src/Platform/DX11/Dx11Cheater.bf new file mode 100644 index 0000000..d6c76dd --- /dev/null +++ b/GlitchyEngine/src/Platform/DX11/Dx11Cheater.bf @@ -0,0 +1,17 @@ +using DirectX.D3D11; +using DirectX.DXGI; + +namespace GlitchyEngine.Platform.DX11 +{ + public static class Dx11Cheater + { + public static ID3D11Device* Device; + public static ID3D11DeviceContext* ImmediateContext; + + public static ID3D11DeviceContext* Context => ImmediateContext; + + public static IDXGISwapChain* SwapChain; + public static ID3D11RenderTargetView* BackbufferTarget; + public static Viewport BackbufferViewport; + } +} diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Buffer.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Buffer.bf new file mode 100644 index 0000000..4c4898e --- /dev/null +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Buffer.bf @@ -0,0 +1,135 @@ +using System.Diagnostics; +using System; +using DirectX.D3D11; + +using internal GlitchyEngine.Renderer; + +namespace GlitchyEngine.Renderer +{ + extension CPUAccessFlags + { + public static explicit operator DirectX.D3D11.CpuAccessFlags(Self cpuAccessFlags) + { + DirectX.D3D11.CpuAccessFlags flags = .None; + + if(cpuAccessFlags.HasFlag(.Read)) + flags |= .Read; + + if(cpuAccessFlags.HasFlag(.Write)) + flags |= .Write; + + return flags; + } + } + + extension BufferDescription + { + public static operator DirectX.D3D11.BufferDescription(Self desc) + { + DirectX.D3D11.BufferDescription result; + + result.ByteWidth = desc.Size; + result.Usage = (.)desc.Usage; + + result.CpuAccessFlags = (.)desc.CPUAccess; + + result.BindFlags = .None; + if(desc.BindFlags.HasFlag(.Constant)) + { + result.BindFlags |= .ConstantBuffer; + } + if(desc.BindFlags.HasFlag(.Index)) + { + result.BindFlags |= .IndexBuffer; + } + if(desc.BindFlags.HasFlag(.Vertex)) + { + result.BindFlags |= .VertexBuffer; + } + + result.MiscFlags = .None; + result.StructureByteStride = 0; + + return result; + } + } + + public extension MapType + { + public static explicit operator DirectX.D3D11.MapType(Self mapType) + { + return (.)(uint32)mapType; + } + } + + public extension Buffer + { + // Todo: nativeBuffer contains exactly that! + internal DirectX.D3D11.BufferDescription nativeDescription; + + internal ID3D11Buffer* nativeBuffer ~ _?.Release(); + + private Result InternalCreateBuffer(void* data, uint32 byteLength, uint32 dstByteOffset) + { + nativeDescription = (.)_description; + + uint8* byteData = (.)data; + + if(dstByteOffset == 0) + { + byteData = new uint8[nativeDescription.ByteWidth]*; + defer:: delete byteData; + Internal.MemCpy(byteData + dstByteOffset, data, byteLength); + } + + SubresourceData srData = .(byteData, byteLength, 0); + var result = _context.nativeDevice.CreateBuffer(ref nativeDescription, &srData, &nativeBuffer); + if(result.Failed) + { + Log.EngineLogger.Error("Failed to create buffer. Message({}):{}", (int)result, result); + return .Err; + } + + return .Ok; + } + + protected override Result PlatformSetData(void* data, uint32 byteLength, uint32 dstByteOffset, GlitchyEngine.Renderer.MapType mapType) + { + if(nativeBuffer == null) + { + // We can pass the data while creating the buffer, so we can return here. + return InternalCreateBuffer(data, byteLength, dstByteOffset); + } + + Debug.Assert(dstByteOffset + byteLength <= _description.Size, "The destination offset and byte length are too long for the target buffer."); + + switch(nativeDescription.Usage) + { + case .Default: + Box dataBox = .(dstByteOffset, 0, 0, dstByteOffset + byteLength, 1, 1); + _context.nativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength); + case .Dynamic: + Debug.Assert(mapType.CanWrite, "The map type has to have write access."); + // Todo: DoNotWaitFlag + MappedSubresource map = ?; + _context.nativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map); + Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength); + _context.nativeContext.Unmap(nativeBuffer, 0); + Runtime.NotImplemented(); + case .Immutable: + Log.EngineLogger.Error("Can't set the data of an immutable resource."); + return .Err; + default: + Log.EngineLogger.Error("Unknown resource usage: engine={}, native={}", _description.Usage, nativeDescription.Usage); + return .Err; + } + + return .Ok; + } + } + + public extension VertexBuffer + { + + } +} diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf new file mode 100644 index 0000000..b92cc5a --- /dev/null +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf @@ -0,0 +1,159 @@ +using System; +using System.Diagnostics; +using DirectX.Common; +using DirectX.D3D11; +using DirectX.D3D11.SDKLayers; +using DirectX.DXGI.DXGI1_2; +using GlitchyEngine.Renderer; +using GlitchyEngine.Math; + +using GlitchyEngine.Platform.DX11; + +using internal GlitchyEngine.Renderer; +//using internal GlitchyEngine.Platform.DX11.Renderer; + +namespace GlitchyEngine.Renderer +//namespace GlitchyEngine.Platform.DX11.Renderer +{ + /// DirectX 11 specific implementation of the GraphicsContext + extension GraphicsContext + //public class Dx11Context : GraphicsContext + { + //private Dx11SwapChain _swapChain; + private SwapChain _swapChain; + + internal Windows.HWnd nativeWindowHandle; + + internal ID3D11Device* nativeDevice; + internal ID3D11DeviceContext* nativeContext; + + private ID3D11Debug* _debugDevice; + + public override SwapChain SwapChain => _swapChain; + + private const uint32 MaxRTVCount = DirectX.D3D11.D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + + //public static override uint32 MaxRenderTargetCount() => MaxRTVCount; + + public this(Windows.HWnd windowHandle) + { + nativeWindowHandle = windowHandle; + + _swapChain = new SwapChain(this); + //_swapChain = new Dx11SwapChain(this); + } + + public ~this() + { + delete _swapChain; + + nativeDevice?.Release(); + nativeContext?.Release(); + _debugDevice.ReportLiveDeviceObjects(.Detail); + _debugDevice?.Release(); + } + + public override void Init() + { + InitDevice(); + + SwapChain.Init(); + } + + /** + * Initializes the Device and ImmediateContext. + */ + void InitDevice() + { + nativeDevice?.Release(); + nativeContext?.Release(); + + Log.EngineLogger.Trace("Creating D3D11 Device and Context..."); + + DeviceCreationFlags deviceFlags = .None; +#if DEBUG + deviceFlags |= .Debug; +#endif + + FeatureLevel[] levels = scope .(.Level_11_0); + + var deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &nativeDevice, let deviceLevel, &nativeContext); + Debug.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message(0x{(int32)deviceResult}): {deviceResult}"); + +#if DEBUG + if(nativeDevice.QueryInterface(out _debugDevice).Succeeded) + { + ID3D11InfoQueue* infoQueue; + if(nativeDevice.QueryInterface(out infoQueue).Succeeded) + { + infoQueue.SetBreakOnSeverity(.Corruption, true); + infoQueue.SetBreakOnSeverity(.Error, true); + + infoQueue.Release(); + } + } +#endif + + Dx11Cheater.Device = nativeDevice; + Dx11Cheater.ImmediateContext = nativeContext; + + Log.EngineLogger.Trace("D3D11 Device and Context created (Feature level: {})", deviceLevel); + } + + + + private ID3D11RenderTargetView*[MaxRTVCount] _renderTargets; + + public override void SetRenderTarget(RenderTarget renderTarget, int slot = 0) + { + if(renderTarget == null) + { + _renderTargets[slot] = _swapChain.nativeBackBufferTarget; + //_immediateContext.OutputMerger.SetRenderTargets(1, &_swapChain._backBufferTarget, null); + } + else + { + Runtime.NotImplemented(); + } + } + + public override void BindRenderTargets() + { + nativeContext.OutputMerger.SetRenderTargets(MaxRTVCount, &_renderTargets, null); + } + + public override void ClearRenderTarget(RenderTarget renderTarget, ColorRGBA color) + { + if(renderTarget == null) + { + nativeContext.ClearRenderTargetView(_swapChain.nativeBackBufferTarget, color); + } + else + { + Runtime.NotImplemented(); + } + } + + public override void SetVertexBuffer(uint32 slot, Buffer buffer, uint32 stride, uint32 offset = 0) + { + // make stride and offset mutable so that we can take their pointers. + var stride, offset; + nativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset); + } + + public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0) + { + nativeContext.Draw(vertexCount, startVertexIndex); + } + + public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0) + { + nativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset); + } + + public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0) + { + nativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset); + } + } +} diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11SwapChain.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11SwapChain.bf new file mode 100644 index 0000000..8c3435d --- /dev/null +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11SwapChain.bf @@ -0,0 +1,155 @@ +using DirectX.D3D11; +using DirectX.DXGI.DXGI1_2; +using GlitchyEngine.Platform.DX11; +using System.Diagnostics; + +using internal GlitchyEngine.Renderer; + +namespace GlitchyEngine.Renderer +{ + public extension SwapChain + { + private GraphicsContext _context; + + private bool _changed; + + private uint32 _width, _height; + + internal DirectX.DXGI.IDXGIDevice* nativeDxgiDevice; + internal IDXGISwapChain1* nativeSwapChain; + + internal ID3D11RenderTargetView* nativeBackBufferTarget; + private DirectX.D3D11.Viewport _backBufferViewport; + + public override uint32 Width + { + get => _width; + + set + { + if(_width == value) + return; + + _width = value; + _changed = true; + } + } + + public override uint32 Height + { + get => _height; + + set + { + if(_height == value) + return; + + _height = value; + _changed = true; + } + } + + public override GraphicsContext Context => _context; + + //public this(Dx11Context context) + public this(GraphicsContext context) + { + _context = context; + + SetResolutionFromWindow(); + } + + public ~this() + { + nativeDxgiDevice?.Release(); + nativeSwapChain?.Release(); + nativeBackBufferTarget?.Release(); + } + + void SetResolutionFromWindow() + { + DirectX.Windows.Winuser.GetClientRect(_context.nativeWindowHandle, let rect); + + Width = (.)(rect.Right - rect.Left); + Height = (.)(rect.Bottom - rect.Top); + } + + public override void Init() + { + ApplyChanges(); + } + + public override void ApplyChanges() + { + if(!_changed) + return; + + UpdateSwapchain(); + } + + /** + * Initializes the swapchain. + */ + public void UpdateSwapchain() + { + Log.EngineLogger.Trace("Updating swap chain ({}, {})", _width, _height); + + uint32 backBufferCount = 2; + Format backBufferFormat = .R8G8B8A8_UNorm; + Format backBufferViewFormat = .R8G8B8A8_UNorm; // _SRGB + + if(nativeSwapChain != null) + { + nativeBackBufferTarget.Release(); + + var resizeResult = nativeSwapChain.ResizeBuffers(backBufferCount, _width, _height, backBufferFormat, .None); + Debug.Assert(resizeResult.Succeeded, scope $"Failed to resize swap chain. Message({(int32)resizeResult}):{resizeResult}"); + } + else + { + _context.nativeDevice.QueryInterface(out nativeDxgiDevice); + + nativeDxgiDevice.GetAdapter(let adapter); + adapter.GetParent(let factory); + adapter.Release(); + + SwapChainDescription1 swDesc = .(); + swDesc.Width = _width; + swDesc.Height = _height; + swDesc.Format = backBufferFormat; + swDesc.SampleDescription = .(1, 0); + swDesc.BufferUsage = .RenderTargetOutput; + swDesc.BufferCount = backBufferCount; + swDesc.SwapEffect = .FlipDiscard; + + SwapChainFullscreenDescription fsSwapChainDesc = .(); + fsSwapChainDesc.Windowed = true; + + var createResult = factory.CreateSwapChainForHwnd((.)_context.nativeDevice, _context.nativeWindowHandle, ref swDesc, &fsSwapChainDesc, null, &nativeSwapChain); + Debug.Assert(createResult.Succeeded, scope $"Failed to create swap chain. Message({(int32)createResult}):{createResult}"); + + factory.Release(); + + Dx11Cheater.SwapChain = nativeSwapChain; + } + + nativeSwapChain.GetBuffer(0, let backBuffer); + + RenderTargetViewDescription rtvDesc = .(backBuffer, .Texture2D, backBufferViewFormat); + _context.nativeDevice.CreateRenderTargetView(backBuffer, &rtvDesc, &nativeBackBufferTarget); + + Dx11Cheater.BackbufferTarget = nativeBackBufferTarget; + + _backBufferViewport = DirectX.D3D11.Viewport(0, 0, _width, _height, 0.0f, 1.0f); + + Dx11Cheater.BackbufferViewport = _backBufferViewport; + + backBuffer.Release(); + } + + public override void Present() + { + nativeSwapChain.Present(Application.Get().Window.IsVSync ? 1 : 0, .None); + } + } +} diff --git a/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf b/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf index 5e2827e..fdaf54e 100644 --- a/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf +++ b/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf @@ -9,6 +9,8 @@ using GlitchyEngine.Events; using System.Diagnostics; using GlitchyEngine.Platform.DX11; using GlitchyEngine.Math; +//using GlitchyEngine.Platform.DX11.Renderer; +using GlitchyEngine.Renderer; using static System.Windows; namespace GlitchyEngine @@ -31,6 +33,10 @@ namespace GlitchyEngine private bool _isVSync = true; + private GraphicsContext _graphicsContext ~ delete _; + + public override GraphicsContext Context => _graphicsContext; + public override int32 MinWidth { get => _minMaxInfo.MinimumTrackingSize.x; @@ -191,16 +197,19 @@ namespace GlitchyEngine _windowHandle = CreateWindowExW(.None, _windowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null); + + //_graphicsContext = new Dx11Context(_windowHandle); + _graphicsContext = new GraphicsContext(_windowHandle); + _graphicsContext.Init(); void* myPtr = Internal.UnsafeCastToPtr(this); - SetWindowLongPtrW(_windowHandle, GWL_USERDATA, (int)myPtr); LoadWindowRectangle(); Log.EngineLogger.Trace("Created window \"{}\" ({}, {})", Title, Width, Height); - DirectX.Init(_windowHandle, (.)Width, (.)Height); + //DirectX.Init(_windowHandle, (.)Width, (.)Height); } private bool _isResizingOrMoving; @@ -249,7 +258,11 @@ namespace GlitchyEngine { SplitHighAndLowOrder!(lParam, out window._clientRect.Width, out window._clientRect.Height); - DirectX.UpdateSwapchain((.)window._clientRect.Width, (.)window._clientRect.Height); + window._graphicsContext.SwapChain.Width = (.)window._clientRect.Width; + window._graphicsContext.SwapChain.Height = (.)window._clientRect.Height; + + window._graphicsContext.SwapChain.ApplyChanges(); + WindowResizeEvent event = scope WindowResizeEvent(window._clientRect.Width, window._clientRect.Height, window._isResizingOrMoving); window._eventCallback(event); } diff --git a/GlitchyEngine/src/Renderer/Buffer.bf b/GlitchyEngine/src/Renderer/Buffer.bf new file mode 100644 index 0000000..bd9ae56 --- /dev/null +++ b/GlitchyEngine/src/Renderer/Buffer.bf @@ -0,0 +1,279 @@ +using System; + +namespace GlitchyEngine.Renderer +{ + /** + * Identifies expected resource use during rendering. + * The usage directly reflects whether a resource is accessible by the CPU and/or the graphics processing unit (GPU). + */ + public enum Usage + { + /** + * A resource that requires read and write access by the GPU. + * This is likely to be the most common usage choice. + */ + Default = 0, + /** + * A resource that can only be read by the GPU. It cannot be written by the GPU, and cannot be accessed at all by the CPU. + */ + Immutable = 1, + /** + * A resource that is accessible by both the GPU (read only) and the CPU (write only). + * A dynamic resource is a good choice for a resource that will be updated by the CPU at least once per frame. + * To update a dynamic resource, use a Map method. + */ + Dynamic = 2, + /** + * A resource that supports data transfer (copy) from the GPU to the CPU. + */ + Staging = 3 + } + + /** + * Defines how the CPU can access a resource. + */ + public enum CPUAccessFlags + { + /// The CPU has no access to the resource. + None = 0, + /// The CPU has read access to the resource. + Read = 1, + /// The CPU has write access to the resource. + Write = 2 + } + + /** + * Defines how to bind a buffer to the pipeline. + */ + public enum BufferBindFlags + { + /// No binding flags specified + None = 0, + /// The Buffer contains vertex data + Vertex = 1, + /// The Buffer contains index data + Index = 2, + // The Buffer contains constant data + Constant = 4, + // ShaderResource? + // UnorderedAccess? + } + + public enum BufferMiscFlags + { + None = 0, + //AllowRawView = 1, + //Structured = 2, + } + + typealias Format = DirectX.DXGI.Format; + + public struct BufferDescription + { + /** + * The size of the buffer in bytes. + */ + public uint32 Size; + + /** + * Identify how the buffer is expected to be read from and written to. Frequency of update is a key factor. + * The most common value is typically Default. + */ + public Usage Usage; + + public CPUAccessFlags CPUAccess; + + public BufferBindFlags BindFlags; + + public BufferMiscFlags MiscFlags; + + // Strucutred Byte stride. + + public this() => this = default; + + public this(uint32 size, BufferBindFlags bindFlags, Usage usage = .Default, CPUAccessFlags cpuAccess = .None, BufferMiscFlags miscFlags = .None) + { + Size = size; + BindFlags = bindFlags; + Usage = usage; + CPUAccess = cpuAccess; + MiscFlags = miscFlags; + } + } + + public enum MapType + { + case None; + case Read; + case Write; + case ReadWrite; + case WriteDiscard; + case WriteNoOverwrite; + + public bool CanWrite => this == Write || + this == ReadWrite || + this == WriteDiscard || + this == WriteNoOverwrite; + + public bool CanRead => this == Read || + this == ReadWrite; + } + + /// Represents a buffer containing binary data on the GPU. + public class Buffer + { + internal GraphicsContext _context; + + protected BufferDescription _description; + + public GraphicsContext Context => _context; + + public BufferDescription Description => _description; + + protected this(GraphicsContext context) + { + _context = context; + } + + /** + * Creates a new instance of a Buffer. + * @param description The buffer description. + */ + public this(GraphicsContext context, BufferDescription description) : this(context) + { + _description = description; + } + + /** + * @param data The span containing the data that will be copied into the buffer. + * @param destinationByteOffset The offset in bytes form the start of the destination buffer. + * @param mapType Only relevant for dynamic buffers... + */ + public Result SetData(Span data, uint32 destinationByteOffset = 0, MapType mapType = .Write) where T : struct + { + return PlatformSetData(data.Ptr, (uint32)(data.Length * sizeof(T)), destinationByteOffset, mapType); + } + + /** + * @param data The span containing the data that will be copied into the buffer. + * @param destinationByteOffset The offset in bytes form the start of the destination buffer. + * @param mapType Only relevant for dynamic buffers... + */ + public Result SetData(T* data, uint32 elementCount, uint32 destinationByteOffset = 0, MapType mapType = .Write) where T : struct + { + return PlatformSetData(data, elementCount * (uint32)sizeof(T), destinationByteOffset, mapType); + } + + public Result SetData(T[CLength] data, uint32 destinationByteOffset = 0, MapType mapType = .Write) where T : struct where CLength : const int + { + var data; + return PlatformSetData(&data, (uint32)sizeof(T[CLength]), destinationByteOffset, mapType); + } + + /** + * // Todo: as soon as Beef supports generic method override, change to generic? + * Platform specific implementation of SetData. + * @param data The pointer to the source data that will be copied to the buffer. + * @param data The number of bytes that will be copied. + * @param dstByteOffset The offset from the start of the target buffer. + */ + protected extern Result PlatformSetData(void* data, uint32 byteLength, uint32 dstByteOffset, MapType mapType); + } + + /** + * Type of data contained in an input slot. + */ + public enum InputClassification + { + /** + * Input data is per-vertex data. + */ + PerVertexData = 0, + /** + * Input data is per-instance data. + */ + PerInstanceData = 1 + } + + public struct VertexElement + { + /** + * The semantic associated with this element in a shader input-signature. + */ + public String SemanticName; + /** + * The semantic index for the element. + * A semantic index modifies a semantic, with an integer index number. + * A semantic index is only needed in a case where there is more than one element with the same semantic. + * For example, a 4x4 matrix would have four components each with the semantic name "matrix", + * however each of the four component would have different semantic indices (0, 1, 2, and 3). + */ + public uint32 SemanticIndex; + /** + * The data type of the element data. + */ + public Format Format; + /** + * An integer value that identifies the input-assembler (see input slot). Valid values are between 0 and 15. + */ + public uint32 InputSlot; + /** + * Optional. Offset (in bytes) from the start of the vertex. Use AppendAligned for convenience to define the current element directly after the previous one, including any packing if necessary. + */ + public uint32 AlignedByteOffset; + /** + * Identifies the input data class for a single input slot. + */ + public InputClassification InputSlotClass; + /** + * The number of instances to draw using the same per-instance data before advancing in the buffer by one element. + * This value must be 0 for an element that contains per-vertex data (the slot class is set to PerVertexData). + */ + public uint32 InstanceDataStepRate; + + public this() => this = default; + + public this(String semanticName, uint32 semanticIndex, Format format, uint32 inputSlot, uint32 offset = (.)-1, InputClassification slotClass = .PerVertexData, uint32 instanceStepRate = 0) + { + SemanticName = semanticName; + SemanticIndex = semanticIndex; + Format = format; + InputSlot = inputSlot; + AlignedByteOffset = offset; + InputSlotClass = slotClass; + InstanceDataStepRate = instanceStepRate; + } + + /** + * Use AppendAligned for convenience to define the current element directly after the previous one, including any packing if necessary. + */ + public static readonly uint32 AppendAligned = 0xffffffff; + } + + public abstract class VertexLayout + { + private GraphicsContext _context; + + private VertexElement[] _elements ~ delete _; + + public GraphicsContext Context => _context; + + public VertexElement[] Elements => _elements; + + /// Takes ownership of ownElements! + public this(GraphicsContext context, VertexElement[] ownElements) + { + _context = context; + _elements = ownElements; + + //CreateNativeLayout(); + } + + private extern void CreateNativeLayout(); + } + + public interface IVertexData + { + static VertexLayout VertexLayout {get;} + } +} diff --git a/GlitchyEngine/src/Renderer/GraphicsContext.bf b/GlitchyEngine/src/Renderer/GraphicsContext.bf new file mode 100644 index 0000000..3edbcb5 --- /dev/null +++ b/GlitchyEngine/src/Renderer/GraphicsContext.bf @@ -0,0 +1,80 @@ +using GlitchyEngine.Math; + +namespace GlitchyEngine.Renderer +{ + public class RenderTarget; + + //public abstract class GraphicsContext + public class GraphicsContext + { + //public abstract SwapChain SwapChain {get;} + public extern SwapChain SwapChain {get;} + + /** + * The maximum number of simultaneous rendertargets supported. + */ + //public static extern uint32 MaxRenderTargetCount(); + + //public abstract void Init(); + public extern void Init(); + + /** + * Sets a rendertarget. + * @param renderTarget The render target. + * @param slot The slot to which the rendertarget will be bound. + * @remarks When @RenderTarget is null the backbuffer will be bound. + * @BindRenderTargets has to be called in order to bind the rendertargets. + */ + //public abstract void SetRenderTarget(RenderTarget renderTarget, int slot = 0); + public extern void SetRenderTarget(RenderTarget renderTarget, int slot = 0); + + /** + * Binds all. + * @param renderTarget The render target. + * @param slot The slot to which the rendertarget will be bound. + * @remarks When @RenderTarget is null the backbuffer will be bound. + */ + //public abstract void BindRenderTargets(); // Todo: maybe do this automatically when a drawcall is issued + public extern void BindRenderTargets(); // Todo: maybe do this automatically when a drawcall is issued + + /** + * Sets all elements in the given render target to one value. + * @param renderTarget The render target. + * @param color The color to clear the render target with. + * @remarks When @renderTarget is null the backbuffer will be cleared. + */ + //public abstract void ClearRenderTarget(RenderTarget renderTarget, ColorRGBA color); + public extern void ClearRenderTarget(RenderTarget renderTarget, ColorRGBA color); + + //public abstract void SetViewport(Viewport viewport); + + /** + * Binds a VertexBuffer to the pipeline. + * @param buffer The vertex buffer to bind. + * Note: the buffer has to have BindFlags.Vertex! + * @param slot The slot the vertex buffer will be bound to. + * @param offset The offset in bytes from the start of the buffer. + * @param stride The stride of the + */ + public extern void SetVertexBuffer(uint32 slot, Buffer buffer, uint32 stride, uint32 offset = 0); + + /** + * Binds a VertexBuffer to the pipeline. + */ + public void SetVertexBuffer(uint32 slot, VertexBufferBinding binding) + { + SetVertexBuffer(slot, binding.Buffer, binding.Stride, binding.Offset); + } + + public extern void Draw(uint32 vertexCount, uint32 startVertexIndex = 0); + + public extern void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0); + + public void SetIndexBuffer(IndexBuffer indexBuffer, uint32 byteOffset = 0) + { + SetIndexBuffer(indexBuffer, indexBuffer.Format, byteOffset); + } + + public extern void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0); + } +} diff --git a/GlitchyEngine/src/Renderer/IndexBuffer.bf b/GlitchyEngine/src/Renderer/IndexBuffer.bf new file mode 100644 index 0000000..3d0a911 --- /dev/null +++ b/GlitchyEngine/src/Renderer/IndexBuffer.bf @@ -0,0 +1,32 @@ +namespace GlitchyEngine.Renderer +{ + public enum IndexFormat + { + Index16Bit, + Index32Bit, + } + + public class IndexBuffer : Buffer + { + private uint32 _indexCount; + private IndexFormat _format; + + public uint32 IndexCount => _indexCount; + public IndexFormat Format => _format; + + public this(GraphicsContext context, uint32 indexCount, Usage usage = .Default, CPUAccessFlags cpuAccess = .None, IndexFormat indexFormat = .Index16Bit) : base(context) + { + _indexCount = indexCount; + _format = indexFormat; + + _description = .() + { + Size = (_format == .Index32Bit ? 4 : 2) * _indexCount, + Usage = usage, + CPUAccess = cpuAccess, + BindFlags = .Index, + MiscFlags = .None + }; + } + } +} diff --git a/GlitchyEngine/src/Renderer/SwapChain.bf b/GlitchyEngine/src/Renderer/SwapChain.bf new file mode 100644 index 0000000..5790c5f --- /dev/null +++ b/GlitchyEngine/src/Renderer/SwapChain.bf @@ -0,0 +1,30 @@ +namespace GlitchyEngine.Renderer +{ + public class SwapChain + { + public extern GraphicsContext Context {get;} + + /** + * Gets or Sets the backbuffers width. + * @remarks @ApplyChanges() needs to be called in order to apply the ganges. + */ + public extern uint32 Width {get; set;} + /** + * Gets or Sets the backbuffers height. + * @remarks @ApplyChanges() needs to be called in order to apply the ganges. + */ + public extern uint32 Height {get; set;} + + public extern void Init(); + + /** + * Applies all changes to the swapchain. + */ + public extern void ApplyChanges(); + + /** + * Swaps the front- and backbuffer. + */ + public extern void Present(); + } +} diff --git a/GlitchyEngine/src/Renderer/VertexBuffer.bf b/GlitchyEngine/src/Renderer/VertexBuffer.bf new file mode 100644 index 0000000..1e85687 --- /dev/null +++ b/GlitchyEngine/src/Renderer/VertexBuffer.bf @@ -0,0 +1,45 @@ +using System; +namespace GlitchyEngine.Renderer +{ + public struct VertexBufferBinding + { + public Buffer Buffer; + public uint32 Stride; + public uint32 Offset; + + public this(Buffer buffer, uint32 stride, uint32 offset = 0) + { + Buffer = buffer; + Stride = stride; + Offset = offset; + } + } + + public class VertexBuffer : Buffer where T: struct, IVertexData + { + private VertexBufferBinding _defaultBinding; + + public VertexBufferBinding Binding => _defaultBinding; + + public this(GraphicsContext context, uint32 vertexCount, Usage usage = .Default, CPUAccessFlags cpuAccess = .None) : base(context) + { + _description = .(){ + Size = ((uint32)sizeof(T) * vertexCount), + Usage = usage, + CPUAccess = cpuAccess, + BindFlags = .Vertex, + MiscFlags = .None + }; + + _defaultBinding = .(this, (.)sizeof(T), 0); + } + + public Result SetData(Span data, uint32 destinationVertexOffset = 0, MapType mapType = .Write) + { + return SetData(data, destinationVertexOffset * (uint32)sizeof(T)); + } + + [Inline] + public static implicit operator VertexBufferBinding(Self buffer) => buffer._defaultBinding; + } +} diff --git a/GlitchyEngine/src/Renderer/Viewport.bf b/GlitchyEngine/src/Renderer/Viewport.bf new file mode 100644 index 0000000..ae1b7b3 --- /dev/null +++ b/GlitchyEngine/src/Renderer/Viewport.bf @@ -0,0 +1,30 @@ +namespace GlitchyEngine.Renderer +{ + public struct Viewport + { + /// X position of the left hand side of the viewport. + public float Left; + /// Y position of the top of the viewport. Ranges between BoundsMin and BoundsMax. + public float Top; + /// Width of the viewport. + public float Width; + /// Height of the viewport. + public float Height; + /// Minimum depth of the viewport. Ranges between 0 and 1. + public float MinDepth; + /// Maximum depth of the viewport. Ranges between 0 and 1. + public float MaxDepth; + + public this() => this = default; + + public this(float left, float top, float width, float height, float minDepth = 0.0f, float maxDepth = 1.0f) + { + Left = left; + Top = top; + Width = width; + Height = height; + MinDepth = minDepth; + MaxDepth = maxDepth; + } + } +} diff --git a/GlitchyEngine/src/Window.bf b/GlitchyEngine/src/Window.bf index 0a4c003..b8b24de 100644 --- a/GlitchyEngine/src/Window.bf +++ b/GlitchyEngine/src/Window.bf @@ -1,6 +1,7 @@ using System; using GlitchyEngine.Events; using GlitchyEngine.Math; +using GlitchyEngine.Renderer; namespace GlitchyEngine { @@ -86,6 +87,11 @@ namespace GlitchyEngine * Gets or Sets whether or not the application uses VSync */ public extern bool IsVSync {get; set;} + + /** + * Gets the windows graphics context. + */ + public extern GraphicsContext Context {get;} /** * Gets a pointer to the platform specific window representation. diff --git a/Sandbox/content/basicShader.hlsl b/Sandbox/content/basicShader.hlsl new file mode 100644 index 0000000..72c8200 --- /dev/null +++ b/Sandbox/content/basicShader.hlsl @@ -0,0 +1,25 @@ +struct VS_IN +{ + float3 Position : POSITION; + float4 Color : COLOR; +}; + +struct PS_IN +{ + float4 Position : SV_POSITION; + float4 Color : COLOR; +}; + +PS_IN VS(VS_IN input) +{ + PS_IN output; + output.Position = float4(input.Position, 1); + output.Color = input.Color; + + return output; +} + +float4 PS(PS_IN input) : SV_TARGET +{ + return input.Color; +} \ No newline at end of file diff --git a/Sandbox/content/directx.ico b/Sandbox/content/directx.ico new file mode 100644 index 0000000..ae04226 Binary files /dev/null and b/Sandbox/content/directx.ico differ diff --git a/Sandbox/src/SandboxApp.bf b/Sandbox/src/SandboxApp.bf index ad63efb..ffb5124 100644 --- a/Sandbox/src/SandboxApp.bf +++ b/Sandbox/src/SandboxApp.bf @@ -4,6 +4,7 @@ using GlitchyEngine.Events; using System.Diagnostics; using GlitchLog; using GlitchyEngine.ImGui; +using ImGui; namespace Sandbox { @@ -29,9 +30,9 @@ namespace Sandbox private bool OnImGuiRender(ImGuiRenderEvent e) { - ImGui.ImGui.Begin("Test"); + ImGui.Begin("Test"); - ImGui.ImGui.End(); + ImGui.End(); return false; }