#include <Graphics/MeshRenderer.h>

#include <Core/HAL/Filesystem/Filesystem.h>
#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Core/Math/Matrix.h>
#include <Graphics/GraphicsDevice.h>
#include <Graphics/Mesh.h>
#include <Graphics/VertexData.h>

namespace Juliet
{
    namespace
    {
        struct MeshRendererState
        {
            GraphicsDevice*         Device           = nullptr;
            GraphicsPipeline*       Pipeline         = nullptr;
            GraphicsBuffer*         VertexBuffer     = nullptr;
            GraphicsBuffer*         IndexBuffer      = nullptr;
            GraphicsBuffer*         LightsBuffer     = nullptr;
            GraphicsBuffer*         TransformsBuffer = nullptr;
            GraphicsTransferBuffer* LoadCopyBuffer   = nullptr;

            VectorArena<Mesh, kDefaultMeshNumber>       Meshes;
            VectorArena<Vertex, kDefaultVertexCount>    Vertices;
            VectorArena<Index, kDefaultIndexCount>      Indices;
            VectorArena<PointLight, kDefaultLightCount> PointLights;

            PointLight* MappedLights     = nullptr;
            Matrix*     MappedTransforms = nullptr;
        };

        MeshRendererState g_MeshRenderer;
    } // namespace

    void InitializeMeshRenderer(NonNullPtr<Arena> arena)
    {
        g_MeshRenderer.Meshes.Create(arena JULIET_DEBUG_PARAM("Meshes"));
        g_MeshRenderer.Vertices.Create(arena JULIET_DEBUG_PARAM("Vertices"));
        g_MeshRenderer.Indices.Create(arena JULIET_DEBUG_PARAM("Indices"));
        g_MeshRenderer.PointLights.Create(arena JULIET_DEBUG_PARAM("PointLights"));
    }

