Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f562030
fix window displays
exdal Aug 15, 2025
5310acb
add atmos refreshing
exdal Aug 15, 2025
c659b6d
add window key events
exdal Aug 16, 2025
c43cea7
separate editor camera from core
exdal Aug 18, 2025
2f01427
editor camera matrix
exdal Aug 18, 2025
2b49971
smooth editor camera
exdal Aug 19, 2025
6f5067e
add hiz fallback
exdal Aug 19, 2025
8e3fda8
runtime mouse movement
exdal Aug 20, 2025
cba8cc8
fix iterator error
exdal Aug 20, 2025
e3f2479
fix camera mouse movements
exdal Aug 22, 2025
6943202
reorganize scenerenderer
exdal Aug 22, 2025
ebb61dd
mesh level two pass occlusion culling
exdal Aug 23, 2025
bfa366c
meshlet index offsetting
exdal Aug 24, 2025
9dd3a4a
debugging gpu crash
exdal Aug 25, 2025
ac79ad2
revert two pass occlusion
exdal Aug 25, 2025
2c801f3
fix gpu materials
exdal Aug 26, 2025
ef72d36
imgui asset fixes
exdal Aug 26, 2025
512c4ed
Merge branch 'dev' of https://github.com/exdal/Lorr into dev
exdal Aug 26, 2025
5256603
remove atomic.slang and gpu.slang
exdal Aug 28, 2025
47e7341
Merge branch 'dev' of https://github.com/exdal/Lorr into dev
exdal Aug 28, 2025
8f69076
bounds check during vis decode
exdal Aug 28, 2025
1ee29e0
add slang for linux
exdal Aug 28, 2025
52c3bab
refactor transfer manager
exdal Aug 29, 2025
c03faf7
fix materials
exdal Aug 29, 2025
9fd7d0b
two pass occlusion culling for meshes (again, with delay)
exdal Aug 31, 2025
644b223
fix syncvals
exdal Sep 1, 2025
15ac96c
add two pass occlusion for meshlets
exdal Sep 2, 2025
207e511
fix cull triangles OOB
exdal Sep 2, 2025
3d1f41b
more conservative hiz
exdal Sep 2, 2025
e15ac98
Merge branch 'master' into dev
exdal Sep 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Lorr/Editor/EditorModule.cc
Original file line number Diff line number Diff line change
Expand Up @@ -365,12 +365,14 @@ static auto draw_welcome_popup(EditorModule &self) -> void {
ZoneScoped;

auto &window = lr::App::mod<lr::Window>();
ImGui::SetNextWindowSize({ 480.0f, 350.0f }, ImGuiCond_Appearing);
auto center_window = glm::vec2(window.get_size()) * 0.5f;
ImGui::SetNextWindowSize({ 480.0f, 350.0f }, ImGuiCond_Always);
ImGui::SetNextWindowPos({ center_window.x, center_window.y }, ImGuiCond_Always, { 0.5f, 0.5f });
constexpr auto popup_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
if (ImGui::BeginPopupModal("###welcome", nullptr, popup_flags)) {
// ── HEADERS ─────────────────────────────────────────────────────────
ImGui::TextUnformatted("placeholder");
ImGui::InvisibleButton("placeholder", { 0.0f, 75.0f });
ImGui::InvisibleButton("placeholder", { -FLT_MAX, 75.0f });

// ── SECTIONS ────────────────────────────────────────────────────────
if (ImGui::BeginTabBar("project_guide")) {
Expand Down
2 changes: 1 addition & 1 deletion Lorr/Editor/Window/AssetBrowserWindow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ static auto draw_dir_contents(AssetBrowserWindow &self) -> void {
auto *asset_texture = editor.get_asset_texture(asset);
auto asset_image = imgui_renderer.add_image(asset_texture->image_view);
ImGui::image_button(file_name, asset_image, button_size);
if (ImGui::BeginDragDropSource()) {
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) {
ImGui::SetDragDropPayload("ASSET_BY_UUID", &asset->uuid, sizeof(lr::UUID));
ImGui::EndDragDropSource();
}
Expand Down
79 changes: 38 additions & 41 deletions Lorr/Editor/Window/InspectorWindow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,6 @@ static auto draw_inspector(InspectorWindow &) -> void {
}

lr::ECS::ComponentWrapper component(selected_entity, component_id);
if (!component.is_component()) {
return;
}

auto name_with_icon = stack.format_char("{}", component.name);
ImGui::PushID(static_cast<i32>(component_id));
if (ImGui::CollapsingHeader(name_with_icon, nullptr, ImGuiTreeNodeFlags_DefaultOpen)) {
Expand All @@ -95,43 +91,45 @@ static auto draw_inspector(InspectorWindow &) -> void {
ImGui::TableSetupColumn("label", 0, 0.5f);
ImGui::TableSetupColumn("property", ImGuiTableColumnFlags_WidthStretch);

ImGui::PushID(component.members_data);
component.for_each([&](usize &i, std::string_view member_name, lr::ECS::ComponentWrapper::Member &member) {
// Draw prop label
ImGui::TableNextRow();
ImGui::TableNextColumn();

ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y);
ImGui::TextUnformatted(member_name.data(), member_name.data() + member_name.length());
ImGui::TableNextColumn();

bool component_modified = false;
ImGui::PushID(static_cast<i32>(i));
std::visit(
ls::match{
[](const auto &) {},
[&](bool *v) { component_modified |= ImGui::Checkbox("", v); },
[&](f32 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_Float); },
[&](i32 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_S32); },
[&](u32 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_U32); },
[&](i64 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_S64); },
[&](u64 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_U64); },
[&](glm::vec2 *v) { component_modified |= ImGui::drag_vec(0, glm::value_ptr(*v), 2, ImGuiDataType_Float); },
[&](glm::vec3 *v) { component_modified |= ImGui::drag_vec(0, glm::value_ptr(*v), 3, ImGuiDataType_Float); },
[&](glm::vec4 *v) { component_modified |= ImGui::drag_vec(0, glm::value_ptr(*v), 4, ImGuiDataType_Float); },
[](std::string *v) { ImGui::InputText("", v); },
[&](lr::UUID *v) { component_modified |= inspect_asset(*v); },
},
member
);
if (component.is_component()) {
ImGui::PushID(component.members_data);
component.for_each([&](usize &i, std::string_view member_name, lr::ECS::ComponentWrapper::Member &member) {
// Draw prop label
ImGui::TableNextRow();
ImGui::TableNextColumn();

ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y);
ImGui::TextUnformatted(member_name.data(), member_name.data() + member_name.length());
ImGui::TableNextColumn();

bool component_modified = false;
ImGui::PushID(static_cast<i32>(i));
std::visit(
ls::match{
[](const auto &) {},
[&](bool *v) { component_modified |= ImGui::Checkbox("", v); },
[&](f32 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_Float); },
[&](i32 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_S32); },
[&](u32 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_U32); },
[&](i64 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_S64); },
[&](u64 *v) { component_modified |= ImGui::drag_vec(0, v, 1, ImGuiDataType_U64); },
[&](glm::vec2 *v) { component_modified |= ImGui::drag_vec(0, glm::value_ptr(*v), 2, ImGuiDataType_Float); },
[&](glm::vec3 *v) { component_modified |= ImGui::drag_vec(0, glm::value_ptr(*v), 3, ImGuiDataType_Float); },
[&](glm::vec4 *v) { component_modified |= ImGui::drag_vec(0, glm::value_ptr(*v), 4, ImGuiDataType_Float); },
[](std::string *v) { ImGui::InputText("", v); },
[&](lr::UUID *v) { component_modified |= inspect_asset(*v); },
},
member
);
ImGui::PopID();

