aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-20 21:18:47 +0200
committerhachem <im@hachem.wtf>2026-08-20 21:18:47 +0200
commit00bf9a8cce28ab1dbc77ba24428be12391c4a576 (patch)
tree918231699cdbd7f261148f23a9717e34302074b9 /src
parentca9b8beaf69f06cac9b91b66ccd03bb99f09dd22 (diff)
[chore]: port camera to vulkan
Diffstat (limited to 'src')
-rw-r--r--src/core/application.cpp11
-rw-r--r--src/platform/vulkan/vulkan_renderer.cpp103
-rw-r--r--src/platform/vulkan/vulkan_renderer.h5
3 files changed, 104 insertions, 15 deletions
diff --git a/src/core/application.cpp b/src/core/application.cpp
index 701e088..4d21586 100644
--- a/src/core/application.cpp
+++ b/src/core/application.cpp
@@ -88,6 +88,15 @@ namespace Donut
if (m_vulkan_renderer)
{
+ bool free_fly = m_vulkan_renderer->is_free_fly();
+ ImGui::Text("Camera");
+ if (ImGui::RadioButton("Orbital", !free_fly)) m_vulkan_renderer->set_free_fly(false);
+ ImGui::SameLine();
+ if (ImGui::RadioButton("Free-fly", free_fly)) m_vulkan_renderer->set_free_fly(true);
+ ImGui::TextDisabled(free_fly ? "WASD move | Q/E down-up | Shift boost | drag to look"
+ : "Drag to orbit | scroll to zoom");
+ ImGui::Separator();
+
auto& hdri = HDRIManager::get();
std::string current = m_vulkan_renderer->current_hdri();
std::string preview = hdri.get_hdri_name(current);
@@ -105,8 +114,6 @@ namespace Donut
ImGui::TextDisabled("Switching rebuilds the cubemap (brief pause).");
}
- ImGui::Separator();
- ImGui::TextWrapped("Drag to orbit, scroll to zoom.");
ImGui::End();
}
diff --git a/src/platform/vulkan/vulkan_renderer.cpp b/src/platform/vulkan/vulkan_renderer.cpp
index 104bb62..69d6501 100644
--- a/src/platform/vulkan/vulkan_renderer.cpp
+++ b/src/platform/vulkan/vulkan_renderer.cpp
@@ -97,6 +97,9 @@ namespace Donut
void* sim_mapped = nullptr;
Camera camera{ 60.0f, (float)GEO_W / (float)GEO_H, 0.1f, 100.0f };
bool left_was_down = false;
+ double last_frame_time = 0.0; // for free-fly dt
+ double fps_last_x = 0.0, fps_last_y = 0.0; // cursor tracking for free-fly look
+ bool user_moving = false; // camera moved/looked this frame (drives step count)
VkImage cube_image = VK_NULL_HANDLE; VkDeviceMemory cube_mem = VK_NULL_HANDLE;
VkImageView cube_view = VK_NULL_HANDLE; VkSampler cube_sampler = VK_NULL_HANDLE;
std::string hdri_path; // path backing the current cubemap (UI display + no-op switch guard)
@@ -935,13 +938,22 @@ namespace Donut
glm::vec3 up; float p2; glm::vec3 fwd; float p3;
float tan_half_fov; float aspect; uint32_t moving; int p4;
} cam_data{};
- glm::vec3 pos = camera.get_orbital_position();
- glm::vec3 fwd = glm::normalize(camera.get_orbital_target() - pos);
+ glm::vec3 pos, fwd;
+ if (camera.get_camera_mode() == CameraMode::FPS)
+ {
+ pos = camera.get_position();
+ fwd = camera.get_forward_direction();
+ }
+ else
+ {
+ pos = camera.get_orbital_position();
+ fwd = glm::normalize(camera.get_orbital_target() - pos);
+ }
glm::vec3 right = glm::normalize(glm::cross(fwd, glm::vec3(0, 1, 0)));
cam_data.pos = pos; cam_data.right = right; cam_data.up = glm::cross(right, fwd); cam_data.fwd = fwd;
cam_data.tan_half_fov = (float)tan(glm::radians(60.0f * 0.5f));
cam_data.aspect = (float)GEO_W / (float)GEO_H;
- cam_data.moving = camera.is_dragging() || camera.is_panning() ? 1u : 0u;
+ cam_data.moving = user_moving ? 1u : 0u;
if (cam_mapped) memcpy(cam_mapped, &cam_data, sizeof(cam_data));
// Fewer integration steps while the camera moves keeps dragging responsive;
@@ -964,20 +976,54 @@ namespace Donut
{
bool over_ui = imgui_init && ImGui::GetIO().WantCaptureMouse;
- bool left_down = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
- if (left_down && !left_was_down && !over_ui)
- camera.process_orbital_mouse_button(GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, 0);
- else if (!left_down && left_was_down)
- camera.process_orbital_mouse_button(GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, 0);
- left_was_down = left_down;
+ double now = glfwGetTime();
+ float dt = last_frame_time > 0.0 ? (float)(now - last_frame_time) : 0.0f;
+ last_frame_time = now;
double mx = 0, my = 0;
glfwGetCursorPos(window, &mx, &my);
- camera.process_orbital_mouse_move(mx, my); // tracks last position internally; orbits only while dragging
+ bool left_down = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
+
+ if (camera.get_camera_mode() == CameraMode::FPS)
+ {
+ // Left-drag looks around (screen-up looks up); WASD/QE move.
+ if (left_down && !left_was_down) { fps_last_x = mx; fps_last_y = my; }
+ if (left_down && !over_ui)
+ camera.on_mouse_move(float(mx - fps_last_x), float(fps_last_y - my));
+ fps_last_x = mx; fps_last_y = my;
+ left_was_down = left_down;
+
+ bool over_kb = imgui_init && ImGui::GetIO().WantCaptureKeyboard;
+ bool moved = false;
+ if (!over_kb && dt > 0.0f)
+ {
+ float mdt = dt * (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS ? 4.0f : 1.0f);
+ if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { camera.move_forward(mdt); moved = true; }
+ if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { camera.move_backward(mdt); moved = true; }
+ if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { camera.move_left(mdt); moved = true; }
+ if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { camera.move_right(mdt); moved = true; }
+ if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) { camera.move_up(mdt); moved = true; }
+ if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) { camera.move_down(mdt); moved = true; }
+ }
+ g_ScrollAccum = 0.0; // scroll unused in free-fly
+ user_moving = moved || (left_down && !over_ui);
+ }
+ else
+ {
+ if (left_down && !left_was_down && !over_ui)
+ camera.process_orbital_mouse_button(GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, 0);
+ else if (!left_down && left_was_down)
+ camera.process_orbital_mouse_button(GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, 0);
+ left_was_down = left_down;
+
+ camera.process_orbital_mouse_move(mx, my); // orbits only while dragging
+
+ double scroll = g_ScrollAccum; g_ScrollAccum = 0.0;
+ if (scroll != 0.0 && !over_ui)
+ camera.process_orbital_scroll(0.0, scroll);
- double scroll = g_ScrollAccum; g_ScrollAccum = 0.0;
- if (scroll != 0.0 && !over_ui)
- camera.process_orbital_scroll(0.0, scroll);
+ user_moving = camera.is_dragging() || camera.is_panning();
+ }
}
auto VulkanRenderer::Impl::destroy_geodesic_resources() -> void
@@ -1176,6 +1222,37 @@ namespace Donut
return m_impl->hdri_path;
}
+ auto VulkanRenderer::set_free_fly(bool enabled) -> void
+ {
+ Impl& v = *m_impl;
+ if (v.device == VK_NULL_HANDLE) return;
+ const bool is_fps = v.camera.get_camera_mode() == CameraMode::FPS;
+ if (enabled == is_fps) return;
+
+ if (enabled)
+ {
+ // Seed the fly pose from the current orbital framing so the view is continuous.
+ glm::vec3 pos = v.camera.get_orbital_position();
+ glm::vec3 fwd = glm::normalize(v.camera.get_orbital_target() - pos);
+ float pitch = glm::degrees(asin(glm::clamp(fwd.y, -1.0f, 1.0f)));
+ float yaw = glm::degrees(atan2(fwd.z, fwd.x));
+ v.camera.set_camera_mode(CameraMode::FPS);
+ v.camera.set_movement_speed(2.0e10f); // scene spans ~1e11 units
+ v.camera.set_mouse_sensitivity(0.15f);
+ v.camera.set_position(pos);
+ v.camera.set_rotation(glm::vec3(pitch, yaw, 0.0f));
+ }
+ else
+ {
+ v.camera.set_camera_mode(CameraMode::Orbital); // orbital state was left intact
+ }
+ }
+
+ auto VulkanRenderer::is_free_fly() const -> bool
+ {
+ return m_impl->camera.get_camera_mode() == CameraMode::FPS;
+ }
+
auto VulkanRenderer::draw_frame(const glm::vec4& clear_color, const std::function<void()>& build_ui) -> void
{
Impl& v = *m_impl;
diff --git a/src/platform/vulkan/vulkan_renderer.h b/src/platform/vulkan/vulkan_renderer.h
index 68a1602..0e643c1 100644
--- a/src/platform/vulkan/vulkan_renderer.h
+++ b/src/platform/vulkan/vulkan_renderer.h
@@ -42,6 +42,11 @@ namespace Donut
// Filesystem path of the HDRI currently backing the cubemap.
auto current_hdri() const -> const std::string&;
+ // Free-fly (WASD + mouse-look) camera vs the default orbital camera.
+ // Enabling seeds the fly pose from the current orbital framing (no jump).
+ auto set_free_fly(bool enabled) -> void;
+ auto is_free_fly() const -> bool;
+
private:
struct Impl;
Impl* m_impl = nullptr;