mirror of
https://github.com/slendidev/lunar.git
synced 2026-01-30 16:28:58 +02:00
@@ -2,9 +2,11 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <numbers>
|
||||
#include <optional>
|
||||
#include <print>
|
||||
#include <stdexcept>
|
||||
@@ -122,6 +124,40 @@ auto linux_key_to_imgui(uint32_t keycode) -> std::optional<ImGuiKey>
|
||||
return ImGuiKey_F11;
|
||||
case KEY_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:
|
||||
return ImGuiKey_0;
|
||||
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 Lunar {
|
||||
@@ -226,6 +398,8 @@ Application::Application()
|
||||
m_logger.info("App init done!");
|
||||
|
||||
m_renderer->set_antialiasing(VulkanRenderer::AntiAliasingKind::MSAA_4X);
|
||||
|
||||
m_cursor = PolarCoordinate::from_vec3(m_camera.target - m_camera.position);
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
@@ -252,6 +426,7 @@ auto Application::run() -> void
|
||||
while (m_running) {
|
||||
uint64_t now { SDL_GetTicks() };
|
||||
uint64_t dt { now - last };
|
||||
float dt_seconds { static_cast<float>(dt) / 1000.0f };
|
||||
last = now;
|
||||
|
||||
if (dt > 0)
|
||||
@@ -273,6 +448,8 @@ auto Application::run() -> void
|
||||
} else if (e.type == SDL_EVENT_MOUSE_MOTION) {
|
||||
m_mouse_x = e.motion.x;
|
||||
m_mouse_y = e.motion.y;
|
||||
m_mouse_dx = e.motion.xrel;
|
||||
m_mouse_dy = e.motion.yrel;
|
||||
forward_to_imgui = true;
|
||||
} else if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN
|
||||
|| e.type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
||||
@@ -289,26 +466,119 @@ auto Application::run() -> void
|
||||
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_ImplVulkan_NewFrame();
|
||||
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowSize({ 300, 100 });
|
||||
ImGui::SetNextWindowPos({ 0, 0 });
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4 { 0, 0, 0, 0.5f });
|
||||
if (ImGui::Begin("Debug Info", nullptr,
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize)) {
|
||||
defer(ImGui::End());
|
||||
|
||||
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();
|
||||
|
||||
if (m_show_imgui) {
|
||||
ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
|
||||
ImGui::ShowDemoWindow();
|
||||
|
||||
ImGui::SetNextWindowSize({ 100, 50 });
|
||||
ImGui::SetNextWindowPos({ 0, 0 });
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4 { 0, 0, 0, 0.5f });
|
||||
if (ImGui::Begin("Debug Info", nullptr,
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize)) {
|
||||
defer(ImGui::End());
|
||||
|
||||
ImGui::Text("%s", std::format("FPS: {:.2f}", fps).c_str());
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::SetNextWindowSize({ 300, -1 }, ImGuiCond_Once);
|
||||
if (ImGui::Begin("Fun menu")) {
|
||||
defer(ImGui::End());
|
||||
@@ -328,36 +598,47 @@ auto Application::run() -> void
|
||||
static_cast<VulkanRenderer::AntiAliasingKind>(
|
||||
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();
|
||||
|
||||
m_renderer->render([&](VulkanRenderer::GL &gl) {
|
||||
auto view { smath::matrix_look_at(smath::Vec3 { 0.0f, 0.0f, 3.0f },
|
||||
smath::Vec3 { 0.0f, 0.0f, 0.0f },
|
||||
smath::Vec3 { 0.0f, 1.0f, 0.0f }, false) };
|
||||
auto view { smath::matrix_look_at(
|
||||
m_camera.position, m_camera.target, m_camera.up) };
|
||||
auto const draw_extent = m_renderer->draw_extent();
|
||||
auto const aspect = draw_extent.height == 0
|
||||
? 1.0f
|
||||
: static_cast<float>(draw_extent.width)
|
||||
/ static_cast<float>(draw_extent.height);
|
||||
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;
|
||||
auto view_projection { projection * view };
|
||||
|
||||
auto rect_model { smath::scale(
|
||||
smath::translate(smath::Vec3 { 0.0f, 0.0f, -5.0f }),
|
||||
smath::Vec3 { 5.0f, 5.0f, 1.0f }) };
|
||||
// auto rect_model { smath::scale(
|
||||
// smath::translate(smath::Vec3 { 0.0f, 0.0f, -5.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();
|
||||
auto const &meshes { m_renderer->test_meshes() };
|
||||
if (meshes.size() > 2 && !meshes[2]->surfaces.empty()) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -386,6 +667,8 @@ auto Application::run() -> void
|
||||
gl.draw_rectangle({ -0.5f, 0.5f }, { 0.5f, 0.5f });
|
||||
gl.draw_rectangle(
|
||||
{ 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) {
|
||||
mouse_captured(!mouse_captured());
|
||||
m_show_imgui = !mouse_captured();
|
||||
bool const new_show_imgui { !m_show_imgui };
|
||||
m_show_imgui = new_show_imgui;
|
||||
mouse_captured(!new_show_imgui);
|
||||
}
|
||||
|
||||
if (auto imgui_key { linux_key_to_imgui(key) }) {
|
||||
ImGui::GetIO().AddKeyEvent(*imgui_key, pressed);
|
||||
if (m_show_imgui)
|
||||
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
|
||||
@@ -502,7 +800,14 @@ auto Application::mouse_captured(bool new_state) -> void
|
||||
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
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include <SDL3/SDL_video.h>
|
||||
#include <imgui.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include "Types.h"
|
||||
|
||||
struct libinput;
|
||||
struct libinput_event_keyboard;
|
||||
@@ -26,6 +28,7 @@ struct Application {
|
||||
auto mouse_captured(bool new_state) -> void;
|
||||
auto mouse_captured() const -> bool { return m_mouse_captured; }
|
||||
auto toggle_mouse_captured() -> void { mouse_captured(!m_mouse_captured); }
|
||||
auto is_key_pressed(uint32_t key) const -> bool;
|
||||
|
||||
private:
|
||||
auto init_input() -> void;
|
||||
@@ -48,6 +51,13 @@ private:
|
||||
|
||||
double m_mouse_x { 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
|
||||
|
||||
37
src/Types.h
37
src/Types.h
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <smath.hpp>
|
||||
#include <vk_mem_alloc.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
@@ -55,4 +57,39 @@ struct GPUSceneData {
|
||||
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
|
||||
|
||||
@@ -341,6 +341,73 @@ auto VulkanRenderer::GL::draw_rectangle(smath::Vec2 pos, smath::Vec2 size,
|
||||
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,
|
||||
smath::Mat4 const &transform, uint32_t index_count, uint32_t first_index,
|
||||
int32_t vertex_offset) -> void
|
||||
@@ -530,7 +597,7 @@ auto VulkanRenderer::resize(uint32_t width, uint32_t height) -> void
|
||||
auto VulkanRenderer::set_antialiasing(AntiAliasingKind kind) -> void
|
||||
{
|
||||
enqueue_render_command(RenderCommand {
|
||||
RenderCommand::SetAntiAliasing { kind },
|
||||
RenderCommand::SetAntiAliasing { kind },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@ struct VulkanRenderer {
|
||||
auto draw_rectangle(smath::Vec2 pos, smath::Vec2 size,
|
||||
smath::Vec4 color = smath::Vec4 { Colors::WHITE, 1.0f },
|
||||
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 flush() -> void;
|
||||
|
||||
|
||||
2
thirdparty/smath
vendored
2
thirdparty/smath
vendored
Submodule thirdparty/smath updated: 1a42238a41...830c64b25a
Reference in New Issue
Block a user