#include "Lightkeeper.h" #include #include #include #include #include #include #include LightKeeper::LightKeeper() : App() { } LightKeeper::~LightKeeper() { if (!cleanedUp) { try { cleanup(); } catch (...) { } } } void LightKeeper::customInit() { RegisterGameComponents(); resources.init(gfxDevice); renderer.init(gfxDevice, resources, m_params.renderSize); const float aspectRatio = static_cast(m_params.renderSize.x) / static_cast(m_params.renderSize.y); camera.setAspectRatio(aspectRatio); camera.SetRotation(glm::radians(glm::vec2(90.f, 0.f))); setupSkybox(); auto& scene = SceneManager::GetInstance().CreateScene("Main"); mainScene = BuildMainScene(scene, gfxDevice, resources); debug2DTexture = resources.loadImageFromFile( gfxDevice, AssetFS::GetInstance().GetFullPath("engine://textures/kobe.png")); } void LightKeeper::setupSkybox() { const auto skyboxPath = AssetFS::GetInstance().GetCookedPathForFile("engine://DJI_0001_stitch.jpg"); const auto vertShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.vert"); const auto fragShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag"); skyboxCubemap = std::make_unique(); skyboxCubemap->LoadCubeMap(gfxDevice, resources, skyboxPath.generic_string()); skyboxCubemap->InitCubemapPipeline(gfxDevice, resources, vertShaderPath.generic_string(), fragShaderPath.generic_string()); skyboxCubemap->CreateCubeMap(gfxDevice, resources); renderer.setSkyboxTexture(skyboxCubemap->GetCubeMapImageID()); } void LightKeeper::customUpdate(float dt) { // LightKeeper owns a camera that hides App::camera; update this instance // after SDL events have been consumed. if (!isPlayerViewActive() && getSceneCamera() == nullptr) { camera.Update(dt); } SceneManager::GetInstance().Update(dt); SceneManager::GetInstance().LateUpdate(dt); updateDebugUi(); } void LightKeeper::drawCrosshair() { if (!isPlayerViewActive()) { return; } const bool focused = mainScene.playerController->GetFocusedInteractable() != nullptr; const glm::vec4 color = focused ? glm::vec4{1.0f, 0.8f, 0.25f, 1.0f} : glm::vec4{1.0f, 1.0f, 1.0f, 0.8f}; const float armLength = focused ? 16.0f : 10.0f; constexpr float thickness = 2.0f; const VkExtent3D extent = renderer.getDrawImage().extent; const glm::vec2 center{static_cast(extent.width) * 0.5f, static_cast(extent.height) * 0.5f}; auto& renderer2D = Renderer2D::GetInstance(); const float halfArm = armLength * 0.5f; renderer2D.DrawLine(center - glm::vec2{halfArm, 0.0f}, center + glm::vec2{halfArm, 0.0f}, thickness, color); renderer2D.DrawLine(center - glm::vec2{0.0f, halfArm}, center + glm::vec2{0.0f, halfArm}, thickness, color); if (focused) { renderer2D.DrawEllipseOutline(center, glm::vec2{14.0f}, thickness, color); } } bool LightKeeper::isPlayerViewActive() const { return mainScene.playerController != nullptr && mainScene.playerController->IsMouseCaptured(); } CameraComponent* LightKeeper::getSceneCamera() const { const auto& activeScenes = SceneManager::GetInstance().GetActiveScenes(); if (useFreeCamera || activeScenes.empty()) { return nullptr; } return activeScenes.front()->GetCurrentCamera(); } void LightKeeper::customDraw() { const auto cmd = gfxDevice.beginFrame(); if (cmd == VK_NULL_HANDLE) { return; } renderer.beginDrawing(gfxDevice); submitDebugDraws(); drawCrosshair(); if (isPlayerViewActive()) { camera.SetRotation(mainScene.playerController->GetYaw(), mainScene.playerController->GetPitch()); camera.m_position = mainScene.playerController->GetEyePosition(); camera.CalculateViewMatrix(); camera.CalculateProjectionMatrix(); } CameraComponent* sceneCamera = isPlayerViewActive() ? nullptr : getSceneCamera(); Camera& viewCamera = sceneCamera != nullptr ? sceneCamera->GetCamera(camera.GetAspectRatio()) : camera; const SceneEnvironment& environment = SceneManager::GetInstance().GetCurrentScene().GetEnvironment(); const GameRenderer::SceneData sceneData{ .camera = viewCamera, .ambientColor = environment.ambientColor, .ambientIntensity = environment.ambientIntensity, .fogColor = environment.fogColor, .fogDensity = environment.fogDensity, .skyboxRotation = environment.skyboxRotation, }; const RenderContext ctx{ .renderer = renderer, .camera = viewCamera, .sceneData = sceneData, }; SceneManager::GetInstance().Render(ctx); renderer.endDrawing(); const auto& drawImage = renderer.getDrawImage(); renderer.draw(cmd, gfxDevice, viewCamera, sceneData); gfxDevice.endFrame( cmd, drawImage, { .clearColor = {{0.f, 0.f, 0.5f, 1.f}}, .drawImageBlitRect = glm::ivec4{}, .imguiPass = &imguiPass, }); } void LightKeeper::customCleanup() { gfxDevice.waitIdle(); SceneManager::GetInstance().Destroy(); if (skyboxCubemap) { skyboxCubemap->cleanup(gfxDevice); skyboxCubemap.reset(); } renderer.cleanup(gfxDevice); } void LightKeeper::customFixedUpdate(float dt) { SceneManager::GetInstance().FixedUpdate(dt); } void LightKeeper::onWindowResize(int newWidth, int newHeight) { renderer.resize(gfxDevice, glm::ivec2{newWidth, newHeight}); const float aspectRatio = static_cast(newWidth) / static_cast(newHeight); camera.setAspectRatio(aspectRatio); }