mirror of
https://github.com/slendidev/lunar.git
synced 2026-01-30 16:28:58 +02:00
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <numbers>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <print>
|
#include <print>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -122,6 +124,40 @@ auto linux_key_to_imgui(uint32_t keycode) -> std::optional<ImGuiKey>
|
|||||||
return ImGuiKey_F11;
|
return ImGuiKey_F11;
|
||||||
case KEY_F12:
|
case KEY_F12:
|
||||||
return ImGuiKey_F12;
|
return ImGuiKey_F12;
|
||||||
|
case KEY_KP0:
|
||||||
|
return ImGuiKey_Keypad0;
|
||||||
|
case KEY_KP1:
|
||||||
|
return ImGuiKey_Keypad1;
|
||||||
|
case KEY_KP2:
|
||||||
|
return ImGuiKey_Keypad2;
|
||||||
|
case KEY_KP3:
|
||||||
|
return ImGuiKey_Keypad3;
|
||||||
|
case KEY_KP4:
|
||||||
|
return ImGuiKey_Keypad4;
|
||||||
|
case KEY_KP5:
|
||||||
|
return ImGuiKey_Keypad5;
|
||||||
|
case KEY_KP6:
|
||||||
|
return ImGuiKey_Keypad6;
|
||||||
|
case KEY_KP7:
|
||||||
|
return ImGuiKey_Keypad7;
|
||||||
|
case KEY_KP8:
|
||||||
|
return ImGuiKey_Keypad8;
|
||||||
|
case KEY_KP9:
|
||||||
|
return ImGuiKey_Keypad9;
|
||||||
|
case KEY_KPDOT:
|
||||||
|
return ImGuiKey_KeypadDecimal;
|
||||||
|
case KEY_KPENTER:
|
||||||
|
return ImGuiKey_KeypadEnter;
|
||||||
|
case KEY_KPPLUS:
|
||||||
|
return ImGuiKey_KeypadAdd;
|
||||||
|
case KEY_KPMINUS:
|
||||||
|
return ImGuiKey_KeypadSubtract;
|
||||||
|
case KEY_KPASTERISK:
|
||||||
|
return ImGuiKey_KeypadMultiply;
|
||||||
|
case KEY_KPSLASH:
|
||||||
|
return ImGuiKey_KeypadDivide;
|
||||||
|
case KEY_KPEQUAL:
|
||||||
|
return ImGuiKey_KeypadEqual;
|
||||||
case KEY_0:
|
case KEY_0:
|
||||||
return ImGuiKey_0;
|
return ImGuiKey_0;
|
||||||
case KEY_1:
|
case KEY_1:
|
||||||
@@ -199,6 +235,142 @@ auto linux_key_to_imgui(uint32_t keycode) -> std::optional<ImGuiKey>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto linux_key_to_char(uint32_t keycode, bool shift) -> std::optional<char32_t>
|
||||||
|
{
|
||||||
|
switch (keycode) {
|
||||||
|
case KEY_0:
|
||||||
|
return shift ? U')' : U'0';
|
||||||
|
case KEY_1:
|
||||||
|
return shift ? U'!' : U'1';
|
||||||
|
case KEY_2:
|
||||||
|
return shift ? U'@' : U'2';
|
||||||
|
case KEY_3:
|
||||||
|
return shift ? U'#' : U'3';
|
||||||
|
case KEY_4:
|
||||||
|
return shift ? U'$' : U'4';
|
||||||
|
case KEY_5:
|
||||||
|
return shift ? U'%' : U'5';
|
||||||
|
case KEY_6:
|
||||||
|
return shift ? U'^' : U'6';
|
||||||
|
case KEY_7:
|
||||||
|
return shift ? U'&' : U'7';
|
||||||
|
case KEY_8:
|
||||||
|
return shift ? U'*' : U'8';
|
||||||
|
case KEY_9:
|
||||||
|
return shift ? U'(' : U'9';
|
||||||
|
case KEY_KP0:
|
||||||
|
return U'0';
|
||||||
|
case KEY_KP1:
|
||||||
|
return U'1';
|
||||||
|
case KEY_KP2:
|
||||||
|
return U'2';
|
||||||
|
case KEY_KP3:
|
||||||
|
return U'3';
|
||||||
|
case KEY_KP4:
|
||||||
|
return U'4';
|
||||||
|
case KEY_KP5:
|
||||||
|
return U'5';
|
||||||
|
case KEY_KP6:
|
||||||
|
return U'6';
|
||||||
|
case KEY_KP7:
|
||||||
|
return U'7';
|
||||||
|
case KEY_KP8:
|
||||||
|
return U'8';
|
||||||
|
case KEY_KP9:
|
||||||
|
return U'9';
|
||||||
|
case KEY_Q:
|
||||||
|
return shift ? U'Q' : U'q';
|
||||||
|
case KEY_W:
|
||||||
|
return shift ? U'W' : U'w';
|
||||||
|
case KEY_E:
|
||||||
|
return shift ? U'E' : U'e';
|
||||||
|
case KEY_R:
|
||||||
|
return shift ? U'R' : U'r';
|
||||||
|
case KEY_T:
|
||||||
|
return shift ? U'T' : U't';
|
||||||
|
case KEY_Y:
|
||||||
|
return shift ? U'Y' : U'y';
|
||||||
|
case KEY_U:
|
||||||
|
return shift ? U'U' : U'u';
|
||||||
|
case KEY_I:
|
||||||
|
return shift ? U'I' : U'i';
|
||||||
|
case KEY_O:
|
||||||
|
return shift ? U'O' : U'o';
|
||||||
|
case KEY_P:
|
||||||
|
return shift ? U'P' : U'p';
|
||||||
|
case KEY_A:
|
||||||
|
return shift ? U'A' : U'a';
|
||||||
|
case KEY_S:
|
||||||
|
return shift ? U'S' : U's';
|
||||||
|
case KEY_D:
|
||||||
|
return shift ? U'D' : U'd';
|
||||||
|
case KEY_F:
|
||||||
|
return shift ? U'F' : U'f';
|
||||||
|
case KEY_G:
|
||||||
|
return shift ? U'G' : U'g';
|
||||||
|
case KEY_H:
|
||||||
|
return shift ? U'H' : U'h';
|
||||||
|
case KEY_J:
|
||||||
|
return shift ? U'J' : U'j';
|
||||||
|
case KEY_K:
|
||||||
|
return shift ? U'K' : U'k';
|
||||||
|
case KEY_L:
|
||||||
|
return shift ? U'L' : U'l';
|
||||||
|
case KEY_Z:
|
||||||
|
return shift ? U'Z' : U'z';
|
||||||
|
case KEY_X:
|
||||||
|
return shift ? U'X' : U'x';
|
||||||
|
case KEY_C:
|
||||||
|
return shift ? U'C' : U'c';
|
||||||
|
case KEY_V:
|
||||||
|
return shift ? U'V' : U'v';
|
||||||
|
case KEY_B:
|
||||||
|
return shift ? U'B' : U'b';
|
||||||
|
case KEY_N:
|
||||||
|
return shift ? U'N' : U'n';
|
||||||
|
case KEY_M:
|
||||||
|
return shift ? U'M' : U'm';
|
||||||
|
case KEY_SPACE:
|
||||||
|
return U' ';
|
||||||
|
case KEY_MINUS:
|
||||||
|
return shift ? U'_' : U'-';
|
||||||
|
case KEY_EQUAL:
|
||||||
|
return shift ? U'+' : U'=';
|
||||||
|
case KEY_LEFTBRACE:
|
||||||
|
return shift ? U'{' : U'[';
|
||||||
|
case KEY_RIGHTBRACE:
|
||||||
|
return shift ? U'}' : U']';
|
||||||
|
case KEY_BACKSLASH:
|
||||||
|
return shift ? U'|' : U'\\';
|
||||||
|
case KEY_SEMICOLON:
|
||||||
|
return shift ? U':' : U';';
|
||||||
|
case KEY_APOSTROPHE:
|
||||||
|
return shift ? U'"' : U'\'';
|
||||||
|
case KEY_GRAVE:
|
||||||
|
return shift ? U'~' : U'`';
|
||||||
|
case KEY_COMMA:
|
||||||
|
return shift ? U'<' : U',';
|
||||||
|
case KEY_DOT:
|
||||||
|
return shift ? U'>' : U'.';
|
||||||
|
case KEY_SLASH:
|
||||||
|
return shift ? U'?' : U'/';
|
||||||
|
case KEY_KPDOT:
|
||||||
|
return U'.';
|
||||||
|
case KEY_KPPLUS:
|
||||||
|
return U'+';
|
||||||
|
case KEY_KPMINUS:
|
||||||
|
return U'-';
|
||||||
|
case KEY_KPASTERISK:
|
||||||
|
return U'*';
|
||||||
|
case KEY_KPSLASH:
|
||||||
|
return U'/';
|
||||||
|
case KEY_KPEQUAL:
|
||||||
|
return U'=';
|
||||||
|
default:
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace Lunar {
|
namespace Lunar {
|
||||||
@@ -226,6 +398,8 @@ Application::Application()
|
|||||||
m_logger.info("App init done!");
|
m_logger.info("App init done!");
|
||||||
|
|
||||||
m_renderer->set_antialiasing(VulkanRenderer::AntiAliasingKind::MSAA_4X);
|
m_renderer->set_antialiasing(VulkanRenderer::AntiAliasingKind::MSAA_4X);
|
||||||
|
|
||||||
|
m_cursor = PolarCoordinate::from_vec3(m_camera.target - m_camera.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
@@ -252,6 +426,7 @@ auto Application::run() -> void
|
|||||||
while (m_running) {
|
while (m_running) {
|
||||||
uint64_t now { SDL_GetTicks() };
|
uint64_t now { SDL_GetTicks() };
|
||||||
uint64_t dt { now - last };
|
uint64_t dt { now - last };
|
||||||
|
float dt_seconds { static_cast<float>(dt) / 1000.0f };
|
||||||
last = now;
|
last = now;
|
||||||
|
|
||||||
if (dt > 0)
|
if (dt > 0)
|
||||||
@@ -273,6 +448,8 @@ auto Application::run() -> void
|
|||||||
} else if (e.type == SDL_EVENT_MOUSE_MOTION) {
|
} else if (e.type == SDL_EVENT_MOUSE_MOTION) {
|
||||||
m_mouse_x = e.motion.x;
|
m_mouse_x = e.motion.x;
|
||||||
m_mouse_y = e.motion.y;
|
m_mouse_y = e.motion.y;
|
||||||
|
m_mouse_dx = e.motion.xrel;
|
||||||
|
m_mouse_dy = e.motion.yrel;
|
||||||
forward_to_imgui = true;
|
forward_to_imgui = true;
|
||||||
} else if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN
|
} else if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN
|
||||||
|| e.type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
|| e.type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
||||||
@@ -289,16 +466,87 @@ auto Application::run() -> void
|
|||||||
ImGui_ImplSDL3_ProcessEvent(&e);
|
ImGui_ImplSDL3_ProcessEvent(&e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto const target_offset { m_camera.target - m_camera.position };
|
||||||
|
auto const target_distance { target_offset.magnitude() };
|
||||||
|
auto const target_polar { PolarCoordinate::from_vec3(target_offset) };
|
||||||
|
// Keep cursor angles in sync with externally-updated targets so view
|
||||||
|
// aligns to the target direction. Preserve radius when the target sits
|
||||||
|
// on top of the camera to avoid collapsing it.
|
||||||
|
if (target_distance > 0.0f) {
|
||||||
|
m_cursor.r = target_distance;
|
||||||
|
m_cursor.theta = target_polar.theta;
|
||||||
|
m_cursor.phi = target_polar.phi;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rotated_this_frame { false };
|
||||||
|
if (mouse_captured()) {
|
||||||
|
constexpr float mouse_sensitivity { 0.0005f };
|
||||||
|
constexpr float phi_epsilon { 0.002f };
|
||||||
|
|
||||||
|
m_cursor.theta
|
||||||
|
-= static_cast<float>(m_mouse_dx) * mouse_sensitivity;
|
||||||
|
m_cursor.phi -= static_cast<float>(m_mouse_dy) * mouse_sensitivity;
|
||||||
|
m_cursor.phi = std::clamp(m_cursor.phi, phi_epsilon,
|
||||||
|
std::numbers::pi_v<float> - phi_epsilon);
|
||||||
|
rotated_this_frame = (m_mouse_dx != 0.0 || m_mouse_dy != 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto look_dir { m_cursor.to_vec3().normalized_safe() };
|
||||||
|
if (!rotated_this_frame && target_distance > 0.0f) {
|
||||||
|
look_dir = target_offset.normalized_safe();
|
||||||
|
}
|
||||||
|
if (look_dir.magnitude() == 0.0f)
|
||||||
|
look_dir = smath::Vec3 { 0.0f, 0.0f, -1.0f };
|
||||||
|
smath::Vec3 const world_up { 0.0f, 1.0f, 0.0f };
|
||||||
|
auto up_basis = world_up;
|
||||||
|
if (std::abs(look_dir.dot(up_basis)) > 0.99f)
|
||||||
|
up_basis = smath::Vec3 { 0.0f, 0.0f, 1.0f };
|
||||||
|
auto right { look_dir.cross(up_basis).normalized_safe() };
|
||||||
|
if (right.magnitude() == 0.0f)
|
||||||
|
right = smath::Vec3 { 1.0f, 0.0f, 0.0f };
|
||||||
|
auto camera_up { right.cross(look_dir).normalized_safe() };
|
||||||
|
if (camera_up.magnitude() == 0.0f)
|
||||||
|
camera_up = world_up;
|
||||||
|
|
||||||
|
smath::Vec3 move_dir {};
|
||||||
|
if (is_key_pressed(KEY_W))
|
||||||
|
move_dir += look_dir;
|
||||||
|
if (is_key_pressed(KEY_S))
|
||||||
|
move_dir -= look_dir;
|
||||||
|
if (is_key_pressed(KEY_D))
|
||||||
|
move_dir += right;
|
||||||
|
if (is_key_pressed(KEY_A))
|
||||||
|
move_dir -= right;
|
||||||
|
if (is_key_pressed(KEY_SPACE))
|
||||||
|
move_dir += world_up;
|
||||||
|
if (is_key_pressed(KEY_LEFTSHIFT))
|
||||||
|
move_dir -= world_up;
|
||||||
|
|
||||||
|
if (move_dir.magnitude() > 0.0f) {
|
||||||
|
constexpr float move_speed { 10.0f };
|
||||||
|
move_dir = move_dir.normalized_safe();
|
||||||
|
m_camera.position += move_dir * (move_speed * dt_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_show_imgui) {
|
||||||
|
m_camera.up = camera_up;
|
||||||
|
if (rotated_this_frame) {
|
||||||
|
auto const distance = target_distance > 0.0f
|
||||||
|
? target_distance
|
||||||
|
: std::max(1.0f, m_cursor.r);
|
||||||
|
m_camera.target = m_camera.position + look_dir * distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mouse_dx = 0.0;
|
||||||
|
m_mouse_dy = 0.0;
|
||||||
|
|
||||||
ImGui_ImplSDL3_NewFrame();
|
ImGui_ImplSDL3_NewFrame();
|
||||||
ImGui_ImplVulkan_NewFrame();
|
ImGui_ImplVulkan_NewFrame();
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
if (m_show_imgui) {
|
ImGui::SetNextWindowSize({ 300, 100 });
|
||||||
ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
|
|
||||||
ImGui::ShowDemoWindow();
|
|
||||||
|
|
||||||
ImGui::SetNextWindowSize({ 100, 50 });
|
|
||||||
ImGui::SetNextWindowPos({ 0, 0 });
|
ImGui::SetNextWindowPos({ 0, 0 });
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4 { 0, 0, 0, 0.5f });
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4 { 0, 0, 0, 0.5f });
|
||||||
if (ImGui::Begin("Debug Info", nullptr,
|
if (ImGui::Begin("Debug Info", nullptr,
|
||||||
@@ -306,9 +554,31 @@ auto Application::run() -> void
|
|||||||
defer(ImGui::End());
|
defer(ImGui::End());
|
||||||
|
|
||||||
ImGui::Text("%s", std::format("FPS: {:.2f}", fps).c_str());
|
ImGui::Text("%s", std::format("FPS: {:.2f}", fps).c_str());
|
||||||
|
ImGui::Text("%s",
|
||||||
|
std::format("Cam pos: ({:.2f}, {:.2f}, {:.2f})",
|
||||||
|
m_camera.position.x(), m_camera.position.y(),
|
||||||
|
m_camera.position.z())
|
||||||
|
.c_str());
|
||||||
|
ImGui::Text("%s",
|
||||||
|
std::format("Cam tgt: ({:.2f}, {:.2f}, {:.2f})",
|
||||||
|
m_camera.target.x(), m_camera.target.y(),
|
||||||
|
m_camera.target.z())
|
||||||
|
.c_str());
|
||||||
|
ImGui::Text("%s",
|
||||||
|
std::format("Cam up: ({:.2f}, {:.2f}, {:.2f})",
|
||||||
|
m_camera.up.x(), m_camera.up.y(), m_camera.up.z())
|
||||||
|
.c_str());
|
||||||
|
ImGui::Text("%s",
|
||||||
|
std::format("Cursor r/theta/phi: {:.2f}, {:.2f}, {:.2f}",
|
||||||
|
m_cursor.r, m_cursor.theta, m_cursor.phi)
|
||||||
|
.c_str());
|
||||||
}
|
}
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (m_show_imgui) {
|
||||||
|
ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
|
||||||
|
ImGui::ShowDemoWindow();
|
||||||
|
|
||||||
ImGui::SetNextWindowSize({ 300, -1 }, ImGuiCond_Once);
|
ImGui::SetNextWindowSize({ 300, -1 }, ImGuiCond_Once);
|
||||||
if (ImGui::Begin("Fun menu")) {
|
if (ImGui::Begin("Fun menu")) {
|
||||||
defer(ImGui::End());
|
defer(ImGui::End());
|
||||||
@@ -328,36 +598,47 @@ auto Application::run() -> void
|
|||||||
static_cast<VulkanRenderer::AntiAliasingKind>(
|
static_cast<VulkanRenderer::AntiAliasingKind>(
|
||||||
selected_item));
|
selected_item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::CollapsingHeader("Camera",
|
||||||
|
ImGuiTreeNodeFlags_Framed
|
||||||
|
| ImGuiTreeNodeFlags_SpanAvailWidth
|
||||||
|
| ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
ImGui::DragFloat4("Pos", m_camera.position.data());
|
||||||
|
ImGui::DragFloat4("Target", m_camera.target.data());
|
||||||
|
ImGui::DragFloat4("Up", m_camera.up.data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
m_renderer->render([&](VulkanRenderer::GL &gl) {
|
m_renderer->render([&](VulkanRenderer::GL &gl) {
|
||||||
auto view { smath::matrix_look_at(smath::Vec3 { 0.0f, 0.0f, 3.0f },
|
auto view { smath::matrix_look_at(
|
||||||
smath::Vec3 { 0.0f, 0.0f, 0.0f },
|
m_camera.position, m_camera.target, m_camera.up) };
|
||||||
smath::Vec3 { 0.0f, 1.0f, 0.0f }, false) };
|
|
||||||
auto const draw_extent = m_renderer->draw_extent();
|
auto const draw_extent = m_renderer->draw_extent();
|
||||||
auto const aspect = draw_extent.height == 0
|
auto const aspect = draw_extent.height == 0
|
||||||
? 1.0f
|
? 1.0f
|
||||||
: static_cast<float>(draw_extent.width)
|
: static_cast<float>(draw_extent.width)
|
||||||
/ static_cast<float>(draw_extent.height);
|
/ static_cast<float>(draw_extent.height);
|
||||||
auto projection { smath::matrix_perspective(
|
auto projection { smath::matrix_perspective(
|
||||||
smath::deg(70.0f), aspect, 0.1f, 10000.0f) };
|
m_camera.fovy, aspect, 0.1f, 10000.0f) };
|
||||||
projection[1][1] *= -1;
|
projection[1][1] *= -1;
|
||||||
auto view_projection { projection * view };
|
auto view_projection { projection * view };
|
||||||
|
|
||||||
auto rect_model { smath::scale(
|
// auto rect_model { smath::scale(
|
||||||
smath::translate(smath::Vec3 { 0.0f, 0.0f, -5.0f }),
|
// smath::translate(smath::Vec3 { 0.0f, 0.0f, -5.0f }),
|
||||||
smath::Vec3 { 5.0f, 5.0f, 1.0f }) };
|
// smath::Vec3 { 5.0f, 5.0f, 1.0f }) };
|
||||||
|
|
||||||
gl.set_transform(view_projection * rect_model);
|
// gl.set_transform(view_projection * rect_model);
|
||||||
|
gl.set_transform(view_projection);
|
||||||
|
|
||||||
gl.set_texture();
|
gl.set_texture();
|
||||||
auto const &meshes { m_renderer->test_meshes() };
|
auto const &meshes { m_renderer->test_meshes() };
|
||||||
if (meshes.size() > 2 && !meshes[2]->surfaces.empty()) {
|
if (meshes.size() > 2 && !meshes[2]->surfaces.empty()) {
|
||||||
auto const &surface = meshes[2]->surfaces[0];
|
auto const &surface = meshes[2]->surfaces[0];
|
||||||
gl.draw_mesh(meshes[2]->mesh_buffers, view_projection,
|
gl.draw_mesh(meshes[2]->mesh_buffers,
|
||||||
|
view_projection
|
||||||
|
* smath::translate(smath::Vec3 { 0.0f, 0.0f, -10.0f }),
|
||||||
surface.count, surface.start_index);
|
surface.count, surface.start_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,6 +667,8 @@ auto Application::run() -> void
|
|||||||
gl.draw_rectangle({ -0.5f, 0.5f }, { 0.5f, 0.5f });
|
gl.draw_rectangle({ -0.5f, 0.5f }, { 0.5f, 0.5f });
|
||||||
gl.draw_rectangle(
|
gl.draw_rectangle(
|
||||||
{ 0, 0.5f }, { 0.5f, 0.5f }, { Colors::TEAL, 1.0f });
|
{ 0, 0.5f }, { 0.5f, 0.5f }, { Colors::TEAL, 1.0f });
|
||||||
|
|
||||||
|
gl.draw_sphere(m_camera.target, 0.01f);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -474,13 +757,28 @@ auto Application::handle_keyboard_event(libinput_event_keyboard *event) -> void
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pressed && key == KEY_F11 && m_ctrl_pressed_count > 0) {
|
if (pressed && key == KEY_F11 && m_ctrl_pressed_count > 0) {
|
||||||
mouse_captured(!mouse_captured());
|
bool const new_show_imgui { !m_show_imgui };
|
||||||
m_show_imgui = !mouse_captured();
|
m_show_imgui = new_show_imgui;
|
||||||
|
mouse_captured(!new_show_imgui);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto imgui_key { linux_key_to_imgui(key) }) {
|
if (auto imgui_key { linux_key_to_imgui(key) }) {
|
||||||
|
if (m_show_imgui)
|
||||||
ImGui::GetIO().AddKeyEvent(*imgui_key, pressed);
|
ImGui::GetIO().AddKeyEvent(*imgui_key, pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_show_imgui && pressed) {
|
||||||
|
bool const shift_pressed { is_key_pressed(KEY_LEFTSHIFT)
|
||||||
|
|| is_key_pressed(KEY_RIGHTSHIFT)
|
||||||
|
|| (key == KEY_LEFTSHIFT && pressed)
|
||||||
|
|| (key == KEY_RIGHTSHIFT && pressed) };
|
||||||
|
|
||||||
|
if (auto ch { linux_key_to_char(key, shift_pressed) })
|
||||||
|
ImGui::GetIO().AddInputCharacter(*ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key < m_key_state.size())
|
||||||
|
m_key_state[key] = pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Application::clamp_mouse_to_window(int width, int height) -> void
|
auto Application::clamp_mouse_to_window(int width, int height) -> void
|
||||||
@@ -502,7 +800,14 @@ auto Application::mouse_captured(bool new_state) -> void
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mouse_captured = new_state;
|
m_mouse_captured = new_state && !m_show_imgui;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Application::is_key_pressed(uint32_t key) const -> bool
|
||||||
|
{
|
||||||
|
if (key >= m_key_state.size())
|
||||||
|
return false;
|
||||||
|
return m_key_state[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Lunar
|
} // namespace Lunar
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <SDL3/SDL_video.h>
|
#include <SDL3/SDL_video.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <linux/input-event-codes.h>
|
||||||
|
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
#include "Types.h"
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
struct libinput;
|
struct libinput;
|
||||||
struct libinput_event_keyboard;
|
struct libinput_event_keyboard;
|
||||||
@@ -26,6 +28,7 @@ struct Application {
|
|||||||
auto mouse_captured(bool new_state) -> void;
|
auto mouse_captured(bool new_state) -> void;
|
||||||
auto mouse_captured() const -> bool { return m_mouse_captured; }
|
auto mouse_captured() const -> bool { return m_mouse_captured; }
|
||||||
auto toggle_mouse_captured() -> void { mouse_captured(!m_mouse_captured); }
|
auto toggle_mouse_captured() -> void { mouse_captured(!m_mouse_captured); }
|
||||||
|
auto is_key_pressed(uint32_t key) const -> bool;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto init_input() -> void;
|
auto init_input() -> void;
|
||||||
@@ -48,6 +51,13 @@ private:
|
|||||||
|
|
||||||
double m_mouse_x { 0.0 };
|
double m_mouse_x { 0.0 };
|
||||||
double m_mouse_y { 0.0 };
|
double m_mouse_y { 0.0 };
|
||||||
|
double m_mouse_dx { 0.0 };
|
||||||
|
double m_mouse_dy { 0.0 };
|
||||||
|
|
||||||
|
std::array<bool, KEY_MAX + 1> m_key_state {};
|
||||||
|
|
||||||
|
Camera m_camera;
|
||||||
|
PolarCoordinate m_cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Lunar
|
} // namespace Lunar
|
||||||
|
|||||||
37
src/Types.h
37
src/Types.h
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include <smath.hpp>
|
#include <smath.hpp>
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
@@ -55,4 +57,39 @@ struct GPUSceneData {
|
|||||||
smath::Vec4 sunlight_color;
|
smath::Vec4 sunlight_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Camera {
|
||||||
|
smath::Vec3 position {};
|
||||||
|
smath::Vec3 target { 0, 0, -1 };
|
||||||
|
smath::Vec3 up { 0, 1, 0 };
|
||||||
|
float fovy { smath::deg(70.0f) };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PolarCoordinate {
|
||||||
|
float r, theta, phi;
|
||||||
|
|
||||||
|
static PolarCoordinate from_vec3(smath::Vec3 const &v)
|
||||||
|
{
|
||||||
|
PolarCoordinate p;
|
||||||
|
p.r = std::sqrt(v.x() * v.x() + v.y() * v.y() + v.z() * v.z());
|
||||||
|
|
||||||
|
if (p.r == 0.0f) {
|
||||||
|
p.theta = 0.0f;
|
||||||
|
p.phi = 0.0f;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.theta = std::atan2(v.z(), v.x());
|
||||||
|
p.phi = std::acos(v.y() / p.r);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
smath::Vec3 to_vec3() const
|
||||||
|
{
|
||||||
|
float sin_phi = std::sin(phi);
|
||||||
|
|
||||||
|
return smath::Vec3 { r * sin_phi * std::cos(theta), r * std::cos(phi),
|
||||||
|
r * sin_phi * std::sin(theta) };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Lunar
|
} // namespace Lunar
|
||||||
|
|||||||
@@ -341,6 +341,73 @@ auto VulkanRenderer::GL::draw_rectangle(smath::Vec2 pos, smath::Vec2 size,
|
|||||||
end();
|
end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto VulkanRenderer::GL::draw_sphere(smath::Vec3 center, float radius,
|
||||||
|
int rings, int segments, std::optional<smath::Vec4> sphere_color) -> void
|
||||||
|
{
|
||||||
|
assert(m_drawing && "begin_drawing must be called first");
|
||||||
|
|
||||||
|
if (radius <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rings < 2)
|
||||||
|
rings = 2;
|
||||||
|
if (segments < 3)
|
||||||
|
segments = 3;
|
||||||
|
|
||||||
|
float const pi = 3.14159265358979323846f;
|
||||||
|
|
||||||
|
// Use caller color if provided, otherwise keep current GL color state.
|
||||||
|
if (sphere_color.has_value())
|
||||||
|
color(*sphere_color);
|
||||||
|
|
||||||
|
// Build as latitude strips
|
||||||
|
for (int y = 0; y < rings; y++) {
|
||||||
|
float const v0 = static_cast<float>(y) / static_cast<float>(rings);
|
||||||
|
float const v1 = static_cast<float>(y + 1) / static_cast<float>(rings);
|
||||||
|
|
||||||
|
float const theta0 = v0 * pi;
|
||||||
|
float const theta1 = v1 * pi;
|
||||||
|
|
||||||
|
float const sin0 = std::sin(theta0);
|
||||||
|
float const cos0 = std::cos(theta0);
|
||||||
|
float const sin1 = std::sin(theta1);
|
||||||
|
float const cos1 = std::cos(theta1);
|
||||||
|
|
||||||
|
begin(GeometryKind::TriangleStrip);
|
||||||
|
|
||||||
|
for (int x = 0; x <= segments; x++) {
|
||||||
|
float const u
|
||||||
|
= static_cast<float>(x) / static_cast<float>(segments);
|
||||||
|
float const phi = u * (2.0f * pi);
|
||||||
|
|
||||||
|
float const sp = std::sin(phi);
|
||||||
|
float const cp = std::cos(phi);
|
||||||
|
|
||||||
|
// Vertex on ring y+1
|
||||||
|
{
|
||||||
|
smath::Vec3 n { sin1 * cp, cos1, sin1 * sp };
|
||||||
|
normal(n);
|
||||||
|
uv(smath::Vec2 { u, 1.0f - v1 });
|
||||||
|
|
||||||
|
smath::Vec3 p = center + n * radius;
|
||||||
|
vert(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertex on ring y
|
||||||
|
{
|
||||||
|
smath::Vec3 n { sin0 * cp, cos0, sin0 * sp };
|
||||||
|
normal(n);
|
||||||
|
uv(smath::Vec2 { u, 1.0f - v0 });
|
||||||
|
|
||||||
|
smath::Vec3 p = center + n * radius;
|
||||||
|
vert(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto VulkanRenderer::GL::draw_mesh(GPUMeshBuffers const &mesh,
|
auto VulkanRenderer::GL::draw_mesh(GPUMeshBuffers const &mesh,
|
||||||
smath::Mat4 const &transform, uint32_t index_count, uint32_t first_index,
|
smath::Mat4 const &transform, uint32_t index_count, uint32_t first_index,
|
||||||
int32_t vertex_offset) -> void
|
int32_t vertex_offset) -> void
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ struct VulkanRenderer {
|
|||||||
auto draw_rectangle(smath::Vec2 pos, smath::Vec2 size,
|
auto draw_rectangle(smath::Vec2 pos, smath::Vec2 size,
|
||||||
smath::Vec4 color = smath::Vec4 { Colors::WHITE, 1.0f },
|
smath::Vec4 color = smath::Vec4 { Colors::WHITE, 1.0f },
|
||||||
float rotation = 0.0f) -> void;
|
float rotation = 0.0f) -> void;
|
||||||
|
auto draw_sphere(smath::Vec3 center, float radius, int rings = 16,
|
||||||
|
int segments = 32, std::optional<smath::Vec4> sphere_color = {})
|
||||||
|
-> void;
|
||||||
auto end() -> void;
|
auto end() -> void;
|
||||||
auto flush() -> void;
|
auto flush() -> void;
|
||||||
|
|
||||||
|
|||||||
2
thirdparty/smath
vendored
2
thirdparty/smath
vendored
Submodule thirdparty/smath updated: 1a42238a41...830c64b25a
Reference in New Issue
Block a user