// IAEngine: 2D Game Engine by IA // Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include #include #include namespace ia::iae { EXTERN SDL_Window *g_windowHandle; INT32 Renderer::s_screenWidth{}; INT32 Renderer::s_screenHeight{}; Renderer::State Renderer::s_state{}; SDL_GPUDevice *Renderer::s_gpuDevice{}; SDL_GPUTexture *Renderer::s_renderTargetSceneColor{}; SDL_GPUTexture *Renderer::s_renderTargetSceneDepth{}; SDL_GPUTexture *Renderer::s_renderTargetDebugDrawColor{}; Pipeline *Renderer::s_geometryPipeline{}; Pipeline *Renderer::s_postprocessPipeline{}; VOID Renderer::Initialize() { SDL_GetWindowSizeInPixels(g_windowHandle, &s_screenWidth, &s_screenHeight); if (!(s_gpuDevice = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV, Engine::IsDebugMode(), nullptr))) THROW_UNKNOWN("Failed to create the SDL GPU Device: ", SDL_GetError()); if (!SDL_ClaimWindowForGPUDevice(s_gpuDevice, g_windowHandle)) THROW_UNKNOWN("Failed to initialize SDL GPU for the window: ", SDL_GetError()); SDL_SetGPUSwapchainParameters(s_gpuDevice, g_windowHandle, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC); GPUResourceManager::Initialize(); // Initialize Render Targets s_renderTargetSceneDepth = GPUResourceManager::CreateTexture(SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, s_screenWidth, s_screenHeight, nullptr, SDL_GPU_TEXTUREFORMAT_D16_UNORM); s_renderTargetSceneColor = GPUResourceManager::CreateTexture( SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER, s_screenWidth, s_screenHeight, nullptr, SDL_GetGPUSwapchainTextureFormat(s_gpuDevice, g_windowHandle)); s_renderTargetDebugDrawColor = GPUResourceManager::CreateTexture( SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER, s_screenWidth, s_screenHeight, nullptr, SDL_GetGPUSwapchainTextureFormat(s_gpuDevice, g_windowHandle)); // Initialize Pipelines s_geometryPipeline = new Pipeline( Pipeline::StageDesc{ .SourceData = SHADER_SOURCE_GEOMETRY_VERT, .SourceLength = sizeof(SHADER_SOURCE_GEOMETRY_VERT), .SamplerCount = 0, .UniformBufferCount = 3, }, Pipeline::StageDesc{ .SourceData = SHADER_SOURCE_GEOMETRY_FRAG, .SourceLength = sizeof(SHADER_SOURCE_GEOMETRY_FRAG), .SamplerCount = 1, .UniformBufferCount = 1, }, true, true); s_postprocessPipeline = new Pipeline( Pipeline::StageDesc{ .SourceData = SHADER_SOURCE_POSTPROCESS_VERT, .SourceLength = sizeof(SHADER_SOURCE_POSTPROCESS_VERT), .SamplerCount = 0, .UniformBufferCount = 0, }, Pipeline::StageDesc{ .SourceData = SHADER_SOURCE_POSTPROCESS_FRAG, .SourceLength = sizeof(SHADER_SOURCE_POSTPROCESS_FRAG), .SamplerCount = 2, .UniformBufferCount = 0, }, false, false); DebugDraw::Initialize(); s_state.ProjectionMatrix = glm::orthoLH(0.0f, (FLOAT32) s_screenWidth, (FLOAT32) s_screenHeight, 0.0f, -2097152.0f, 2097152.0f); s_state.ColorTargetInfo.clear_color = SDL_FColor{0.33f, 0.33f, 0.33f, 1.0f}; s_state.ColorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR; s_state.ColorTargetInfo.store_op = SDL_GPU_STOREOP_STORE; s_state.DepthStencilTargetInfo.cycle = true; s_state.DepthStencilTargetInfo.clear_depth = 0; s_state.DepthStencilTargetInfo.clear_stencil = 0; s_state.DepthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR; s_state.DepthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE; s_state.DepthStencilTargetInfo.stencil_load_op = SDL_GPU_LOADOP_CLEAR; s_state.DepthStencilTargetInfo.stencil_store_op = SDL_GPU_STOREOP_STORE; } VOID Renderer::Terminate() { SDL_WaitForGPUIdle(s_gpuDevice); DebugDraw::Terminate(); delete s_geometryPipeline; delete s_postprocessPipeline; GPUResourceManager::DestroyTexture(s_renderTargetSceneDepth); GPUResourceManager::DestroyTexture(s_renderTargetSceneColor); GPUResourceManager::DestroyTexture(s_renderTargetDebugDrawColor); GPUResourceManager::Terminate(); SDL_ReleaseWindowFromGPUDevice(s_gpuDevice, g_windowHandle); SDL_DestroyGPUDevice(s_gpuDevice); } VOID Renderer::BeginFrame() { if (!(s_state.ActiveCommandBuffer = SDL_AcquireGPUCommandBuffer(s_gpuDevice))) THROW_UNKNOWN("Failed to acquire SDL GPU command buffer: ", SDL_GetError()); s_state.ColorTargetInfo.texture = s_renderTargetSceneColor; s_state.DepthStencilTargetInfo.texture = s_renderTargetSceneDepth; s_state.ActiveRenderPass = SDL_BeginGPURenderPass(s_state.ActiveCommandBuffer, &s_state.ColorTargetInfo, 1, &s_state.DepthStencilTargetInfo); SDL_BindGPUGraphicsPipeline(s_state.ActiveRenderPass, s_geometryPipeline->GetHandle()); SDL_PushGPUVertexUniformData(s_state.ActiveCommandBuffer, 0, &s_state.ProjectionMatrix, sizeof(Mat4)); //SDL_PushGPUVertexUniformData(s_state.ActiveCommandBuffer, 1, s_state.ActiveCamera->GetMatrix(), sizeof(Mat4)); } VOID Renderer::EndFrame() { SDL_EndGPURenderPass(s_state.ActiveRenderPass); DebugDraw::Render(); const auto imDrawData = ImGui::GetDrawData(); ImGui_ImplSDLGPU3_PrepareDrawData(imDrawData, s_state.ActiveCommandBuffer); s_state.ColorTargetInfo.texture = s_renderTargetDebugDrawColor; s_state.ActiveRenderPass = SDL_BeginGPURenderPass(s_state.ActiveCommandBuffer, &s_state.ColorTargetInfo, 1, nullptr); ImGui_ImplSDLGPU3_RenderDrawData(imDrawData, s_state.ActiveCommandBuffer, s_state.ActiveRenderPass); SDL_EndGPURenderPass(s_state.ActiveRenderPass); SDL_GPUTexture *swapChainTexture{}; if (!SDL_WaitAndAcquireGPUSwapchainTexture(s_state.ActiveCommandBuffer, g_windowHandle, &swapChainTexture, (PUINT32) &s_screenWidth, (PUINT32) &s_screenHeight)) THROW_UNKNOWN("Failed to acquire SDL GPU Swapchain texture: ", SDL_GetError()); if (!swapChainTexture) return; s_state.ColorTargetInfo.texture = swapChainTexture; s_state.ActiveRenderPass = SDL_BeginGPURenderPass(s_state.ActiveCommandBuffer, &s_state.ColorTargetInfo, 1, nullptr); SDL_BindGPUGraphicsPipeline(s_state.ActiveRenderPass, s_postprocessPipeline->GetHandle()); SDL_GPUTextureSamplerBinding textureBindings[2] = { {.texture = s_renderTargetSceneColor, .sampler = GPUResourceManager::GetSampler_LinearRepeat()}, {.texture = s_renderTargetDebugDrawColor, .sampler = GPUResourceManager::GetSampler_LinearRepeat()}, }; SDL_BindGPUFragmentSamplers(s_state.ActiveRenderPass, 0, textureBindings, 2); SDL_DrawGPUPrimitives(s_state.ActiveRenderPass, 6, 1, 0, 0); SDL_EndGPURenderPass(s_state.ActiveRenderPass); SDL_SubmitGPUCommandBuffer(s_state.ActiveCommandBuffer); } VOID Renderer::OnScreenResize(IN INT32 newWidth, IN INT32 newHeight) { } SDL_GPUTextureFormat Renderer::GetRenderTargetFormat() { return SDL_GetGPUSwapchainTextureFormat(s_gpuDevice, g_windowHandle); } } // namespace ia::iae namespace ia::iae { VOID Engine::SetActiveCamera(IN ICameraComponent *cameraComponent) { Renderer::s_state.ActiveCamera = cameraComponent; } Handle Engine::CreateGeometry(IN CONST Vector &vertices, IN CONST Vector &indices) { return INVALID_HANDLE; } VOID Engine::DestroyGeometry(IN Handle geometry) { } VOID Engine::DrawGeometry(IN Handle handle) { } VOID Engine::SetRenderState_Scissor(IN IVec4 rect) { Renderer::s_state.Scissor = rect.z ? SDL_Rect{0, 0, Renderer::s_screenWidth, Renderer::s_screenHeight} : SDL_Rect{rect.x, rect.y, rect.z, rect.w}; } VOID Engine::SetRenderState_FlippedH(IN BOOL value) { Renderer::s_state.FlippedH = value; } VOID Engine::SetRenderState_FlippedV(IN BOOL value) { Renderer::s_state.FlippedV = value; } VOID Engine::SetRenderState_TextureOffset(IN Vec2 off) { Renderer::s_state.TextureOffset = off; } VOID Engine::SetRenderState_ColorOverlay(IN Color color) { Renderer::s_state.ColorOverlay = color; } VOID Engine::SetRenderState_CameraRelative(IN BOOL value) { Renderer::s_state.CameraRelative = value; } VOID Engine::SetRenderState_Texture(IN Handle image) { Renderer::s_state.ActiveTexture = image; } VOID Engine::SetRenderState_Transform(IN Vec2 position, IN Vec2 scale, IN FLOAT32 rotation, IN UINT8 layer, IN INT16 sortIndex) { } } // namespace ia::iae