From e9e78966be302b3b52718b2c8e1d711ac425bfd9 Mon Sep 17 00:00:00 2001 From: bailehuni Date: Fri, 26 Apr 2024 23:31:34 +0100 Subject: [PATCH] Allow changing present mode --- include/gfx.h | 17 +- include/gfx_device.h | 3 + res/engine/shaders/fancy.frag | 5 +- src/application.cpp | 287 ++++++++++++++++++++++++++------- src/gfx_device_vulkan.cpp | 31 +++- src/renderer.cpp | 1 + src/util/gltf_loader.cpp | 10 +- src/vulkan/swapchain.cpp | 30 ++-- src/vulkan/swapchain.h | 5 +- src/window.cpp | 6 +- test/src/camera_controller.cpp | 4 + test/src/camera_controller.hpp | 7 +- test/src/game.cpp | 9 +- 13 files changed, 308 insertions(+), 107 deletions(-) diff --git a/include/gfx.h b/include/gfx.h index 2571cee..9659cc6 100644 --- a/include/gfx.h +++ b/include/gfx.h @@ -29,23 +29,24 @@ enum class MSAALevel { k16X, }; +enum class PresentMode { + kDoubleBufferedNoVsync, + kDoubleBufferedVsync, + kTripleBuffered, +}; + struct GraphicsSettings { GraphicsSettings() { // sane defaults - enable_validation = true; - vsync = true; - // not all GPUs/drivers support immediate present with V-sync enabled - wait_for_present = true; + enable_validation = false; + present_mode = PresentMode::kDoubleBufferedVsync; msaa_level = MSAALevel::kOff; enable_anisotropy = false; // anisotropic filtering can severely affect performance on intel iGPUs } bool enable_validation; - bool vsync; - // idle CPU after render until the frame has been presented - // (no affect with V-sync disabled) - bool wait_for_present; + PresentMode present_mode; MSAALevel msaa_level; bool enable_anisotropy; }; diff --git a/include/gfx_device.h b/include/gfx_device.h index 8a46b4b..11ae61a 100644 --- a/include/gfx_device.h +++ b/include/gfx_device.h @@ -19,6 +19,9 @@ class GFXDevice { void GetViewportSize(uint32_t* w, uint32_t* h); + void ChangePresentMode(gfx::PresentMode mode); + gfx::PresentMode GetPresentMode(); + void SetupImguiBackend(); void ShutdownImguiBackend(); void CmdRenderImguiDrawData(gfx::DrawBuffer* draw_buffer, ImDrawData* draw_data); diff --git a/res/engine/shaders/fancy.frag b/res/engine/shaders/fancy.frag index f449519..74f9785 100644 --- a/res/engine/shaders/fancy.frag +++ b/res/engine/shaders/fancy.frag @@ -118,8 +118,9 @@ void main() { lighting *= (1.0 - shadow); - const vec3 ambient_light = vec3(0.09082, 0.13281, 0.18164) * 2.4; - lighting += mix(ambient_light, texture(globalSetSkybox, R).rgb, metallic) * ao * diffuse_brdf; // this is NOT physically-based, it just looks cool + const vec3 ambient_light = vec3(0.09082, 0.13281, 0.18164) * 2.4 * 0.1; + //lighting += mix(ambient_light, texture(globalSetSkybox, R).rgb, metallic) * ao * diffuse_brdf; // this is NOT physically-based, it just looks cool + lighting += (ambient_light * ao * diffuse_brdf); // tone mapping const vec3 hdr_color = emission + lighting; diff --git a/src/application.cpp b/src/application.cpp index 6e8c9fe..f1b4b30 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -75,6 +75,39 @@ static std::filesystem::path getResourcesPath() return resourcesPath; } +#ifdef _WIN32 +static std::string openGLTFDialog() { + OPENFILENAMEA ofn; // common dialog box structure + CHAR szFile[260] = { 0 }; // if using TCHAR macros, use TCHAR array + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = NULL; + ofn.lpstrFile = szFile; + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = "GLTF Files (*.gltf;*.glb)\0*.gltf;*.glb\0All Files (*.*)\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + + // Display the Open dialog box + if (GetOpenFileNameA(&ofn) == TRUE) + { + return ofn.lpstrFile; + } + else + { + return ""; // User cancelled the dialog + } +} +#endif + +static auto frametimeFromFPS(int fps) { return std::chrono::nanoseconds(1'000'000'000 / fps); } + Application::Application(const char* appName, const char* appVersion, gfx::GraphicsSettings graphicsSettings, Configuration configuration) : app_name(appName), app_version(appVersion), configuration_(configuration) { @@ -184,11 +217,6 @@ void Application::GameLoop() { LOG_DEBUG("Begin game loop..."); - constexpr int FPS_LIMIT = 240; - constexpr auto FRAMETIME_LIMIT = std::chrono::nanoseconds(1000000000 / FPS_LIMIT); - auto beginFrame = std::chrono::steady_clock::now(); - auto endFrame = beginFrame + FRAMETIME_LIMIT; - auto lastTick = window_->GetNanos(); std::array delta_times{}; @@ -196,8 +224,29 @@ void Application::GameLoop() bool menu_active = false; bool show_entity_boxes = false; bool show_bounding_volumes = false; + bool enable_frame_limiter = false; + bool triple_buffering = false; + bool vsync = false; bool show_info_window = false; } debug_menu_state; + debug_menu_state.enable_frame_limiter = configuration_.enable_frame_limiter; + switch (renderer_->GetDevice()->GetPresentMode()) { + case gfx::PresentMode::kDoubleBufferedNoVsync: + debug_menu_state.triple_buffering = false; + debug_menu_state.vsync = false; + break; + case gfx::PresentMode::kDoubleBufferedVsync: + debug_menu_state.triple_buffering = false; + debug_menu_state.vsync = true; + break; + case gfx::PresentMode::kTripleBuffered: + debug_menu_state.triple_buffering = true; + debug_menu_state.vsync = false; + } + + int fps_limit = 240; + auto beginFrame = std::chrono::steady_clock::now(); + auto endFrame = beginFrame + frametimeFromFPS(fps_limit); // single-threaded game loop while (window_->IsRunning()) { @@ -225,16 +274,71 @@ void Application::GameLoop() debug_menu_state.show_info_window = !debug_menu_state.show_info_window; } + if (window_->GetKeyPress(inputs::Key::K_L)) { + debug_menu_state.enable_frame_limiter ^= true; + } + ImGui_ImplVulkan_NewFrame(); ImGui_ImplSDL2_NewFrame(); ImGui::NewFrame(); + //ImGui::ShowDemoWindow(); + + // Stop mouse from moving the camera when the settings menu is open + input_manager_->SetDeviceActive(InputDevice::kMouse, !debug_menu_state.menu_active); + if (debug_menu_state.menu_active) { - if (ImGui::Begin("debugMenu", 0)) { - ImGui::Text("Test!"); + if (ImGui::Begin("Settings", 0)) { ImGui::Text("FPS: %.3f", std::roundf(avg_fps)); - ImGui::Checkbox("Show entity hitboxes?", &debug_menu_state.show_entity_boxes); - ImGui::Checkbox("Show bounding volumes?", &debug_menu_state.show_bounding_volumes); + ImGui::Checkbox("Enable FPS limiter", &debug_menu_state.enable_frame_limiter); + if (debug_menu_state.enable_frame_limiter) { + ImGui::SliderInt("FPS limit", &fps_limit, 10, 360); + } + if (debug_menu_state.triple_buffering) { + ImGui::BeginDisabled(); + } + if (ImGui::Checkbox("Enable vsync", &debug_menu_state.vsync)) { + if (debug_menu_state.vsync) { + renderer_->GetDevice()->ChangePresentMode(gfx::PresentMode::kDoubleBufferedVsync); + } + else { + renderer_->GetDevice()->ChangePresentMode(gfx::PresentMode::kDoubleBufferedNoVsync); + } + } + if (debug_menu_state.triple_buffering) { + ImGui::EndDisabled(); + } + if (ImGui::Checkbox("Triple buffering", &debug_menu_state.triple_buffering)) { + if (debug_menu_state.triple_buffering) { + debug_menu_state.vsync = false; + renderer_->GetDevice()->ChangePresentMode(gfx::PresentMode::kTripleBuffered); + } + else { + if (debug_menu_state.vsync) { + renderer_->GetDevice()->ChangePresentMode(gfx::PresentMode::kDoubleBufferedVsync); + } + else { + renderer_->GetDevice()->ChangePresentMode(gfx::PresentMode::kDoubleBufferedNoVsync); + } + } + } + ImGui::Separator(); + ImGui::Checkbox("Show entity hitboxes", &debug_menu_state.show_entity_boxes); + ImGui::Checkbox("Show bounding volumes", &debug_menu_state.show_bounding_volumes); + ImGui::Separator(); +#ifndef _WIN32 + ImGui::BeginDisabled(); +#endif + // load gltf file dialog + if (ImGui::Button("Load glTF")) { +#ifdef _WIN32 + std::string path = std::filesystem::path(openGLTFDialog()).string(); + +#endif + } +#ifndef _WIN32 + ImGui::EndDisabled(); +#endif } ImGui::End(); } @@ -281,62 +385,86 @@ void Application::GameLoop() for (const auto& node : colsys->bvh_) { if (node.type1 == CollisionSystem::BiTreeNode::Type::Entity) { const glm::vec3 col = - (node.type1 == CollisionSystem::BiTreeNode::Type::BoundingVolume) ? glm::vec3{ 1.0f, 0.0f, 0.0f } : glm::vec3{ 0.0f, 1.0f, 0.0f }; - Line line1{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, col }; + (node.type1 == CollisionSystem::BiTreeNode::Type::BoundingVolume) ? glm::vec3{1.0f, 0.0f, 0.0f} : glm::vec3{0.0f, 1.0f, 0.0f}; + Line line1{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, col}; debug_lines.push_back(line1); - Line line2{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, col }; + Line line2{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, col}; debug_lines.push_back(line2); - Line line3{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, col }; + Line line3{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, col}; debug_lines.push_back(line3); - Line line4{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, col }; + Line line4{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, col}; debug_lines.push_back(line4); - Line line5{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, col }; + Line line5{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, + glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, col}; debug_lines.push_back(line5); - Line line6{ glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col }; + Line line6{glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col}; debug_lines.push_back(line6); - Line line7{ glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col }; + Line line7{glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col}; debug_lines.push_back(line7); - Line line8{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, col }; + Line line8{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, + glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, col}; debug_lines.push_back(line8); - Line line9{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col }; + Line line9{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col}; debug_lines.push_back(line9); - Line line10{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col }; + Line line10{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col}; debug_lines.push_back(line10); - Line line11{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col }; + Line line11{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col}; debug_lines.push_back(line11); - Line line12{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col }; + Line line12{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col}; debug_lines.push_back(line12); } if (node.type2 == CollisionSystem::BiTreeNode::Type::Entity) { const glm::vec3 col = - (node.type2 == CollisionSystem::BiTreeNode::Type::BoundingVolume) ? glm::vec3{ 1.0f, 0.0f, 0.0f } : glm::vec3{ 0.0f, 1.0f, 0.0f }; - Line line1{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, col }; + (node.type2 == CollisionSystem::BiTreeNode::Type::BoundingVolume) ? glm::vec3{1.0f, 0.0f, 0.0f} : glm::vec3{0.0f, 1.0f, 0.0f}; + Line line1{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, col}; debug_lines.push_back(line1); - Line line2{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, col }; + Line line2{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, col}; debug_lines.push_back(line2); - Line line3{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, col }; + Line line3{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, col}; debug_lines.push_back(line3); - Line line4{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, col }; + Line line4{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, col}; debug_lines.push_back(line4); - Line line5{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, col }; + Line line5{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, + glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, col}; debug_lines.push_back(line5); - Line line6{ glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col }; + Line line6{glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col}; debug_lines.push_back(line6); - Line line7{ glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col }; + Line line7{glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col}; debug_lines.push_back(line7); - Line line8{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, col }; + Line line8{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, + glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, col}; debug_lines.push_back(line8); - Line line9{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col }; + Line line9{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col}; debug_lines.push_back(line9); - Line line10{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col }; + Line line10{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col}; debug_lines.push_back(line10); - Line line11{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col }; + Line line11{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col}; debug_lines.push_back(line11); - Line line12{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col }; + Line line12{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col}; debug_lines.push_back(line12); } } @@ -347,62 +475,86 @@ void Application::GameLoop() for (const auto& node : colsys->bvh_) { if (node.type1 == CollisionSystem::BiTreeNode::Type::BoundingVolume) { const glm::vec3 col = - (node.type1 == CollisionSystem::BiTreeNode::Type::BoundingVolume) ? glm::vec3{ 1.0f, 0.0f, 0.0f } : glm::vec3{ 0.0f, 1.0f, 0.0f }; - Line line1{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, col }; + (node.type1 == CollisionSystem::BiTreeNode::Type::BoundingVolume) ? glm::vec3{1.0f, 0.0f, 0.0f} : glm::vec3{0.0f, 1.0f, 0.0f}; + Line line1{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, col}; debug_lines.push_back(line1); - Line line2{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, col }; + Line line2{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, col}; debug_lines.push_back(line2); - Line line3{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, col }; + Line line3{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, col}; debug_lines.push_back(line3); - Line line4{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, col }; + Line line4{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, col}; debug_lines.push_back(line4); - Line line5{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, col }; + Line line5{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.min.z}, + glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, col}; debug_lines.push_back(line5); - Line line6{ glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col }; + Line line6{glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.min.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col}; debug_lines.push_back(line6); - Line line7{ glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col }; + Line line7{glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.min.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col}; debug_lines.push_back(line7); - Line line8{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, col }; + Line line8{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.min.z}, + glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, col}; debug_lines.push_back(line8); - Line line9{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col }; + Line line9{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col}; debug_lines.push_back(line9); - Line line10{ glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col }; + Line line10{glm::vec3{node.box1.min.x, node.box1.min.y, node.box1.max.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col}; debug_lines.push_back(line10); - Line line11{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col }; + Line line11{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, + glm::vec3{node.box1.max.x, node.box1.min.y, node.box1.max.z}, col}; debug_lines.push_back(line11); - Line line12{ glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col }; + Line line12{glm::vec3{node.box1.max.x, node.box1.max.y, node.box1.max.z}, + glm::vec3{node.box1.min.x, node.box1.max.y, node.box1.max.z}, col}; debug_lines.push_back(line12); } if (node.type2 == CollisionSystem::BiTreeNode::Type::BoundingVolume) { const glm::vec3 col = - (node.type2 == CollisionSystem::BiTreeNode::Type::BoundingVolume) ? glm::vec3{ 1.0f, 0.0f, 0.0f } : glm::vec3{ 0.0f, 1.0f, 0.0f }; - Line line1{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, col }; + (node.type2 == CollisionSystem::BiTreeNode::Type::BoundingVolume) ? glm::vec3{1.0f, 0.0f, 0.0f} : glm::vec3{0.0f, 1.0f, 0.0f}; + Line line1{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, col}; debug_lines.push_back(line1); - Line line2{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, col }; + Line line2{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, col}; debug_lines.push_back(line2); - Line line3{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, col }; + Line line3{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, col}; debug_lines.push_back(line3); - Line line4{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, col }; + Line line4{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, col}; debug_lines.push_back(line4); - Line line5{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, col }; + Line line5{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.min.z}, + glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, col}; debug_lines.push_back(line5); - Line line6{ glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col }; + Line line6{glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.min.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col}; debug_lines.push_back(line6); - Line line7{ glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col }; + Line line7{glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.min.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col}; debug_lines.push_back(line7); - Line line8{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, col }; + Line line8{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.min.z}, + glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, col}; debug_lines.push_back(line8); - Line line9{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col }; + Line line9{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col}; debug_lines.push_back(line9); - Line line10{ glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col }; + Line line10{glm::vec3{node.box2.min.x, node.box2.min.y, node.box2.max.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col}; debug_lines.push_back(line10); - Line line11{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col }; + Line line11{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, + glm::vec3{node.box2.max.x, node.box2.min.y, node.box2.max.z}, col}; debug_lines.push_back(line11); - Line line12{ glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col }; + Line line12{glm::vec3{node.box2.max.x, node.box2.max.y, node.box2.max.z}, + glm::vec3{node.box2.min.x, node.box2.max.y, node.box2.max.z}, col}; debug_lines.push_back(line12); } } @@ -420,11 +572,22 @@ void Application::GameLoop() window_->GetInputAndEvents(); /* fps limiter */ + if (configuration_.enable_frame_limiter != debug_menu_state.enable_frame_limiter) { + if (debug_menu_state.enable_frame_limiter) { + configuration_.enable_frame_limiter = true; + // reset beginFrame and endFrame so the limiter doesn't hang for ages + beginFrame = std::chrono::steady_clock::now(); + endFrame = beginFrame; + } + else { + configuration_.enable_frame_limiter = false; + } + } if (configuration_.enable_frame_limiter) { std::this_thread::sleep_until(endFrame); } beginFrame = endFrame; - endFrame = beginFrame + FRAMETIME_LIMIT; + endFrame = beginFrame + frametimeFromFPS(fps_limit); delta_times[window_->GetFrameCount() % delta_times.size()] = window_->dt(); } diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index bc07692..2220d34 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -67,7 +67,7 @@ static void check_vk_result(VkResult code) { checkVulkanError(code, -1); } namespace engine { -static constexpr uint32_t FRAMES_IN_FLIGHT = 2; // This improved FPS by 5x! (on Intel IGPU) +static constexpr uint32_t FRAMES_IN_FLIGHT = 2; // This improved FPS by 5x! (on Intel IGPU) static constexpr size_t PUSH_CONSTANT_MAX_SIZE = 128; // bytes static constexpr VkIndexType INDEX_TYPE = VK_INDEX_TYPE_UINT32; @@ -474,8 +474,7 @@ GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* wi pimpl->swapchainInfo.physicalDevice = pimpl->device.physicalDevice; pimpl->swapchainInfo.surface = pimpl->surface; pimpl->swapchainInfo.window = pimpl->window; - pimpl->swapchainInfo.vsync = pimpl->graphicsSettings.vsync; - pimpl->swapchainInfo.waitForPresent = pimpl->graphicsSettings.wait_for_present; + pimpl->swapchainInfo.requested_present_mode = pimpl->graphicsSettings.present_mode; createSwapchain(&pimpl->swapchain, pimpl->swapchainInfo); /* make synchronisation primitives for rendering and allocate command buffers @@ -577,6 +576,26 @@ void GFXDevice::GetViewportSize(uint32_t* w, uint32_t* h) } } +void GFXDevice::ChangePresentMode(gfx::PresentMode mode) +{ + pimpl->swapchainInfo.requested_present_mode = mode; + // need to recreate swapchain to apply changes + pimpl->swapchainIsOutOfDate = true; +} + +gfx::PresentMode GFXDevice::GetPresentMode() { + switch (pimpl->swapchain.presentMode) { + case VK_PRESENT_MODE_FIFO_KHR: + return gfx::PresentMode::kDoubleBufferedVsync; + case VK_PRESENT_MODE_IMMEDIATE_KHR: + return gfx::PresentMode::kDoubleBufferedNoVsync; + case VK_PRESENT_MODE_MAILBOX_KHR: + return gfx::PresentMode::kTripleBuffered; + default: + throw std::runtime_error("Unknown present mode"); + } +} + void GFXDevice::SetupImguiBackend() { auto loaderFunc = [](const char* function_name, void* user_data) -> PFN_vkVoidFunction { @@ -947,7 +966,7 @@ void GFXDevice::FinishRender(gfx::DrawBuffer* drawBuffer) std::vector waitSemaphores{}; std::vector waitDstStageMasks{}; - waitSemaphores.push_back(drawBuffer->frameData.presentSemaphore); // wait for image from 2nd last frame to be presented so it can be rendered to again + waitSemaphores.push_back(drawBuffer->frameData.presentSemaphore); // wait for image from 2nd last frame to be presented so it can be rendered to again waitDstStageMasks.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); waitSemaphores.push_back(drawBuffer->frameData.transferSemaphore); // wait for uniform buffer copies to complete waitDstStageMasks.push_back(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT); @@ -1360,7 +1379,7 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info) rasterizer.depthBiasEnable = VK_TRUE; rasterizer.depthBiasConstantFactor = 2.0f; // 1.25f; rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 3.5f; // 1.75f; + rasterizer.depthBiasSlopeFactor = 3.5f; // 1.75f; } else { rasterizer.depthBiasEnable = VK_FALSE; @@ -1493,7 +1512,7 @@ gfx::DescriptorSetLayout* GFXDevice::CreateDescriptorSetLayout(const std::vector uint32_t i = 0; for (const auto& binding : bindings) { auto& vulkanBinding = vulkanBindings.emplace_back(); - vulkanBinding.binding = i; // This should be as low as possible to avoid wasting memory + vulkanBinding.binding = i; // This should be as low as possible to avoid wasting memory vulkanBinding.descriptorType = converters::getDescriptorType(binding.descriptor_type); vulkanBinding.descriptorCount = 1; // if > 1, accessible as an array in the shader vulkanBinding.stageFlags = converters::getShaderStageFlags(binding.stage_flags); diff --git a/src/renderer.cpp b/src/renderer.cpp index 6df56c8..9e22229 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -4,6 +4,7 @@ #include "application_component.h" #include "util/files.h" +#include "log.h" #include #include diff --git a/src/util/gltf_loader.cpp b/src/util/gltf_loader.cpp index 74c98a9..93a7e81 100644 --- a/src/util/gltf_loader.cpp +++ b/src/util/gltf_loader.cpp @@ -89,6 +89,8 @@ static glm::mat4 MatFromDoubleArray(const std::vector& arr) engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) { + LOG_INFO("Loading gltf file: {}", path); + tg::TinyGLTF loader; tg::Model model; std::string err, warn; @@ -407,6 +409,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) std::vector indices; indices.reserve(num_indices); + // TODO: natively support indices of these sizes instead of having to convert to uint32 if (indices_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) { for (size_t i = 0; i < num_indices; ++i) { indices.push_back(*reinterpret_cast(&indices_data_start[i * 1])); @@ -630,7 +633,6 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) if (node.mesh != -1) { const auto& primitives = primitive_arrays.at(node.mesh); - int i = 0; if (primitives.size() == 1) { auto meshren = scene.AddComponent(e); meshren->mesh = primitives.front().mesh; @@ -639,12 +641,14 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) collider->aabb = primitives.front().aabb; } else { + int i = 0; for (const EnginePrimitive& prim : primitives) { auto prim_entity = scene.CreateEntity(std::string("_mesh") + std::to_string(i), e); + scene.GetTransform(prim_entity)->is_static = isStatic; auto meshren = scene.AddComponent(prim_entity); meshren->mesh = prim.mesh; meshren->material = prim.material; - auto collider = scene.AddComponent(e); + auto collider = scene.AddComponent(prim_entity); collider->aabb = prim.aabb; ++i; } @@ -660,7 +664,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) generateEntities(parent, model.nodes.at(i)); } - LOG_DEBUG("Loaded glTF model: {}", path); + LOG_DEBUG("Loaded glTF file: {}", path); return parent; } diff --git a/src/vulkan/swapchain.cpp b/src/vulkan/swapchain.cpp index 498d28e..6808ab4 100644 --- a/src/vulkan/swapchain.cpp +++ b/src/vulkan/swapchain.cpp @@ -53,21 +53,23 @@ namespace engine { res = vkGetPhysicalDeviceSurfacePresentModesKHR(info.physicalDevice, info.surface, &surfacePresentModeCount, presentModes.data()); assert(res == VK_SUCCESS); - sc->presentMode = VK_PRESENT_MODE_FIFO_KHR; // This mode is always available - if (info.vsync == true) { - if (info.waitForPresent == false) { - for (const auto& presMode : presentModes) { - if (presMode == VK_PRESENT_MODE_MAILBOX_KHR) { - sc->presentMode = presMode; // this mode allows V-sync without fixing FPS to refresh rate - } - } - } + VkPresentModeKHR present_mode_requested; + switch (info.requested_present_mode) { + case gfx::PresentMode::kDoubleBufferedNoVsync: + present_mode_requested = VK_PRESENT_MODE_IMMEDIATE_KHR; + break; + case gfx::PresentMode::kDoubleBufferedVsync: + present_mode_requested = VK_PRESENT_MODE_FIFO_KHR; + break; + case gfx::PresentMode::kTripleBuffered: + present_mode_requested = VK_PRESENT_MODE_MAILBOX_KHR; } - else { - for (const auto& presMode : presentModes) { - if (presMode == VK_PRESENT_MODE_IMMEDIATE_KHR) { - sc->presentMode = presMode; // V-sync off - } + sc->presentMode = VK_PRESENT_MODE_FIFO_KHR; // This mode is always available + // check requested mode is available + for (VkPresentModeKHR mode : presentModes) { + if (mode == present_mode_requested) { + sc->presentMode = mode; + break; } } diff --git a/src/vulkan/swapchain.h b/src/vulkan/swapchain.h index 908edd6..3108b6c 100644 --- a/src/vulkan/swapchain.h +++ b/src/vulkan/swapchain.h @@ -9,6 +9,8 @@ #include +#include "gfx.h" + namespace engine { struct DepthStencil { @@ -38,8 +40,7 @@ namespace engine { VkSurfaceKHR surface; SDL_Window* window; VmaAllocator allocator; - bool vsync; - bool waitForPresent; + gfx::PresentMode requested_present_mode; }; void createSwapchain(Swapchain* sc, const SwapchainInfo& info); diff --git a/src/window.cpp b/src/window.cpp index abfc64b..aa83def 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -169,8 +169,9 @@ void Window::OnMouseMotionEvent(SDL_MouseMotionEvent& e) else { mouse_.x = e.x; mouse_.y = e.y; - mouse_.dx = e.xrel; - mouse_.dy = e.yrel; + // mouse motion events can occur multiple times per frame when FPS drops, these need to be accumulated + mouse_.dx += e.xrel; + mouse_.dy += e.yrel; } } @@ -289,6 +290,7 @@ bool Window::SetRelativeMouseMode(bool enabled) int code = SDL_SetRelativeMouseMode(static_cast(enabled)); if (code != 0) { throw std::runtime_error("Unable to set relative mouse mode"); + // return false; } else { return true; diff --git a/test/src/camera_controller.cpp b/test/src/camera_controller.cpp index ca70612..49dd8fa 100644 --- a/test/src/camera_controller.cpp +++ b/test/src/camera_controller.cpp @@ -202,6 +202,10 @@ void CameraControllerSystem::OnUpdate(float ts) scene_->app()->scene_manager()->SetActiveScene(next_scene_); } + if (scene_->app()->window()->GetKeyPress(engine::inputs::Key::K_Q)) { + c->noclip ^= true; + } + if (scene_->app()->window()->GetButtonPress(engine::inputs::MouseButton::M_LEFT)) { engine::Ray ray{}; ray.origin = t->position; diff --git a/test/src/camera_controller.hpp b/test/src/camera_controller.hpp index 5b82096..e8e1a2b 100644 --- a/test/src/camera_controller.hpp +++ b/test/src/camera_controller.hpp @@ -8,7 +8,7 @@ struct CameraControllerComponent { // looking - static constexpr float kCameraSensitivity = 0.007f; + static constexpr float kCameraSensitivity = 0.001f; static constexpr float kMaxPitch = glm::pi(); static constexpr float kMinPitch = 0.0f; @@ -16,7 +16,7 @@ struct CameraControllerComponent { static constexpr float kSpeedForwardBack = 4.0f; static constexpr float kSpeedStrafe = 4.0f; static constexpr float kSprintMultiplier = 2.0f; - static constexpr float kJumpVelocity = 4.4f; + static constexpr float kJumpVelocity = 4.4f * 2.0f; // collision static constexpr float kPlayerHeight = 2.0f; // 71.0f * 25.4f / 1000.0f; @@ -31,7 +31,8 @@ struct CameraControllerComponent { bool noclip = false; float yaw = 0.0f; - float pitch = glm::half_pi(); + //float pitch = glm::half_pi(); + float pitch = 0.0f; glm::vec3 vel{0.0f, 0.0f, 0.0f}; bool grounded = false; diff --git a/test/src/game.cpp b/test/src/game.cpp index adf9d43..71372e6 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -46,8 +46,7 @@ void PlayGame(GameSettings settings) engine::gfx::GraphicsSettings graphics_settings{}; graphics_settings.enable_validation = settings.enable_validation; - graphics_settings.vsync = false; - graphics_settings.wait_for_present = false; + graphics_settings.present_mode = engine::gfx::PresentMode::kTripleBuffered; graphics_settings.msaa_level = engine::gfx::MSAALevel::kOff; graphics_settings.enable_anisotropy = true; @@ -66,12 +65,12 @@ void PlayGame(GameSettings settings) /* as of right now, the entity with tag 'camera' is used to build the view * matrix */ - engine::Entity sponza = engine::util::LoadGLTF(*start_scene, app.GetResourcePath("models/tree.glb"), true); - start_scene->GetPosition(sponza).z += 90.0f; + //engine::Entity temple = engine::util::LoadGLTF(*start_scene, "C:/games/temple.glb", true); start_scene->RegisterComponent(); start_scene->RegisterSystem(); start_scene->AddComponent(camera)->noclip = true; + start_scene->GetPosition(camera).z += 10.0f; } engine::Scene* main_scene = app.scene_manager()->CreateEmptyScene(); @@ -107,7 +106,7 @@ void PlayGame(GameSettings settings) // main_scene->GetComponent(bottle)->position.z += 5.0f; engine::Entity helmet = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/DamagedHelmet.glb"), true); - main_scene->GetPosition(helmet) += glm::vec3{5.0f, 5.0f, 1.0f}; + main_scene->GetPosition(helmet) += glm::vec3{5.0f, 5.0f, 5.0f}; main_scene->GetScale(helmet) *= 3.0f; main_scene->GetRotation(helmet) = glm::angleAxis(glm::pi(), glm::vec3{ 0.0f, 0.0f, 1.0f }); main_scene->GetRotation(helmet) *= glm::angleAxis(glm::half_pi(), glm::vec3{ 1.0f, 0.0f, 0.0f });