2025-07-10 13:29:03 +03:30
|
|
|
#include <asset_manager/asset_manager.hpp>
|
2025-07-10 13:55:18 +03:30
|
|
|
#include <camera/component.hpp>
|
|
|
|
#include <engine/scene/components.hpp>
|
2025-07-05 13:28:41 +03:30
|
|
|
#include <glm/glm.hpp>
|
|
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
#include <imgui.h>
|
|
|
|
#include <imgui_internal.h>
|
|
|
|
#include <mirror/panel/properties.hpp>
|
|
|
|
|
2025-07-11 00:05:48 +03:30
|
|
|
namespace lt {
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-05 15:36:53 +03:30
|
|
|
void PropertiesPanel::on_user_interface_update()
|
2025-07-05 13:28:41 +03:30
|
|
|
{
|
|
|
|
ImGui::Begin("Properties");
|
|
|
|
|
2025-07-05 15:36:53 +03:30
|
|
|
if (m_entity_context.is_valid())
|
2025-07-05 13:28:41 +03:30
|
|
|
{
|
2025-07-05 15:36:53 +03:30
|
|
|
if (m_entity_context.has_component<TagComponent>())
|
2025-07-05 13:28:41 +03:30
|
|
|
{
|
2025-07-06 14:02:50 +03:30
|
|
|
auto &tagComponent = m_entity_context.get_component<TagComponent>();
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 14:02:50 +03:30
|
|
|
auto buffer = std::array<char, 256> {};
|
|
|
|
memset(buffer.data(), 0, buffer.size());
|
|
|
|
std::strncpy(buffer.data(), tagComponent.tag.c_str(), buffer.size());
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 14:02:50 +03:30
|
|
|
if (ImGui::InputText("##Tag", buffer.data(), buffer.size()))
|
|
|
|
{
|
|
|
|
tagComponent.tag = buffer.data();
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::PushItemWidth(-1);
|
|
|
|
|
|
|
|
if (ImGui::Button("Add component"))
|
2025-07-06 15:10:34 +03:30
|
|
|
{
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::OpenPopup("Components");
|
2025-07-06 15:10:34 +03:30
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
|
|
|
if (ImGui::BeginPopup("Components"))
|
|
|
|
{
|
|
|
|
if (ImGui::Selectable(
|
|
|
|
"SpriteRenderer",
|
|
|
|
false,
|
2025-07-05 15:36:53 +03:30
|
|
|
m_entity_context.has_component<SpriteRendererComponent>() ?
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGuiSelectableFlags_Disabled :
|
2025-07-06 15:10:34 +03:30
|
|
|
ImGuiSelectableFlags {}
|
2025-07-05 13:28:41 +03:30
|
|
|
))
|
2025-07-06 15:10:34 +03:30
|
|
|
{
|
2025-07-06 14:02:50 +03:30
|
|
|
m_entity_context.add_component<SpriteRendererComponent>(
|
2025-07-11 00:05:48 +03:30
|
|
|
lt::AssetManager::get_texture("awesomeface")
|
2025-07-05 13:28:41 +03:30
|
|
|
);
|
2025-07-06 15:10:34 +03:30
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
|
|
|
if (ImGui::Selectable(
|
|
|
|
"Camera",
|
|
|
|
false,
|
2025-07-05 15:36:53 +03:30
|
|
|
m_entity_context.has_component<CameraComponent>() ?
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGuiSelectableFlags_Disabled :
|
2025-07-06 15:10:34 +03:30
|
|
|
ImGuiSelectableFlags {}
|
2025-07-05 13:28:41 +03:30
|
|
|
))
|
2025-07-06 15:10:34 +03:30
|
|
|
{
|
2025-07-06 14:02:50 +03:30
|
|
|
m_entity_context.add_component<CameraComponent>();
|
2025-07-06 15:10:34 +03:30
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
|
|
|
ImGui::PopItemWidth();
|
|
|
|
|
2025-07-05 15:36:53 +03:30
|
|
|
draw_component<TransformComponent>(
|
2025-07-05 13:28:41 +03:30
|
|
|
"Transform Component",
|
2025-07-05 14:23:01 +03:30
|
|
|
m_entity_context,
|
2025-07-05 13:28:41 +03:30
|
|
|
[&](auto &transformComponent) {
|
2025-07-05 15:36:53 +03:30
|
|
|
draw_vec3_control("Translation", transformComponent.translation);
|
2025-07-05 13:28:41 +03:30
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2025-07-05 15:36:53 +03:30
|
|
|
draw_component<SpriteRendererComponent>(
|
2025-07-05 13:28:41 +03:30
|
|
|
"SpriteRenderer Component",
|
2025-07-05 14:23:01 +03:30
|
|
|
m_entity_context,
|
2025-07-05 13:28:41 +03:30
|
|
|
[&](auto &spriteRendererComponent) {
|
|
|
|
ImGui::ColorEdit4("Color", &spriteRendererComponent.tint[0]);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2025-07-05 15:36:53 +03:30
|
|
|
draw_component<CameraComponent>(
|
2025-07-05 13:28:41 +03:30
|
|
|
"Camera Component",
|
2025-07-05 14:23:01 +03:30
|
|
|
m_entity_context,
|
2025-07-05 13:28:41 +03:30
|
|
|
[&](auto &cameraComponent) {
|
|
|
|
auto &camera = cameraComponent.camera;
|
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
auto projection_type = camera.get_projection_type();
|
|
|
|
auto projection_types_str = std::array<const char *, 2> {
|
2025-07-06 14:02:50 +03:30
|
|
|
"Orthographic",
|
|
|
|
"Perspective",
|
|
|
|
};
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (ImGui::BeginCombo("ProjectionType", projection_types_str[(int)projection_type]))
|
2025-07-05 13:28:41 +03:30
|
|
|
{
|
2025-07-06 15:10:34 +03:30
|
|
|
for (auto idx = 0; idx < 2; idx++)
|
2025-07-05 13:28:41 +03:30
|
|
|
{
|
2025-07-06 15:10:34 +03:30
|
|
|
const auto is_selected = static_cast<int>(projection_type) == idx;
|
|
|
|
if (ImGui::Selectable(projection_types_str[idx], is_selected))
|
2025-07-05 13:28:41 +03:30
|
|
|
{
|
2025-07-06 15:10:34 +03:30
|
|
|
projection_type = static_cast<SceneCamera::ProjectionType>(idx);
|
|
|
|
camera.set_projection_type(projection_type);
|
2025-07-05 13:28:41 +03:30
|
|
|
}
|
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (is_selected)
|
|
|
|
{
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::SetItemDefaultFocus();
|
2025-07-06 15:10:34 +03:30
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndCombo();
|
|
|
|
}
|
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (projection_type == SceneCamera::ProjectionType::Orthographic)
|
2025-07-05 13:28:41 +03:30
|
|
|
{
|
2025-07-06 15:10:34 +03:30
|
|
|
auto ortho_size = float {};
|
|
|
|
auto near_plane = float {};
|
|
|
|
auto far_plane = float {};
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
ortho_size = camera.get_orthographic_size();
|
|
|
|
near_plane = camera.get_orthographic_near_plane();
|
|
|
|
far_plane = camera.get_orthographic_far_plane();
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (ImGui::DragFloat("Orthographic Size", &ortho_size))
|
|
|
|
{
|
|
|
|
camera.set_orthographic_size(ortho_size);
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (ImGui::DragFloat("Near Plane", &near_plane))
|
|
|
|
{
|
|
|
|
camera.set_orthographic_near_plane(near_plane);
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (ImGui::DragFloat("Far Plane", &far_plane))
|
|
|
|
{
|
|
|
|
camera.set_orthographic_far_plane(far_plane);
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
else // perspective
|
|
|
|
{
|
2025-07-06 15:10:34 +03:30
|
|
|
auto vertical_fov = float {};
|
|
|
|
auto near_plane = float {};
|
|
|
|
auto far_plane = float {};
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
vertical_fov = glm::degrees(camera.get_perspective_vertical_fov());
|
|
|
|
near_plane = camera.get_perspective_near_plane();
|
|
|
|
far_plane = camera.get_perspective_far_plane();
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (ImGui::DragFloat("Vertical FOV", &vertical_fov))
|
|
|
|
{
|
|
|
|
camera.set_perspective_vertical_fov(glm::radians(vertical_fov));
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (ImGui::DragFloat("Near Plane", &near_plane))
|
|
|
|
{
|
|
|
|
camera.set_perspective_near_plane(near_plane);
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
if (ImGui::DragFloat("Far Plane", &far_plane))
|
|
|
|
{
|
|
|
|
camera.set_perspective_far_plane(far_plane);
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::End();
|
|
|
|
}
|
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
void PropertiesPanel::set_entity_context(const Entity &entity)
|
2025-07-05 13:28:41 +03:30
|
|
|
{
|
2025-07-05 14:23:01 +03:30
|
|
|
m_entity_context = entity;
|
2025-07-05 13:28:41 +03:30
|
|
|
}
|
|
|
|
|
2025-07-05 15:36:53 +03:30
|
|
|
void PropertiesPanel::draw_vec3_control(
|
2025-07-05 13:28:41 +03:30
|
|
|
const std::string &label,
|
|
|
|
glm::vec3 &values,
|
2025-07-06 15:10:34 +03:30
|
|
|
float reset_value,
|
|
|
|
float column_width
|
2025-07-05 13:28:41 +03:30
|
|
|
)
|
|
|
|
{
|
2025-07-06 14:02:50 +03:30
|
|
|
auto &io = ImGui::GetIO();
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
auto *bold_font = io.Fonts->Fonts[0];
|
2025-07-05 13:28:41 +03:30
|
|
|
|
|
|
|
ImGui::Columns(2);
|
2025-07-06 15:10:34 +03:30
|
|
|
ImGui::SetColumnWidth(0, column_width);
|
|
|
|
ImGui::TextUnformatted(label.c_str());
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::NextColumn();
|
|
|
|
|
|
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2 { 0, 0 });
|
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
auto line_height = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
|
|
|
|
auto button_size = ImVec2 { line_height + 3.0f, line_height };
|
2025-07-05 13:28:41 +03:30
|
|
|
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.1f, 0.15f, 1.0f));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.9f, 0.2f, 0.2f, 1.0f));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.8f, 0.1f, 0.15f, 1.0f));
|
2025-07-06 15:10:34 +03:30
|
|
|
ImGui::PushFont(bold_font);
|
|
|
|
if (ImGui::Button("X", button_size))
|
|
|
|
{
|
|
|
|
values.x = reset_value;
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::PopFont();
|
|
|
|
ImGui::PopStyleColor(3);
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::DragFloat("##X", &values.x, 0.1f);
|
|
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.7f, 0.2f, 1.0f));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.8f, 0.3f, 1.0f));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.2f, 0.7f, 0.2f, 1.0f));
|
2025-07-06 15:10:34 +03:30
|
|
|
ImGui::PushFont(bold_font);
|
|
|
|
if (ImGui::Button("Y", button_size))
|
|
|
|
{
|
|
|
|
values.y = reset_value;
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::PopFont();
|
|
|
|
ImGui::PopStyleColor(3);
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::DragFloat("##Y", &values.y, 0.1f);
|
|
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.1f, 0.25f, 0.8f, 1.0f));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.2f, 0.35f, 0.9f, 1.0f));
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.1f, 0.25f, 0.8f, 1.0f));
|
2025-07-06 15:10:34 +03:30
|
|
|
ImGui::PushFont(bold_font);
|
|
|
|
if (ImGui::Button("Z", button_size))
|
|
|
|
{
|
|
|
|
values.z = reset_value;
|
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::PopFont();
|
|
|
|
ImGui::PopStyleColor(3);
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::DragFloat("##Z", &values.z, 0.1f);
|
|
|
|
ImGui::PopItemWidth();
|
|
|
|
|
|
|
|
ImGui::PopStyleVar();
|
|
|
|
ImGui::Columns(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename ComponentType, typename UIFunction>
|
2025-07-05 15:36:53 +03:30
|
|
|
void PropertiesPanel::draw_component(
|
2025-07-05 13:28:41 +03:30
|
|
|
const std::string &name,
|
|
|
|
Entity entity,
|
2025-07-06 15:10:34 +03:30
|
|
|
UIFunction user_interface_function
|
2025-07-05 13:28:41 +03:30
|
|
|
)
|
|
|
|
{
|
2025-07-05 15:36:53 +03:30
|
|
|
if (!entity.has_component<ComponentType>())
|
2025-07-06 15:10:34 +03:30
|
|
|
{
|
2025-07-05 13:28:41 +03:30
|
|
|
return;
|
2025-07-06 15:10:34 +03:30
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 14:02:50 +03:30
|
|
|
auto &component = entity.get_component<ComponentType>();
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
auto available_region = ImGui::GetContentRegionAvail();
|
2025-07-05 13:28:41 +03:30
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
// NOLINTNEXTLINE
|
2025-07-06 14:02:50 +03:30
|
|
|
auto flags = ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth
|
|
|
|
| ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_AllowItemOverlap
|
|
|
|
| ImGuiTreeNodeFlags_FramePadding;
|
2025-07-05 13:28:41 +03:30
|
|
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 4, 4 });
|
2025-07-06 14:02:50 +03:30
|
|
|
auto lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::Separator();
|
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
// NOLINTNEXTLINE
|
2025-07-05 13:28:41 +03:30
|
|
|
if (ImGui::TreeNodeEx((void *)typeid(ComponentType).hash_code(), flags, name.c_str()))
|
|
|
|
{
|
|
|
|
ImGui::PopStyleVar();
|
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
ImGui::SameLine(available_region.x - lineHeight * .5f);
|
2025-07-05 13:28:41 +03:30
|
|
|
if (ImGui::Button("+", { lineHeight, lineHeight }))
|
2025-07-06 15:10:34 +03:30
|
|
|
{
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::OpenPopup("ComponentSettings");
|
2025-07-06 15:10:34 +03:30
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
|
|
|
if (ImGui::BeginPopup("ComponentSettings"))
|
|
|
|
{
|
|
|
|
if (ImGui::Selectable("Remove component"))
|
2025-07-06 15:10:34 +03:30
|
|
|
{
|
2025-07-05 15:36:53 +03:30
|
|
|
entity.remove_component<ComponentType>();
|
2025-07-06 15:10:34 +03:30
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
|
|
|
|
2025-07-06 15:10:34 +03:30
|
|
|
user_interface_function(component);
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::TreePop();
|
|
|
|
}
|
|
|
|
else
|
2025-07-06 15:10:34 +03:30
|
|
|
{
|
2025-07-05 13:28:41 +03:30
|
|
|
ImGui::PopStyleVar();
|
2025-07-06 15:10:34 +03:30
|
|
|
}
|
2025-07-05 13:28:41 +03:30
|
|
|
}
|
|
|
|
|
2025-07-11 00:05:48 +03:30
|
|
|
} // namespace lt
|