312 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <asset_manager/asset_manager.hpp>
 | 
						|
#include <camera/component.hpp>
 | 
						|
#include <ecs/components.hpp>
 | 
						|
#include <imgui.h>
 | 
						|
#include <imgui_internal.h>
 | 
						|
#include <math/trig.hpp>
 | 
						|
#include <mirror/panels/properties.hpp>
 | 
						|
 | 
						|
namespace lt {
 | 
						|
 | 
						|
void PropertiesPanel::on_user_interface_update()
 | 
						|
{
 | 
						|
	ImGui::Begin("Properties");
 | 
						|
 | 
						|
	if (m_entity_context.is_valid())
 | 
						|
	{
 | 
						|
		if (m_entity_context.has_component<TagComponent>())
 | 
						|
		{
 | 
						|
			auto &tagComponent = m_entity_context.get_component<TagComponent>();
 | 
						|
 | 
						|
			auto buffer = std::array<char, 256> {};
 | 
						|
			memset(buffer.data(), 0, buffer.size());
 | 
						|
			strncpy(buffer.data(), tagComponent.tag.c_str(), buffer.size());
 | 
						|
 | 
						|
			if (ImGui::InputText("##Tag", buffer.data(), buffer.size()))
 | 
						|
			{
 | 
						|
				tagComponent.tag = buffer.data();
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		ImGui::SameLine();
 | 
						|
		ImGui::PushItemWidth(-1);
 | 
						|
 | 
						|
		if (ImGui::Button("Add component"))
 | 
						|
		{
 | 
						|
			ImGui::OpenPopup("Components");
 | 
						|
		}
 | 
						|
 | 
						|
		if (ImGui::BeginPopup("Components"))
 | 
						|
		{
 | 
						|
			if (ImGui::Selectable(
 | 
						|
			        "SpriteRenderer",
 | 
						|
			        false,
 | 
						|
			        m_entity_context.has_component<SpriteRendererComponent>() ?
 | 
						|
			            ImGuiSelectableFlags_Disabled :
 | 
						|
			            ImGuiSelectableFlags {}
 | 
						|
			    ))
 | 
						|
			{
 | 
						|
				m_entity_context.add_component<SpriteRendererComponent>(
 | 
						|
				    lt::AssetManager::get_texture("awesomeface")
 | 
						|
				);
 | 
						|
			}
 | 
						|
 | 
						|
			if (ImGui::Selectable(
 | 
						|
			        "Camera",
 | 
						|
			        false,
 | 
						|
			        m_entity_context.has_component<CameraComponent>() ?
 | 
						|
			            ImGuiSelectableFlags_Disabled :
 | 
						|
			            ImGuiSelectableFlags {}
 | 
						|
			    ))
 | 
						|
			{
 | 
						|
				m_entity_context.add_component<CameraComponent>();
 | 
						|
			}
 | 
						|
 | 
						|
			ImGui::EndPopup();
 | 
						|
		}
 | 
						|
		ImGui::PopItemWidth();
 | 
						|
 | 
						|
		draw_component<TransformComponent>(
 | 
						|
		    "Transform Component",
 | 
						|
		    m_entity_context,
 | 
						|
		    [&](auto &transformComponent) {
 | 
						|
			    draw_vec3_control("Translation", transformComponent.translation);
 | 
						|
		    }
 | 
						|
		);
 | 
						|
 | 
						|
		draw_component<SpriteRendererComponent>(
 | 
						|
		    "SpriteRenderer Component",
 | 
						|
		    m_entity_context,
 | 
						|
		    [&](auto &spriteRendererComponent) {
 | 
						|
			    ImGui::ColorEdit4("Color", &spriteRendererComponent.tint[0]);
 | 
						|
		    }
 | 
						|
		);
 | 
						|
 | 
						|
		draw_component<CameraComponent>(
 | 
						|
		    "Camera Component",
 | 
						|
		    m_entity_context,
 | 
						|
		    [&](auto &cameraComponent) {
 | 
						|
			    auto &camera = cameraComponent.camera;
 | 
						|
 | 
						|
			    auto projection_type = camera.get_projection_type();
 | 
						|
			    auto projection_types_str = std::array<const char *, 2> {
 | 
						|
				    "Orthographic",
 | 
						|
				    "Perspective",
 | 
						|
			    };
 | 
						|
 | 
						|
			    if (ImGui::BeginCombo("ProjectionType", projection_types_str[(int)projection_type]))
 | 
						|
			    {
 | 
						|
				    for (auto idx = 0; idx < 2; idx++)
 | 
						|
				    {
 | 
						|
					    const auto is_selected = static_cast<int>(projection_type) == idx;
 | 
						|
					    if (ImGui::Selectable(projection_types_str[idx], is_selected))
 | 
						|
					    {
 | 
						|
						    projection_type = static_cast<SceneCamera::ProjectionType>(idx);
 | 
						|
						    camera.set_projection_type(projection_type);
 | 
						|
					    }
 | 
						|
 | 
						|
					    if (is_selected)
 | 
						|
					    {
 | 
						|
						    ImGui::SetItemDefaultFocus();
 | 
						|
					    }
 | 
						|
				    }
 | 
						|
 | 
						|
				    ImGui::EndCombo();
 | 
						|
			    }
 | 
						|
 | 
						|
			    if (projection_type == SceneCamera::ProjectionType::Orthographic)
 | 
						|
			    {
 | 
						|
				    auto ortho_size = float {};
 | 
						|
				    auto near_plane = float {};
 | 
						|
				    auto far_plane = float {};
 | 
						|
 | 
						|
				    ortho_size = camera.get_orthographic_size();
 | 
						|
				    near_plane = camera.get_orthographic_near_plane();
 | 
						|
				    far_plane = camera.get_orthographic_far_plane();
 | 
						|
 | 
						|
				    if (ImGui::DragFloat("Orthographic Size", &ortho_size))
 | 
						|
				    {
 | 
						|
					    camera.set_orthographic_size(ortho_size);
 | 
						|
				    }
 | 
						|
 | 
						|
				    if (ImGui::DragFloat("Near Plane", &near_plane))
 | 
						|
				    {
 | 
						|
					    camera.set_orthographic_near_plane(near_plane);
 | 
						|
				    }
 | 
						|
 | 
						|
				    if (ImGui::DragFloat("Far Plane", &far_plane))
 | 
						|
				    {
 | 
						|
					    camera.set_orthographic_far_plane(far_plane);
 | 
						|
				    }
 | 
						|
			    }
 | 
						|
 | 
						|
			    else // perspective
 | 
						|
			    {
 | 
						|
				    auto vertical_fov = float {};
 | 
						|
				    auto near_plane = float {};
 | 
						|
				    auto far_plane = float {};
 | 
						|
 | 
						|
				    vertical_fov = math::degrees(camera.get_perspective_vertical_fov());
 | 
						|
				    near_plane = camera.get_perspective_near_plane();
 | 
						|
				    far_plane = camera.get_perspective_far_plane();
 | 
						|
 | 
						|
				    if (ImGui::DragFloat("Vertical FOV", &vertical_fov))
 | 
						|
				    {
 | 
						|
					    camera.set_perspective_vertical_fov(math::radians(vertical_fov));
 | 
						|
				    }
 | 
						|
 | 
						|
				    if (ImGui::DragFloat("Near Plane", &near_plane))
 | 
						|
				    {
 | 
						|
					    camera.set_perspective_near_plane(near_plane);
 | 
						|
				    }
 | 
						|
 | 
						|
				    if (ImGui::DragFloat("Far Plane", &far_plane))
 | 
						|
				    {
 | 
						|
					    camera.set_perspective_far_plane(far_plane);
 | 
						|
				    }
 | 
						|
			    }
 | 
						|
 | 
						|
			    ImGui::Separator();
 | 
						|
		    }
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	ImGui::End();
 | 
						|
}
 | 
						|
 | 
						|
void PropertiesPanel::set_entity_context(const Entity &entity)
 | 
						|
{
 | 
						|
	m_entity_context = entity;
 | 
						|
}
 | 
						|
 | 
						|
void PropertiesPanel::draw_vec3_control(
 | 
						|
    const std::string &label,
 | 
						|
    math::vec3 &values,
 | 
						|
    float reset_value,
 | 
						|
    float column_width
 | 
						|
)
 | 
						|
{
 | 
						|
	auto &io = ImGui::GetIO();
 | 
						|
 | 
						|
	auto *bold_font = io.Fonts->Fonts[0];
 | 
						|
 | 
						|
	ImGui::Columns(2);
 | 
						|
	ImGui::SetColumnWidth(0, column_width);
 | 
						|
	ImGui::TextUnformatted(label.c_str());
 | 
						|
	ImGui::NextColumn();
 | 
						|
 | 
						|
	ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
 | 
						|
	ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2 { 0, 0 });
 | 
						|
 | 
						|
	auto line_height = GImGui->Font->LegacySize + GImGui->Style.FramePadding.y * 2.0f;
 | 
						|
	auto button_size = ImVec2 { line_height + 3.0f, line_height };
 | 
						|
 | 
						|
	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));
 | 
						|
	ImGui::PushFont(bold_font);
 | 
						|
	if (ImGui::Button("X", button_size))
 | 
						|
	{
 | 
						|
		values.x = reset_value;
 | 
						|
	}
 | 
						|
	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));
 | 
						|
	ImGui::PushFont(bold_font);
 | 
						|
	if (ImGui::Button("Y", button_size))
 | 
						|
	{
 | 
						|
		values.y = reset_value;
 | 
						|
	}
 | 
						|
	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));
 | 
						|
	ImGui::PushFont(bold_font);
 | 
						|
	if (ImGui::Button("Z", button_size))
 | 
						|
	{
 | 
						|
		values.z = reset_value;
 | 
						|
	}
 | 
						|
	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>
 | 
						|