    bool InitializeMeshRendererGraphics(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
    {
        bool result = true;

        GraphicsDevice* graphicsDevice = g_MeshRenderer.Device = device.Get();

        // Create graphics pipeline
        String           entryPoint = WrapString("main");
        ShaderCreateInfo shaderCI   = {};
        shaderCI.EntryPoint         = entryPoint;

        String shaderPath    = GetAssetPath(WrapString("Triangle.vert.dxil"));
        shaderCI.Stage       = ShaderStage::Vertex;
        Shader* vertexShader = CreateShader(graphicsDevice, shaderPath, shaderCI);

        shaderPath             = GetAssetPath(WrapString("SolidColor.frag.dxil"));
        shaderCI.Stage         = ShaderStage::Fragment;
        Shader* fragmentShader = CreateShader(graphicsDevice, shaderPath, shaderCI);

        ColorTargetDescription colorTargetDescription = {};
        colorTargetDescription.Format                 = GetSwapChainTextureFormat(graphicsDevice, window);

        GraphicsPipelineCreateInfo pipelineCI         = {};
        pipelineCI.VertexShader                       = vertexShader;
        pipelineCI.FragmentShader                     = fragmentShader;
        pipelineCI.PrimitiveType                      = PrimitiveType::TriangleList;
        pipelineCI.TargetInfo                         = { .ColorTargetDescriptions = &colorTargetDescription,
                                                          .NumColorTargets         = 1,
                                                          .DepthStencilFormat      = TextureFormat::D32_FLOAT,
                                                          .HasDepthStencilTarget   = true };
        pipelineCI.RasterizerState.FillMode           = FillMode::Solid;
        pipelineCI.RasterizerState.CullMode           = CullMode::None;
        pipelineCI.RasterizerState.FrontFace          = FrontFace::Clockwise;
        pipelineCI.DepthStencilState.EnableDepthTest  = true;
        pipelineCI.DepthStencilState.EnableDepthWrite = true;
        pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less;

        g_MeshRenderer.Pipeline = CreateGraphicsPipeline(graphicsDevice, pipelineCI);
        if (g_MeshRenderer.Pipeline == nullptr)
        {
            LogError(LogCategory::Graphics, "Failed to create graphics pipeline!");
            result = false;
        }

        // Create the vertex and index buffers
        BufferCreateInfo vertexBufferCI = {};
        vertexBufferCI.Size             = kGeometryPage;
        vertexBufferCI.Stride           = 0;
        vertexBufferCI.Usage            = BufferUsage::StructuredBuffer;
        g_MeshRenderer.VertexBuffer     = CreateGraphicsBuffer(graphicsDevice, vertexBufferCI);
        Assert(g_MeshRenderer.VertexBuffer != nullptr);

        BufferCreateInfo indexBufferCI = {};
        indexBufferCI.Size             = kIndexPage;
        indexBufferCI.Usage            = BufferUsage::IndexBuffer;
        g_MeshRenderer.IndexBuffer     = CreateGraphicsBuffer(graphicsDevice, indexBufferCI);
        Assert(g_MeshRenderer.IndexBuffer != nullptr);

        // Lights Buffer
        BufferCreateInfo lightsBufferCI = {};
        lightsBufferCI.Size             = 1024 * sizeof(PointLight); // Max 1024 lights for now
        lightsBufferCI.Stride           = sizeof(PointLight);
        lightsBufferCI.Usage            = BufferUsage::StructuredBuffer;
        lightsBufferCI.IsDynamic        = true;
        g_MeshRenderer.LightsBuffer     = CreateGraphicsBuffer(graphicsDevice, lightsBufferCI);
        Assert(g_MeshRenderer.LightsBuffer != nullptr);
        g_MeshRenderer.MappedLights = static_cast<PointLight*>(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.LightsBuffer));
        Assert(g_MeshRenderer.MappedLights != nullptr);

        // Transforms Buffer
        BufferCreateInfo transformsBufferCI = {};
        transformsBufferCI.Size             = 10000 * sizeof(Matrix); // Max 10000 meshes for now
        transformsBufferCI.Stride           = sizeof(Matrix);
        transformsBufferCI.Usage            = BufferUsage::StructuredBuffer;
        transformsBufferCI.IsDynamic        = true;
        g_MeshRenderer.TransformsBuffer     = CreateGraphicsBuffer(graphicsDevice, transformsBufferCI);
        Assert(g_MeshRenderer.TransformsBuffer != nullptr);
        g_MeshRenderer.MappedTransforms =
            static_cast<Matrix*>(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.TransformsBuffer));
        Assert(g_MeshRenderer.MappedTransforms != nullptr);

        // Sync existing lights that might have been added before graphics initialization
        for (index_t i = 0; i < g_MeshRenderer.PointLights.Count; ++i)
        {
            g_MeshRenderer.MappedLights[i] = g_MeshRenderer.PointLights.Data[i];
        }

        if (vertexShader)
        {
            DestroyShader(graphicsDevice, vertexShader);
        }
        if (fragmentShader)
        {
            DestroyShader(graphicsDevice, fragmentShader);
        }