if (component_modified) {
selected_entity.modified(component_id.entity());
}
});
ImGui::PopID();
}

if (component_modified) {
selected_entity.modified(component_id.entity());
}
});

ImGui::PopID();
ImGui::EndTable();

if (ImGui::Button("Remove Component", ImVec2(region.x, 0))) {
Expand All @@ -150,8 +148,7 @@ static auto draw_inspector(InspectorWindow &) -> void {
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
ImGui::SetNextWindowSize({ region.x, 0 });
if (ImGui::BeginPopup("add_component")) {
auto &entity_db = active_scene->get_entity_db();
auto all_components = entity_db.get_components();
auto all_components = active_scene->get_known_component_ids();
for (const auto &component : all_components) { //
lr::memory::ScopedStack stack;
ImGui::PushID(static_cast<i32>(component.raw_id()));
Expand Down
1 change: 0 additions & 1 deletion Lorr/Editor/Window/SceneBrowserWindow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ static auto draw_children(SceneBrowserWindow &self, flecs::entity root) -> void
auto q = world //
.query_builder()
.with(flecs::ChildOf, root)
.without<lr::ECS::Hidden>()
.build();

ImGui::TableNextRow();
Expand Down
145 changes: 73 additions & 72 deletions Lorr/Editor/Window/ViewportWindow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "Engine/Asset/Asset.hh"
#include "Engine/Core/App.hh"

#include "Engine/Math/Quat.hh"

#include <ImGuizmo.h>
#include <glm/gtx/matrix_decompose.hpp>

Expand Down Expand Up @@ -124,37 +126,39 @@ static auto draw_tools(ViewportWindow &self) -> void {
ImGui::SetNextWindowPos(editor_camera_popup_pos, ImGuiCond_Appearing);
ImGui::SetNextWindowSize({ editor_camera_popup_width, 0 }, ImGuiCond_Appearing);
if (ImGui::BeginPopup("editor_camera")) {
auto editor_camera = active_scene->get_editor_camera();
auto *camera_transform = editor_camera.get_mut<lr::ECS::Transform>();
auto *camera_info = editor_camera.get_mut<lr::ECS::Camera>();

ImGui::SeparatorText("Position");
ImGui::drag_vec(0, glm::value_ptr(camera_transform->position), 3, ImGuiDataType_Float);
ImGui::drag_vec(0, glm::value_ptr(self.editor_camera.position), 3, ImGuiDataType_Float);

ImGui::SeparatorText("Rotation");
auto camera_rotation_degrees = glm::degrees(camera_transform->rotation);
ImGui::drag_vec(1, glm::value_ptr(camera_rotation_degrees), 3, ImGuiDataType_Float);
camera_transform->rotation = glm::radians(lr::Math::normalize_180(camera_rotation_degrees));
auto camera_yaw_pitch = glm::vec2(self.editor_camera.yaw, self.editor_camera.pitch);
ImGui::drag_vec(1, glm::value_ptr(camera_yaw_pitch), 2, ImGuiDataType_Float);
self.editor_camera.yaw = camera_yaw_pitch.x;
self.editor_camera.pitch = camera_yaw_pitch.y;

ImGui::SeparatorText("FoV");
ImGui::drag_vec(2, &camera_info->fov, 1, ImGuiDataType_Float);
ImGui::drag_vec(2, &self.editor_camera.fov, 1, ImGuiDataType_Float);

ImGui::SeparatorText("Far Clip");
ImGui::drag_vec(3, &camera_info->far_clip, 1, ImGuiDataType_Float);
ImGui::drag_vec(3, &self.editor_camera.far_clip, 1, ImGuiDataType_Float);

ImGui::SeparatorText("Velocity");
ImGui::drag_vec(4, &camera_info->velocity_mul, 1, ImGuiDataType_Float);
ImGui::SeparatorText("Max Velocity");
ImGui::drag_vec(4, &self.editor_camera.max_velocity, 1, ImGuiDataType_Float);

ImGui::EndPopup();
}

if (editor.show_debug) {
auto &cull_flags = reinterpret_cast<i32 &>(active_scene->get_cull_flags());
auto &scene_renderer = lr::App::mod<lr::SceneRenderer>();

ImGui::CheckboxFlags("Cull Mesh Frustum", &cull_flags, std::to_underlying(lr::GPU::CullFlags::MeshFrustum));
ImGui::CheckboxFlags("Cull Mesh Occlusion", &cull_flags, std::to_underlying(lr::GPU::CullFlags::MeshOcclusion));
ImGui::CheckboxFlags("Cull Meshlet Frustum", &cull_flags, std::to_underlying(lr::GPU::CullFlags::MeshletFrustum));
ImGui::CheckboxFlags("Cull Meshlet Occlusion", &cull_flags, std::to_underlying(lr::GPU::CullFlags::MeshletOcclusion));
ImGui::CheckboxFlags("Cull Triangle Back Face", &cull_flags, std::to_underlying(lr::GPU::CullFlags::TriangleBackFace));
ImGui::CheckboxFlags("Cull Micro Triangles", &cull_flags, std::to_underlying(lr::GPU::CullFlags::MicroTriangles));
ImGui::CheckboxFlags("Cull Occlusion", &cull_flags, std::to_underlying(lr::GPU::CullFlags::Occlusion));
// ImGui::Checkbox("Debug Lines", &editor.scene_renderer.debug_lines);
ImGui::Checkbox("Debug Lines", &scene_renderer.debug_lines);
ImGui::SliderFloat("Overdraw Heatmap", &scene_renderer.overdraw_heatmap_scale, 0.0f, 100.0f);
}
}

Expand All @@ -168,18 +172,13 @@ static auto draw_viewport(ViewportWindow &self, vuk::Format format, vuk::Extent3
auto *active_scene = asset_man.get_scene(active_project.active_scene_uuid);
auto &selected_entity = active_project.selected_entity;

auto editor_camera = active_scene->get_editor_camera();
auto *current_window = ImGui::GetCurrentWindow();
auto window_rect = current_window->InnerRect;
auto window_pos = window_rect.Min;
auto window_size = window_rect.GetSize();
auto work_area_size = ImGui::GetContentRegionAvail();
auto &io = ImGui::GetIO();

auto *camera = editor_camera.get_mut<lr::ECS::Camera>();
auto *camera_transform = editor_camera.get_mut<lr::ECS::Transform>();
camera->resolution = { window_size.x, window_size.y };
camera->aspect_ratio = window_size.x / window_size.y;
auto delta_time = io.DeltaTime;

ImGuizmo::SetDrawlist();
ImGuizmo::SetOrthographic(false);
Expand All @@ -200,7 +199,50 @@ static auto draw_viewport(ViewportWindow &self, vuk::Format format, vuk::Extent3
requested_texel_transform.emplace(glm::uvec2(mouse_pos_rel.x, mouse_pos_rel.y));
}

auto prepared_frame = active_scene->prepare_frame(scene_renderer);
{
// Update editor camera
auto target_velocity = glm::vec3(0.0f);
if (!ImGuizmo::IsUsingAny() && ImGui::IsWindowHovered()) {
if (ImGui::IsKeyDown(ImGuiKey_W)) {
target_velocity.x = self.editor_camera.max_velocity;
}

if (ImGui::IsKeyDown(ImGuiKey_S)) {
target_velocity.x = -self.editor_camera.max_velocity;
}

if (ImGui::IsKeyDown(ImGuiKey_D)) {
target_velocity.z = self.editor_camera.max_velocity;
}

if (ImGui::IsKeyDown(ImGuiKey_A)) {
target_velocity.z = -self.editor_camera.max_velocity;
}

if (ImGui::IsKeyDown(ImGuiKey_E)) {
target_velocity.y = self.editor_camera.max_velocity;
}

if (ImGui::IsKeyDown(ImGuiKey_Q)) {
target_velocity.y = -self.editor_camera.max_velocity;
}

if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
auto drag = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left, 0);
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Left);

auto sensitivity = 0.1f;
self.editor_camera.yaw += drag.x * sensitivity;
self.editor_camera.pitch -= drag.y * sensitivity;
self.editor_camera.pitch = glm::clamp(self.editor_camera.pitch, -89.9f, 89.9f);
}
}

self.editor_camera.resolution = { window_size.x, window_size.y };
self.editor_camera.update(delta_time, target_velocity);
}

auto prepared_frame = active_scene->prepare_frame(scene_renderer, self.editor_camera); // NOLINT(cppcoreguidelines-slicing)

auto viewport_attachment_info = vuk::ImageAttachment{
.image_type = vuk::ImageType::e2D,
Expand All @@ -214,7 +256,7 @@ static auto draw_viewport(ViewportWindow &self, vuk::Format format, vuk::Extent3
};
auto viewport_attachment = vuk::declare_ia("viewport", viewport_attachment_info);
auto scene_render_info = lr::SceneRenderInfo{
.delta_time = ImGui::GetIO().DeltaTime,
.delta_time = delta_time,
.cull_flags = active_scene->get_cull_flags(),
.picking_texel = requested_texel_transform,
};
Expand All @@ -234,14 +276,18 @@ static auto draw_viewport(ViewportWindow &self, vuk::Format format, vuk::Extent3
}

if (selected_entity && selected_entity.has<lr::ECS::Transform>()) {
auto camera_forward = glm::vec3(0.0, 0.0, 1.0) * lr::Math::quat_dir(camera_transform->rotation);
auto camera_projection = glm::perspective(glm::radians(camera->fov), camera->aspect_ratio, camera->far_clip, camera->near_clip);
auto camera_view = glm::lookAt(camera_transform->position, camera_transform->position + camera_forward, glm::vec3(0.0, 1.0, 0.0));
camera_projection[1][1] *= -1.0f;
auto camera_direction = self.editor_camera.direction();
auto camera_projection = glm::perspectiveRH_ZO(
glm::radians(self.editor_camera.fov),
self.editor_camera.aspect_ratio(),
self.editor_camera.far_clip,
self.editor_camera.near_clip
);
auto camera_view = glm::lookAt(self.editor_camera.position, self.editor_camera.position + camera_direction, glm::vec3(0.0, 1.0, 0.0));

auto *transform = selected_entity.get_mut<lr::ECS::Transform>();
auto T = glm::translate(glm::mat4(1.0), transform->position);
auto R = glm::mat4_cast(glm::quat(transform->rotation));
auto R = glm::mat4_cast(lr::Math::quat_dir(transform->rotation));
auto S = glm::scale(glm::mat4(1.0), transform->scale);
auto gizmo_mat = T * R * S;
auto delta_mat = glm::mat4(1.0f);
Expand Down Expand Up @@ -274,51 +320,6 @@ static auto draw_viewport(ViewportWindow &self, vuk::Format format, vuk::Extent3
selected_entity.modified<lr::ECS::Transform>();
}
}

// ── CAMERA CONTROLLER ───────────────────────────────────────────────
if (!ImGuizmo::IsUsingAny() && ImGui::IsWindowHovered()) {
bool reset_z = false;
bool reset_x = false;

if (ImGui::IsKeyDown(ImGuiKey_W)) {
camera->axis_velocity.z = -camera->velocity_mul;
reset_z |= true;
}

if (ImGui::IsKeyDown(ImGuiKey_S)) {
camera->axis_velocity.z = camera->velocity_mul;
reset_z |= true;
}

if (ImGui::IsKeyDown(ImGuiKey_A)) {
camera->axis_velocity.x = -camera->velocity_mul;
reset_x |= true;
}

if (ImGui::IsKeyDown(ImGuiKey_D)) {
camera->axis_velocity.x = camera->velocity_mul;
reset_x |= true;
}

if (!reset_z) {
camera->axis_velocity.z = 0.0;
}

if (!reset_x) {
camera->axis_velocity.x = 0.0;
}

if (ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
auto drag = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right, 0);
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Right);

auto sensitivity = 0.1f;
auto camera_rotation_degrees = glm::degrees(camera_transform->rotation);
camera_rotation_degrees.x += drag.x * sensitivity;
camera_rotation_degrees.y += drag.y * sensitivity;
camera_transform->rotation = glm::radians(camera_rotation_degrees);
}
}
}