void PropertiesPanel::draw_component(
 | 
						|
    const std::string &name,
 | 
						|
    Entity entity,
 | 
						|
    UIFunction user_interface_function
 | 
						|
)
 | 
						|
{
 | 
						|
	if (!entity.has_component<ComponentType>())
 | 
						|
	{
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	auto &component = entity.get_component<ComponentType>();
 | 
						|
 | 
						|
	auto available_region = ImGui::GetContentRegionAvail();
 | 
						|
 | 
						|
	// NOLINTNEXTLINE
 | 
						|
	auto flags = ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth
 | 
						|
	             | ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_AllowItemOverlap
 | 
						|
	             | ImGuiTreeNodeFlags_FramePadding;
 | 
						|
 | 
						|
	ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 4, 4 });
 | 
						|
	auto lineHeight = GImGui->Font->LegacySize + GImGui->Style.FramePadding.y * 2.0f;
 | 
						|
	ImGui::Separator();
 | 
						|
 | 
						|
	// NOLINTNEXTLINE
 | 
						|
	if (ImGui::TreeNodeEx((void *)typeid(ComponentType).hash_code(), flags, name.c_str()))
 | 
						|
	{
 | 
						|
		ImGui::PopStyleVar();
 | 
						|
 | 
						|
		ImGui::SameLine(available_region.x - lineHeight * .5f);
 | 
						|
		if (ImGui::Button("+", { lineHeight, lineHeight }))
 | 
						|
		{
 | 
						|
			ImGui::OpenPopup("ComponentSettings");
 | 
						|
		}
 | 
						|
 | 
						|
		if (ImGui::BeginPopup("ComponentSettings"))
 | 
						|
		{
 | 
						|
			if (ImGui::Selectable("Remove component"))
 | 
						|
			{
 | 
						|
				entity.remove_component<ComponentType>();
 | 
						|
			}
 | 
						|
 | 
						|
			ImGui::EndPopup();
 | 
						|
		}
 | 
						|
 | 
						|
		user_interface_function(component);
 | 
						|
		ImGui::TreePop();
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		ImGui::PopStyleVar();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
} // namespace lt
 |