        // Load evereything that is already in the vectors
        CommandList* loadCmd = AcquireCommandList(device);
        LoadMeshesOnGPU(loadCmd);
        SubmitCommandLists(loadCmd);
        return result;
    }

    void ShutdownMeshRendererGraphics()
    {
        if (g_MeshRenderer.LoadCopyBuffer)
        {
            UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
            DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
            g_MeshRenderer.LoadCopyBuffer = nullptr;
        }

        DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.IndexBuffer);
        DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);

        if (g_MeshRenderer.LightsBuffer)
        {
            UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
            DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
            g_MeshRenderer.LightsBuffer = nullptr;
        }

        if (g_MeshRenderer.TransformsBuffer)
        {
            UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer);
            DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer);
            g_MeshRenderer.TransformsBuffer = nullptr;
        }
    }

    void ShutdownMeshRenderer()
    {
        g_MeshRenderer.Indices.Destroy();
        g_MeshRenderer.Vertices.Destroy();
        g_MeshRenderer.Meshes.Destroy();
        g_MeshRenderer.PointLights.Destroy();
    }

    void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList)
    {
        if (g_MeshRenderer.Meshes.IsEmpty())
        {
            return;
        }

        // Loading everything in one go.
        // Destroy the buffer at the end

        TransferBufferCreateInfo uploadBCI = {};
        uploadBCI.Usage                    = TransferBufferUsage::Upload;
        uploadBCI.Size                     = kGeometryPage + kIndexPage;
        g_MeshRenderer.LoadCopyBuffer      = CreateGraphicsTransferBuffer(g_MeshRenderer.Device, uploadBCI);

        void* map = MapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);

        Vertex* vertices = g_MeshRenderer.Vertices.Data;
        if (!vertices)
        {
            UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
            DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
            g_MeshRenderer.LoadCopyBuffer = nullptr;
            return;
        }

        Index* indices = g_MeshRenderer.Indices.Data;
        if (!indices)
        {
            UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
            DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
            g_MeshRenderer.LoadCopyBuffer = nullptr;
            return;
        }

        // Copy all meshes! This supports only one page for now
        // Copy ALL Vertices in one block
        size_t totalVertexBytes = g_MeshRenderer.Vertices.Count * sizeof(Vertex);
        MemCopy(map, g_MeshRenderer.Vertices.Data, totalVertexBytes);

        // Copy ALL Indices in one block
        size_t indexOfByteOffset = (kGeometryPage + 255) & static_cast<size_t>(~255);
        uint8* ptrOneByte        = static_cast<uint8*>(map);
        size_t totalIndexBytes   = g_MeshRenderer.Indices.Count * sizeof(Index);

        MemCopy(ptrOneByte + indexOfByteOffset, g_MeshRenderer.Indices.Data, totalIndexBytes);

        UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);

        CopyBuffer(cmdList, g_MeshRenderer.VertexBuffer, g_MeshRenderer.LoadCopyBuffer, totalVertexBytes, 0, 0);
        CopyBuffer(cmdList, g_MeshRenderer.IndexBuffer, g_MeshRenderer.LoadCopyBuffer, totalIndexBytes, 0, indexOfByteOffset);

        // Transition vertex buffer to SRV state (this barrier waits for copy to complete)
        TransitionBufferToReadable(cmdList, g_MeshRenderer.VertexBuffer);
        TransitionBufferToReadable(cmdList, g_MeshRenderer.IndexBuffer);
    }

    void RenderMeshes(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, PushData& pushData)
    {
        // First destroy any buffer that needs to be
        if (g_MeshRenderer.LoadCopyBuffer)
        {
            WaitUntilGPUIsIdle(g_MeshRenderer.Device);
            UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
            DestroyGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
            g_MeshRenderer.LoadCopyBuffer = nullptr;
        }

        BindGraphicsPipeline(pass, g_MeshRenderer.Pipeline);

        uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);
        uint32 lightDescriptorIndex  = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);

        uint32 transformsDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.TransformsBuffer);

        pushData.BufferIndex           = vertexDescriptorIndex;
        pushData.LightBufferIndex      = lightDescriptorIndex;
        pushData.TransformsBufferIndex = transformsDescriptorIndex;
        pushData.ActiveLightCount      = static_cast<uint32>(g_MeshRenderer.PointLights.Count);

        SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0);

        uint32 meshIndex = 0;
        for (Mesh& mesh : g_MeshRenderer.Meshes)
        {
            if (g_MeshRenderer.MappedTransforms)
            {
                g_MeshRenderer.MappedTransforms[meshIndex] = mesh.Transform;
            }

            pushData.MeshIndex    = meshIndex;
            pushData.TextureIndex = 0;
            pushData.VertexOffset = static_cast<uint32>(mesh.VertexOffset);
            pushData.Padding      = 0;
            pushData.Scale[0]     = 1.0f;
            pushData.Scale[1]     = 1.0f;
            pushData.Translate[0] = 0.0f;
            pushData.Translate[1] = 0.0f;
            SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
            DrawIndexedPrimitives(pass, static_cast<uint32>(mesh.IndexCount), 1, static_cast<uint32>(mesh.IndexOffset),
                                  static_cast<uint32>(mesh.VertexOffset), 0);
            meshIndex++;
        }
    }

    LightID AddPointLight(const PointLight& light)
    {
        Assert(g_MeshRenderer.PointLights.Count < kDefaultLightCount);
        LightID id = g_MeshRenderer.PointLights.Count;
        g_MeshRenderer.PointLights.PushBack(light);
        if (g_MeshRenderer.MappedLights)
        {
            g_MeshRenderer.MappedLights[id] = light;
        }
        return id;
    }

    void SetPointLightPosition(LightID id, const Vector3& position)
    {
        Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
        g_MeshRenderer.PointLights.Data[id].Position = position;
        if (g_MeshRenderer.MappedLights)
        {
            g_MeshRenderer.MappedLights[id].Position = position;
        }
    }

    void SetPointLightColor(LightID id, const Vector3& color)
    {
        Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
        g_MeshRenderer.PointLights.Data[id].Color = color;
        if (g_MeshRenderer.MappedLights)
        {
            g_MeshRenderer.MappedLights[id].Color = color;
        }
    }

    void SetPointLightRadius(LightID id, float radius)
    {
        Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
        g_MeshRenderer.PointLights.Data[id].Radius = radius;
        if (g_MeshRenderer.MappedLights)
        {
            g_MeshRenderer.MappedLights[id].Radius = radius;
        }
    }

    void SetPointLightIntensity(LightID id, float intensity)
    {
        Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
        g_MeshRenderer.PointLights.Data[id].Intensity = intensity;
        if (g_MeshRenderer.MappedLights)
        {
            g_MeshRenderer.MappedLights[id].Intensity = intensity;
        }
    }

    void ClearPointLights()
    {
        g_MeshRenderer.PointLights.Clear();
    }

    MeshID AddCube()
    {
        Mesh result = {};

        constexpr Vertex vertexData[] = { // Front Face (Z = -0.5f) — Red
                                          { { -0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, 0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { -0.5f, -0.5f, -0.5f }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },

                                          // Back Face (Z = 0.5f) — Green
                                          { { 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { -0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },

                                          // Top Face (Y = 0.5f) — Blue
                                          { { -0.5f, 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { -0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },

                                          // Bottom Face (Y = -0.5f) — Yellow
                                          { { -0.5f, -0.5f, -0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, -0.5f, -0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, -0.5f, 0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { -0.5f, -0.5f, 0.5f }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },

                                          // Right Face (X = 0.5f) — Cyan
                                          { { 0.5f, 0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, -0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { 0.5f, -0.5f, -0.5f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },

                                          // Left Face (X = -0.5f) — Magenta
                                          { { -0.5f, 0.5f, 0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { -0.5f, 0.5f, -0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { -0.5f, -0.5f, -0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
                                          { { -0.5f, -0.5f, 0.5f }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }
        };
        constexpr size_t cubeVertexCount = ArraySize(vertexData);
        result.VertexCount               = cubeVertexCount;
        result.VertexOffset              = g_MeshRenderer.Vertices.Count;
        g_MeshRenderer.Vertices.PushBack(vertexData, cubeVertexCount);

        constexpr uint16 indices[]      = { 0,  1,  2,  0,  2,  3,    // Front
                                            4,  5,  6,  4,  6,  7,    // Back
                                            8,  9,  10, 8,  10, 11,   // Top
                                            12, 13, 14, 12, 14, 15,   // Bottom
                                            16, 17, 18, 16, 18, 19,   // Right
                                            20, 21, 22, 20, 22, 23 }; // Left
        constexpr size_t indexCubeCount = ArraySize(indices);
        result.IndexCount               = indexCubeCount;
        result.IndexOffset              = g_MeshRenderer.Indices.Count;
        g_MeshRenderer.Indices.PushBack(indices, indexCubeCount);

        MeshID id = g_MeshRenderer.Meshes.Count;
        g_MeshRenderer.Meshes.PushBack(result);
        return id;
    }

    MeshID AddQuad()
    {
        // Mesh result = {};

        // // Using the exact 6 vertices from the working triangles!
        // constexpr Vertex vertexData[] = {
        //     // Triangle 1 (Clockwise)
        //     { { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, // 0: Red
        //     { { 0.0f, 0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },   // 1: Green
        //     { { 0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } },  // 2: Blue
        //
        //     // Triangle 2 (Clockwise)
        //     { { -0.5f, 0.5f, 0.0f }, { 1.0f, 1.0f, 0.0f, 1.0f } }, // 3: Yellow
        //     { { 0.0f, 0.8f, 0.0f }, { 0.0f, 1.0f, 1.0f, 1.0f } },  // 4: Cyan
        //     { { 0.5f, 0.5f, 0.0f }, { 1.0f, 0.0f, 1.0f, 1.0f } }   // 5: Magenta
        // };
        // constexpr size_t triVertexCount = ArraySize(vertexData);
        // result.VertexCount              = triVertexCount;
        // result.Vertices                 = ArenaPushArray<Vertex>(arena.Get(), triVertexCount);
        // MemCopy(result.Vertices, vertexData, sizeof(Vertex) * triVertexCount);
        //
        // // Just the 6 indices for the two triangles
        // constexpr uint16 indices[]     = { 0, 1, 2, 3, 4, 5 };
        // constexpr size_t triIndexCount = ArraySize(indices);
        // result.IndexCount              = triIndexCount;
        // result.Indices = ArenaPushArray<uint16>(arena.Get(), triIndexCount JULIET_DEBUG_PARAM("Indices"));
        // MemCopy(result.Indices, indices, sizeof(uint16) * triIndexCount);
        //
        // g_MeshRenderer.Meshes.PushBack(std::move(result));
        return g_MeshRenderer.Meshes.Count - 1;
    }

    void SetMeshTransform(MeshID id, const Matrix& transform)
    {
        Assert(id < static_cast<MeshID>(g_MeshRenderer.Meshes.Count));
        g_MeshRenderer.Meshes.Data[id].Transform = transform;
    }

#if ALLOW_SHADER_HOT_RELOAD
    void ReloadMeshRendererShaders()
    {
        auto* pipeline = g_MeshRenderer.Pipeline;
        auto* device   = g_MeshRenderer.Device;

        String           entryPoint = WrapString("main");
        ShaderCreateInfo shaderCI   = {};
        shaderCI.EntryPoint         = entryPoint;
        String shaderPath           = GetAssetPath(WrapString("Triangle.vert.dxil"));
        shaderCI.Stage              = ShaderStage::Vertex;
        Shader* vertexShader        = CreateShader(device, shaderPath, shaderCI);

        shaderPath             = GetAssetPath(WrapString("SolidColor.frag.dxil"));
        shaderCI.Stage         = ShaderStage::Fragment;
        Shader* fragmentShader = CreateShader(device, shaderPath, shaderCI);

        UpdateGraphicsPipelineShaders(device, pipeline, vertexShader, fragmentShader);

        if (vertexShader)
        {
            DestroyShader(device, vertexShader);
        }
        if (fragmentShader)
        {
            DestroyShader(device, fragmentShader);
        }
    }
#endif
} // namespace Juliet