ViewportWindow::ViewportWindow(std::string name_, bool open_) : IWindow(std::move(name_), open_) {
Expand Down
4 changes: 4 additions & 0 deletions Lorr/Editor/Window/ViewportWindow.hh
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#pragma once

#include "Editor/Window/IWindow.hh"
#include "Engine/Scene/EditorCamera.hh"

#include <flecs.h>

namespace led {
struct ViewportWindow : IWindow {
u32 gizmo_op = 0;
lr::EditorCamera editor_camera = {};

ViewportWindow(std::string name_, bool open_ = true);

Expand Down
13 changes: 9 additions & 4 deletions Lorr/Editor/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ i32 main(i32, c8 **) {

lr::Window::init_sdl();
auto primary_display = lr::Window::display_at(0).value();
auto window_info = lr::WindowInfo{
.title = "Lorr Editor",
.display = &primary_display,
.width = 1720,
.height = 880,
.flags = lr::WindowFlag::Centered | lr::WindowFlag::Resizable,
};

lr::AppBuilder() //
.module<lr::Device>(3)
.module<lr::Window>(
lr::WindowInfo{ .title = "Lorr Editor", .width = 1720, .height = 880, .flags = lr::WindowFlag::Centered | lr::WindowFlag::Resizable }
)
.module<lr::Device>(1)
.module<lr::Window>(window_info)
.module<lr::AssetManager>()
.module<lr::ImGuiRenderer>()
.module<lr::SceneRenderer>()
Expand Down
Loading
Loading