4#include "imgui_widgets/utils.h"
32#include <imgui/imgui.h>
33#include <imgui/imgui_internal.h>
34#include <imgui_widgets/gizmo.h>
35#include <imgui_widgets/imcoolbar.h>
50void apply_material_preview(
rtti::context& ctx, entt::handle
entity,
const std::string& material_path,
53void manipulation_gizmos(
bool& gizmo_at_center,
bool& was_using_gizmo, entt::handle
center, entt::handle editor_camera, editing_manager& em);
54void handle_camera_movement(entt::handle camera, math::vec3& move_dir,
float&
acceleration,
bool& is_dragging);
57struct material_preview_state
66static material_preview_state g_preview_state;
69auto check_material_drag(std::string& out_material_path) ->
bool
73 auto payload = ImGui::GetDragDropPayload();
74 if(payload && payload->IsDataType(
type.c_str()))
78 out_material_path = std::string(
reinterpret_cast<const char*
>(payload->Data), std::size_t(payload->DataSize));
88void handle_material_preview(
rtti::context& ctx,
const camera_component& camera_comp,
const std::string& material_path)
90 auto& pick_manager = ctx.
get_cached<picking_manager>();
93 if(g_preview_state.current_drag_material != material_path)
96 if(g_preview_state.is_previewing && g_preview_state.last_preview_entity)
98 restore_original_materials(g_preview_state.last_preview_entity, g_preview_state.original_materials);
102 g_preview_state.current_drag_material = material_path;
103 g_preview_state.is_previewing =
false;
108 auto cursor_pos = ImGui::GetMousePos();
109 pick_manager.query_pick(
110 math::vec2{cursor_pos.x, cursor_pos.y},
111 camera_comp.get_camera(),
112 [&ctx, material_path](entt::handle
entity,
const math::vec2& screen_pos) {
113 apply_material_preview(ctx,
entity, material_path, g_preview_state.last_preview_entity,
114 g_preview_state.original_materials, g_preview_state.is_previewing);
120void handle_material_drop(
rtti::context& ctx,
const camera_component& camera_comp,
const std::string& material_path)
122 auto cursor_pos = ImGui::GetMousePos();
123 auto& pick_manager = ctx.
get_cached<picking_manager>();
128 auto material_asset = am.get_asset<
material>(material_path);
132 pick_manager.query_pick(
133 math::vec2{cursor_pos.x, cursor_pos.y},
134 camera_comp.get_camera(),
135 [material_asset, &em](entt::handle
entity,
const math::vec2& screen_pos) {
140 auto& model_comp =
entity.get<model_component>();
141 const auto& current_model = model_comp.get_model();
142 auto old_materials = current_model.get_materials();
144 em.push_undo_stack_enabled(
true);
147 em.queue_action<entity_set_materials_action_t>({},
entity, old_materials, material_asset);
149 em.pop_undo_stack_enabled();
153 APPLOG_WARNING(
"Cannot apply material to entity without model_component");
160void handle_mesh_drop(
rtti::context& ctx,
const camera_component& camera_comp,
const std::string& mesh_path)
162 auto cursor_pos = ImGui::GetMousePos();
165 em.queue_action(
"Drop Mesh",
166 [&ctx, camera = camera_comp.get_camera(), mesh_path, cursor_pos]()
168 auto& em = ctx.get_cached<editing_manager>();
169 auto target_scene = em.get_active_scene(ctx);
171 auto object = defaults::create_mesh_entity_at(ctx,
175 math::vec2{cursor_pos.x, cursor_pos.y});
181void handle_prefab_drop(
rtti::context& ctx,
const camera_component& camera_comp,
const std::string& prefab_path)
183 auto cursor_pos = ImGui::GetMousePos();
186 em.queue_action(
"Drop Prefab",
187 [&ctx, camera = camera_comp.get_camera(), prefab_path, cursor_pos]()
189 auto& em = ctx.get_cached<editing_manager>();
190 auto target_scene = em.get_active_scene(ctx);
192 auto object = defaults::create_prefab_at(ctx,
196 math::vec2{cursor_pos.x, cursor_pos.y});
202void reset_preview_state()
204 if(g_preview_state.is_previewing && g_preview_state.last_preview_entity)
206 restore_original_materials(g_preview_state.last_preview_entity, g_preview_state.original_materials);
207 g_preview_state.is_previewing =
false;
208 g_preview_state.last_preview_entity = {};
209 g_preview_state.original_materials.clear();
210 g_preview_state.current_drag_material.clear();
218auto calculate_movement_speed(
float base_speed,
bool speed_boost_active,
float multiplier) ->
float
220 float movement_speed = base_speed;
221 if(speed_boost_active)
223 movement_speed *= multiplier;
225 return movement_speed;
228void handle_middle_mouse_panning(entt::handle camera,
float movement_speed,
float dt)
230 if(!ImGui::IsMouseDown(ImGuiMouseButton_Middle))
235 auto delta_move = ImGui::GetIO().MouseDelta;
236 auto&
transform = camera.get<transform_component>();
238 if(delta_move.x != 0)
240 transform.move_by_local({-1 * delta_move.x * movement_speed * dt, 0.0f, 0.0f});
242 if(delta_move.y != 0)
244 transform.move_by_local({0.0f, delta_move.y * movement_speed * dt, 0.0f});
248auto collect_movement_input(
float& max_hold,
bool& is_dragging) -> math::vec3
250 math::vec3 movement_input{0.0f, 0.0f, 0.0f};
252 auto is_key_down = [&](ImGuiKey
k) ->
bool
254 bool down = ImGui::IsKeyDown(k);
257 auto data = ImGui::GetKeyData(ImGui::GetCurrentContext(), k);
258 max_hold = std::max(max_hold, data->DownDuration);
265 float move_speed = 4.0f;
266 if(is_key_down(shortcuts::camera_forward))
268 movement_input.z += move_speed;
270 if(is_key_down(shortcuts::camera_backward))
272 movement_input.z -= move_speed;
274 if(is_key_down(shortcuts::camera_right))
276 movement_input.x += move_speed;
278 if(is_key_down(shortcuts::camera_left))
280 movement_input.x -= move_speed;
286 auto delta_wheel = ImGui::GetIO().MouseWheel;
289 movement_input.z += 15.0f * delta_wheel;
292 return movement_input;
295auto handle_mouse_rotation(entt::handle camera,
float rotation_speed,
bool is_dragging)->
bool
302 auto delta_move = ImGui::GetIO().MouseDelta;
303 auto&
transform = camera.get<transform_component>();
305 if(delta_move.x != 0.0f || delta_move.y != 0.0f)
307 float dx = delta_move.x * rotation_speed;
308 float dy = delta_move.y * rotation_speed;
310 transform.rotate_by_euler_global({0.0f, dx, 0.0f});
311 transform.rotate_by_euler_local({dy, 0.0f, 0.0f});
317void update_movement_acceleration(math::vec3& move_dir,
float& acceleration,
const math::vec3&
input,
bool any_input)
321 if(acceleration < 0.1f)
327 move_dir.x =
input.x;
328 move_dir.z =
input.z;
330 else if(acceleration > 0.0001f)
336void apply_movement(entt::handle camera,
337 const math::vec3& move_dir,
338 float movement_speed,
344 if(acceleration <= 0.0001f)
349 auto&
transform = camera.get<transform_component>();
351 if(!math::any(math::epsilonNotEqual(move_dir, math::vec3(0.0f, 0.0f, 0.0f), math::epsilon<float>())))
356 float adjusted_dt = dt;
357 if(math::epsilonNotEqual(move_dir.x, 0.0f, math::epsilon<float>()) ||
358 math::epsilonNotEqual(move_dir.z, 0.0f, math::epsilon<float>()))
360 adjusted_dt += max_hold * hold_speed;
363 auto length = math::length(move_dir);
364 transform.move_by_local(math::normalize(move_dir) * length * movement_speed * adjusted_dt * acceleration);
370void handle_camera_movement(entt::handle camera, math::vec3& move_dir,
float& acceleration,
bool& is_dragging)
372 if(!ImGui::IsWindowFocused())
377 if(!ImGui::IsWindowHovered() && !is_dragging)
383 constexpr float base_movement_speed = 2.0f;
384 constexpr float rotation_speed = 0.1f;
385 constexpr float speed_multiplier = 5.0f;
386 constexpr float hold_speed = 0.1f;
387 constexpr float fixed_dt = 0.0166f;
389 bool speed_boost_active = ImGui::IsKeyDown(shortcuts::modifier_camera_speed_boost);
390 float movement_speed = calculate_movement_speed(base_movement_speed, speed_boost_active, speed_multiplier);
393 handle_middle_mouse_panning(camera, movement_speed, fixed_dt);
397 is_dragging = ImGui::IsMouseDown(ImGuiMouseButton_Right);
401 ImGui::WrapMousePos();
402 if(ImGui::IsWindowHovered())
404 ImGui::SetMouseCursor(ImGuiMouseCursor_Cross);
409 float max_hold = 0.0f;
410 math::vec3 movement_input = collect_movement_input(max_hold, is_dragging);
411 bool any_input = math::any(math::epsilonNotEqual(movement_input, math::vec3(0.0f), math::epsilon<float>()));
414 bool any_rotation = handle_mouse_rotation(camera, rotation_speed, is_dragging);
417 update_movement_acceleration(move_dir, acceleration, movement_input, any_input);
419 if(any_input || any_rotation)
424 if(acceleration > 0.0001f)
427 apply_movement(camera, move_dir, movement_speed, acceleration, 0.0f, hold_speed, fixed_dt);
435void setup_gizmo_context(
const camera_component& camera_comp)
437 auto p = ImGui::GetItemRectMin();
438 auto s = ImGui::GetItemRectSize();
439 const auto& camera = camera_comp.get_camera();
441 ImGuizmo::SetDrawlist(ImGui::GetWindowDrawList());
442 ImGuizmo::SetRect(
p.x,
p.y,
s.x,
s.y);
443 ImGuizmo::SetOrthographic(camera.get_projection_mode() == projection_mode::orthographic);
446void handle_view_manipulator(entt::handle editor_camera,
const camera_component& camera_comp)
448 auto p = ImGui::GetItemRectMin();
449 auto s = ImGui::GetItemRectSize();
450 const auto& camera = camera_comp.get_camera();
451 auto& camera_trans = editor_camera.get<transform_component>();
453 auto view = camera.get_view().get_matrix();
454 static const ImVec2 view_gizmo_sz(100.0f, 100.0f);
456 ImGuizmo::ViewManipulate(value_ptr(view),
458 p + ImVec2(
s.x - view_gizmo_sz.x, 0.0f),
460 ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)));
466void handle_gizmo_shortcuts(editing_manager& em)
468 if(ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::IsAnyItemActive() || ImGuizmo::IsUsing())
473 if(ImGui::IsKeyPressed(shortcuts::universal_tool))
475 em.operation = ImGuizmo::OPERATION::UNIVERSAL;
477 if(ImGui::IsKeyPressed(shortcuts::move_tool))
479 em.operation = ImGuizmo::OPERATION::TRANSLATE;
481 if(ImGui::IsKeyPressed(shortcuts::rotate_tool))
483 em.operation = ImGuizmo::OPERATION::ROTATE;
485 if(ImGui::IsKeyPressed(shortcuts::scale_tool))
487 em.operation = ImGuizmo::OPERATION::SCALE;
489 if(ImGui::IsKeyPressed(shortcuts::bounds_tool))
491 em.operation = ImGuizmo::OPERATION::BOUNDS;
495void setup_snap_data(editing_manager& em,
float*& snap,
float*& bounds_snap,
float bounds_snap_data[3])
498 bounds_snap =
nullptr;
500 if(!ImGui::IsKeyDown(shortcuts::modifier_snapping))
505 bounds_snap = bounds_snap_data;
507 if(em.operation == ImGuizmo::OPERATION::TRANSLATE)
509 snap = &em.snap_data.translation_snap[0];
511 else if(em.operation == ImGuizmo::OPERATION::ROTATE)
513 snap = &em.snap_data.rotation_degree_snap;
515 else if(em.operation == ImGuizmo::OPERATION::SCALE)
517 snap = &em.snap_data.scale_snap;
521auto calculate_center_pivot(
const std::vector<entt::handle*>& selections) -> math::vec3
523 math::vec3 pivot{0.0f, 0.0f, 0.0f};
526 for(
const auto& sel : selections)
530 auto& sel_transform_comp = sel->get<transform_component>();
531 pivot += sel_transform_comp.get_position_global();
538 pivot /=
static_cast<float>(points);
544void setup_gizmo_pivot(
bool gizmo_at_center,
546 const std::vector<entt::handle*>& selections,
547 entt::handle active_selection)
549 auto& center_transform_comp =
center.get<transform_component>();
550 auto& transform_comp = active_selection.get<transform_component>();
552 auto trans_global = transform_comp.get_transform_global();
553 center_transform_comp.set_transform_global(trans_global);
557 math::vec3 pivot = calculate_center_pivot(selections);
558 center_transform_comp.set_position_global(pivot);
562auto handle_text_component_bounds_manipulation(entt::handle active_selection,
563 const camera_component& camera_comp,
566 float bounds_snap_data[3],
567 float* bounds_snap) ->
bool
569 auto text_comp = active_selection.try_get<text_component>();
575 auto area = text_comp->get_area();
581 auto& transform_comp = active_selection.get<transform_component>();
582 const auto& camera = camera_comp.get_camera();
586 math::vec3 initial_position = transform_comp.get_position_global();
599 model_tr.
set_position(transform_comp.get_position_global());
600 model_tr.
set_rotation(transform_comp.get_rotation_global());
601 model_tr.
set_scale(math::vec3(area.width, area.height, 1.0f));
603 math::mat4 output = model_tr;
605 int movetype = ImGuizmo::Manipulate(camera.get_view(),
606 camera.get_projection(),
609 math::value_ptr(output),
615 if(movetype != ImGuizmo::MT_NONE)
623 math::vec3 new_position = trans;
626 auto composite_action = std::make_shared<composite_action_t>();
629 composite_action->add_sub_action(std::make_shared<entity_set_text_bounds_action_t>(
630 active_selection, initial_area, new_area));
633 composite_action->add_sub_action(std::make_shared<transform_move_global_action_t>(
634 active_selection, initial_position, new_position));
637 em.push_undo_stack_enabled(
true);
638 em.do_action(
"Text Bounds Manipulation", composite_action);
639 em.pop_undo_stack_enabled();
647void handle_inverse_kinematics(entt::handle selection, entt::handle center, editing_manager& em)
649 if(ImGui::IsAnyItemActive())
654 auto& center_transform_comp =
center.get<transform_component>();
656 if(ImGui::IsKeyDown(shortcuts::ik_ccd))
658 ik_set_position_ccd(selection, center_transform_comp.get_position_global(), em.ik_data.num_nodes);
660 else if(ImGui::IsKeyDown(shortcuts::ik_fabrik))
666void apply_transform_delta_to_selections(
const std::vector<entt::handle>& top_level_selections,
667 const std::vector<entt::handle>& original_parents,
668 const math::mat4& center_delta)
670 for(
size_t i = 0;
i < top_level_selections.size(); ++
i)
672 auto& sel = top_level_selections[
i];
678 auto& sel_transform_comp = sel.get<transform_component>();
681 math::mat4 old_global = sel_transform_comp.get_transform_global();
684 math::mat4 new_global = center_delta * old_global;
688 entt::handle original_parent = original_parents[
i];
691 const auto& parent_transform = original_parent.get<transform_component>();
692 math::mat4 parent_global = parent_transform.get_transform_global();
693 math::mat4 parent_global_inv = glm::inverse(parent_global);
695 math::mat4 new_local = parent_global_inv * new_global;
706auto handle_standard_gizmo_manipulation(entt::handle active_selection,
708 const camera_component& camera_comp,
712 auto& center_transform_comp =
center.get<transform_component>();
713 const auto& camera = camera_comp.get_camera();
715 math::mat4 output = center_transform_comp.get_transform_global();
716 math::mat4 output_delta;
718 ImGuizmo::AllowAxisFlip(
false);
720 int movetype = ImGuizmo::Manipulate(camera.get_view(),
721 camera.get_projection(),
724 math::value_ptr(output),
725 math::value_ptr(output_delta),
730 if(movetype != ImGuizmo::MT_NONE)
734 auto perspective = center_transform_comp.get_perspective_local();
735 auto skew = center_transform_comp.get_skew_local();
737 if(ImGuizmo::IsScaleType(movetype))
739 center_transform_comp.scale_by_local(delta.
get_scale());
741 if(ImGuizmo::IsRotateType(movetype))
743 center_transform_comp.rotate_by_global(delta.
get_rotation());
745 if(ImGuizmo::IsTranslateType(movetype))
750 center_transform_comp.set_skew_local(skew);
751 center_transform_comp.set_perspective_local(perspective);
757void manipulation_gizmos(
bool& gizmo_at_center,
bool& was_using_gizmo, entt::handle center, entt::handle editor_camera, editing_manager& em)
759 auto& camera_trans = editor_camera.get<transform_component>();
760 auto& camera_comp = editor_camera.get<camera_component>();
762 setup_gizmo_context(camera_comp);
763 handle_view_manipulator(editor_camera, camera_comp);
764 handle_gizmo_shortcuts(em);
766 auto active_sel = em.try_get_active_selection_as<entt::handle>();
767 if(!active_sel || !active_sel->valid() || !active_sel->all_of<transform_component>())
772 float bounds_snap_data[3] = {0.1f, 0.1f, 0.0f};
773 float* snap =
nullptr;
774 float* bounds_snap =
nullptr;
776 setup_snap_data(em, snap, bounds_snap, bounds_snap_data);
778 auto selections = em.try_get_selections_as<entt::handle>();
779 setup_gizmo_pivot(gizmo_at_center, center, selections, *active_sel);
782 auto& center_transform_comp =
center.get<transform_component>();
783 math::mat4 center_initial_global = center_transform_comp.get_transform_global();
786 std::vector<entt::handle> selection_values;
787 selection_values.reserve(selections.size());
788 for(
const auto& sel : selections)
792 selection_values.emplace_back(*sel);
796 auto top_level_selections = transform_component::get_top_level_entities(selection_values);
798 std::vector<entt::handle> original_parents;
799 std::vector<math::transform> original_transforms;
800 original_parents.reserve(top_level_selections.size());
801 original_transforms.reserve(top_level_selections.size());
804 for(
const auto& sel : top_level_selections)
808 auto& sel_transform_comp = sel.get<transform_component>();
809 original_parents.emplace_back(sel_transform_comp.get_parent());
810 original_transforms.emplace_back(sel_transform_comp.get_transform_local());
814 bool bounds_changed =
false;
816 if(em.operation != ImGuizmo::ROTATE && em.operation != ImGuizmo::SCALE && top_level_selections.size() == 1)
818 bounds_changed = handle_text_component_bounds_manipulation(*active_sel,
826 int movetype = ImGuizmo::MT_NONE;
828 if(em.operation != ImGuizmo::BOUNDS)
830 movetype = handle_standard_gizmo_manipulation(*active_sel, center, camera_comp, em, snap);
834 math::mat4 center_final_global = center_transform_comp.get_transform_global();
835 math::mat4 center_delta = center_final_global * glm::inverse(center_initial_global);
838 auto batch_action = std::make_shared<composite_action_t>();
840 for(
size_t i = 0;
i < top_level_selections.size(); ++
i)
842 auto& sel = top_level_selections[
i];
845 handle_inverse_kinematics(sel, center, em);
846 if(ImGui::IsKeyDown(shortcuts::ik_ccd) || ImGui::IsKeyDown(shortcuts::ik_fabrik))
853 auto& sel_transform_comp = sel.get<transform_component>();
854 math::mat4 old_global = sel_transform_comp.get_transform_global();
855 math::mat4 new_global = center_delta * old_global;
858 entt::handle original_parent = original_parents[
i];
863 const auto& parent_transform = original_parent.get<transform_component>();
864 math::mat4 parent_global = parent_transform.get_transform_global();
865 math::mat4 parent_global_inv = glm::inverse(parent_global);
866 math::mat4 new_local = parent_global_inv * new_global;
876 sel_transform_comp.set_transform_local(new_local_transform);
879 if(movetype != ImGuizmo::MT_NONE)
883 bool position = ImGuizmo::IsTranslateType(movetype);
884 bool rotation = ImGuizmo::IsRotateType(movetype);
885 bool scale = ImGuizmo::IsScaleType(movetype);
888 if(top_level_selections.size() > 1)
899 auto composite_action = std::make_shared<composite_action_t>();
904 composite_action->add_sub_action(std::make_shared<transform_move_action_t>(
906 original_transforms[i].get_position(),
911 composite_action->add_sub_action(std::make_shared<transform_rotate_action_t>(
913 original_transforms[i].get_rotation(),
918 composite_action->add_sub_action(std::make_shared<transform_scale_action_t>(
920 original_transforms[i].get_scale(),
925 composite_action->add_sub_action(std::make_shared<transform_skew_action_t>(
927 original_transforms[i].get_skew(),
932 batch_action->add_sub_action(composite_action);
939 if(batch_action->sub_actions.size() > 0)
941 em.push_undo_stack_enabled(
true);
942 em.do_action(
"Transform Manipulation", batch_action);
943 em.pop_undo_stack_enabled();
948void process_drag_drop_target(
rtti::context& ctx,
const camera_component& camera_comp)
950 if(!ImGui::BeginDragDropTarget())
953 reset_preview_state();
958 if(ImGui::IsDragDropPayloadBeingAccepted())
960 ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
963 std::string material_path;
964 if(check_material_drag(material_path))
966 handle_material_preview(ctx, camera_comp, material_path);
971 ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
972 reset_preview_state();
978 auto payload = ImGui::AcceptDragDropPayload(
type.c_str());
979 if(payload !=
nullptr)
981 std::string absolute_path(
reinterpret_cast<const char*
>(payload->Data), std::size_t(payload->DataSize));
985 reset_preview_state();
987 handle_material_drop(ctx, camera_comp, key);
994 auto payload = ImGui::AcceptDragDropPayload(
type.c_str());
995 if(payload !=
nullptr)
998 reset_preview_state();
1000 std::string absolute_path(
reinterpret_cast<const char*
>(payload->Data), std::size_t(payload->DataSize));
1003 handle_mesh_drop(ctx, camera_comp, key);
1010 auto payload = ImGui::AcceptDragDropPayload(
type.c_str());
1011 if(payload !=
nullptr)
1014 reset_preview_state();
1016 std::string absolute_path(
reinterpret_cast<const char*
>(payload->Data), std::size_t(payload->DataSize));
1019 handle_prefab_drop(ctx, camera_comp, key);
1023 ImGui::EndDragDropTarget();
1032 auto& model_comp =
entity.get<model_component>();
1033 class model model_copy = model_comp.get_model();
1036 for(
size_t i = 0;
i <
original_materials.size() && i < model_copy.get_materials().size(); ++i)
1042 model_comp.set_model(model_copy);
1046void apply_material_preview(
rtti::context& ctx, entt::handle
entity,
const std::string& material_path,
1076 auto material_asset = am.get_asset<
material>(material_path);
1079 auto& model_comp =
entity.get<model_component>();
1080 auto& model = model_comp.get_model();
1086 for(
const auto& mat : model.get_materials())
1093 class model model_copy = model;
1094 for(
size_t i = 0;
i < model_copy.get_materials().
size(); ++
i)
1096 model_copy.set_material(material_asset, i);
1098 model_comp.set_model(model_copy);
1141 if(!ImGui::IsAnyItemHovered() && !ImGuizmo::IsOver() && ImGui::IsWindowHovered())
1143 if(ImGui::IsMouseClicked(ImGuiMouseButton_Left))
1145 drag_start_pos_ = ImGui::GetMousePos();
1148 if(ImGui::IsMouseDragging(ImGuiMouseButton_Left))
1151 if(!is_drag_selecting_)
1153 is_drag_selecting_ =
true;
1160 if(is_drag_selecting_)
1162 drag_current_pos_ = ImGui::GetMousePos();
1165 if(ImGui::IsMouseReleased(ImGuiMouseButton_Left))
1167 auto& pick_manager = ctx.
get_cached<picking_manager>();
1168 pick_manager.cancel_pick();
1169 is_drag_selecting_ =
false;
1174void scene_panel::draw_drag_selection_rect(
const ImVec2& start_pos,
const ImVec2& current_pos)
1176 if(start_pos.x == current_pos.x && start_pos.y == current_pos.y)
1181 ImDrawList* draw_list = ImGui::GetWindowDrawList();
1184 ImVec2 min_pos(std::min(start_pos.x, current_pos.x), std::min(start_pos.y, current_pos.y));
1185 ImVec2 max_pos(std::max(start_pos.x, current_pos.x), std::max(start_pos.y, current_pos.y));
1188 ImU32 rect_color = ImGui::GetColorU32(ImVec4(0.2f, 0.6f, 1.0f, 0.3f));
1189 ImU32 border_color = ImGui::GetColorU32(ImVec4(0.2f, 0.6f, 1.0f, 0.8f));
1192 draw_list->AddRectFilled(min_pos, max_pos, rect_color);
1195 draw_list->AddRect(min_pos, max_pos, border_color, 0.0f, 0, 2.0f);
1199void scene_panel::handle_prefab_mode_changes(
rtti::context& ctx)
1201 auto& em = ctx.
get_cached<editing_manager>();
1205 if(is_prefab_mode && !was_prefab_mode_)
1210 else if(!is_prefab_mode && was_prefab_mode_)
1219 was_prefab_mode_ = is_prefab_mode;
1224 handle_prefab_mode_changes(ctx);
1265 path.render_scene(
handle, camera_comp, *target_scene, dt);
1276 draw_scene(ctx, dt);
1283 if(ImGui::Begin(
name,
nullptr, ImGuiWindowFlags_MenuBar))
1285 is_focused_ = ImGui::IsWindowFocused();
1298 entt::handle camera_entity;
1299 panel_scene_.registry->view<
camera_component>().each([&](
auto e,
auto&& camera_comp)
1301 camera_entity = panel_scene_.create_handle(e);
1303 return camera_entity;
1308 entt::handle center_entity;
1310 auto view = panel_scene_.registry->view<
root_component>(entt::exclude<camera_component>);
1311 view.each([&](
auto e,
auto&& comp)
1313 center_entity = panel_scene_.create_handle(e);
1315 return center_entity;
1320 is_visible_ = visible;
1330 return auto_save_prefab_;
1338void scene_panel::draw_prefab_mode_header(
rtti::context& ctx)
1347 ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
1354 ImGui::PopStyleColor();
1359 ImGui::Text(
"Editing Prefab: %s", fs::path(em.
edited_prefab.id()).filename().string().c_str());
1362 if(ImGui::Button(
"Save"))
1368 ImGui::Checkbox(
"Auto Save", &auto_save_prefab_);
1369 ImGui::SetItemTooltipEx(
"%s",
"Automatically save changes when exiting prefab mode");
1375void scene_panel::draw_transform_tools(editing_manager& em)
1377 ImGui::SetNextWindowViewportToCurrent();
1379 if(ImGui::MenuItem(
ICON_MDI_CURSOR_MOVE,
nullptr, em.operation == ImGuizmo::OPERATION::TRANSLATE))
1381 em.operation = ImGuizmo::OPERATION::TRANSLATE;
1383 ImGui::SetItemTooltipEx(
"%s",
"Translate Tool");
1384 ImGui::SetNextWindowViewportToCurrent();
1388 em.operation = ImGuizmo::OPERATION::ROTATE;
1390 ImGui::SetItemTooltipEx(
"%s",
"Rotate Tool");
1391 ImGui::SetNextWindowViewportToCurrent();
1395 em.operation = ImGuizmo::OPERATION::SCALE;
1396 em.mode = ImGuizmo::MODE::LOCAL;
1398 ImGui::SetItemTooltipEx(
"%s",
"Scale Tool");
1399 ImGui::SetNextWindowViewportToCurrent();
1401 if(ImGui::MenuItem(
ICON_MDI_MOVE_RESIZE,
nullptr, em.operation == ImGuizmo::OPERATION::UNIVERSAL))
1403 em.operation = ImGuizmo::OPERATION::UNIVERSAL;
1404 em.mode = ImGuizmo::MODE::LOCAL;
1406 ImGui::SetItemTooltipEx(
"%s",
"Transform Tool");
1409void scene_panel::draw_gizmo_pivot_mode_menu(
bool& gizmo_at_center)
1413 ImGui::SetNextWindowViewportToCurrent();
1415 if(ImGui::BeginMenu(
icon))
1419 gizmo_at_center =
true;
1421 ImGui::SetItemTooltipEx(
"%s",
1422 "The tool handle is placed at the center\n"
1423 "of the selections' pivots.");
1427 gizmo_at_center =
false;
1429 ImGui::SetItemTooltipEx(
"%s",
1430 "The tool handle is placed at the\n"
1431 "active object's pivot point.");
1435 ImGui::SetItemTooltipEx(
"%s",
"Tool's Handle Position");
1438void scene_panel::draw_coordinate_system_menu(editing_manager& em)
1442 ImGui::SetNextWindowViewportToCurrent();
1444 if(ImGui::BeginMenu(
icon))
1448 em.mode == ImGuizmo::MODE::LOCAL))
1450 em.mode = ImGuizmo::MODE::LOCAL;
1452 ImGui::SetItemTooltipEx(
"%s",
"Local Coordinate System");
1454 if(ImGui::MenuItem(
ICON_MDI_WEB "Global",
nullptr, em.mode == ImGuizmo::MODE::WORLD))
1456 em.mode = ImGuizmo::MODE::WORLD;
1458 ImGui::SetItemTooltipEx(
"%s",
"Global Coordinate System");
1462 ImGui::SetItemTooltipEx(
"%s",
"Tool's Coordinate System");
1465void scene_panel::draw_grid_settings_menu(editing_manager& em)
1467 ImGui::SetNextWindowViewportToCurrent();
1471 em.show_grid = !em.show_grid;
1473 ImGui::SetItemTooltipEx(
"%s",
"Show/Hide Grid");
1474 ImGui::SetNextWindowViewportToCurrent();
1478 ImGui::PushItemWidth(100.0f);
1480 ImGui::TextUnformatted(
"Grid Visual");
1481 ImGui::LabelText(
"Plane",
"%s",
"X Z");
1482 ImGui::SliderFloat(
"Opacity", &em.grid_data.opacity, 0.0f, 1.0f);
1483 ImGui::Checkbox(
"Depth Aware", &em.grid_data.depth_aware);
1484 ImGui::SetItemTooltipEx(
"%s",
"Grid is depth aware.");
1486 ImGui::PopItemWidth();
1490 ImGui::SetItemTooltipEx(
"%s",
"Grid Properties");
1493void scene_panel::draw_gizmos_settings_menu(editing_manager& em)
1495 ImGui::SetNextWindowViewportToCurrent();
1499 em.show_icon_gizmos = !em.show_icon_gizmos;
1501 ImGui::SetItemTooltipEx(
"%s",
"Show/Hide Gizmos");
1502 ImGui::PushID(
"Billboard Gizmos");
1503 ImGui::SetNextWindowViewportToCurrent();
1507 ImGui::PushItemWidth(100.0f);
1509 ImGui::TextUnformatted(
"Gizmos Visual");
1510 ImGui::SliderFloat(
"Opacity", &em.billboard_data.opacity, 0.0f, 1.0f);
1511 ImGui::SliderFloat(
"Size", &em.billboard_data.size, 0.1f, 1.0f);
1513 ImGui::Checkbox(
"Depth Aware", &em.billboard_data.depth_aware);
1514 ImGui::SetItemTooltipEx(
"%s",
"Gizmos are depth aware.");
1516 ImGui::PopItemWidth();
1520 ImGui::SetItemTooltipEx(
"%s",
"Gizmos Properties");
1524void scene_panel::draw_visualization_menu()
1526 ImGui::SetNextWindowViewportToCurrent();
1530 ImGui::RadioButton(
"Full", &visualize_passes_, -1);
1531 ImGui::RadioButton(
"Base Color", &visualize_passes_, 0);
1532 ImGui::RadioButton(
"Diffuse Color", &visualize_passes_, 1);
1533 ImGui::RadioButton(
"Specular Color", &visualize_passes_, 2);
1534 ImGui::RadioButton(
"Indirect Specular Color", &visualize_passes_, 3);
1535 ImGui::RadioButton(
"Ambient Occlusion", &visualize_passes_, 4);
1536 ImGui::RadioButton(
"Normals (World Space)", &visualize_passes_, 5);
1537 ImGui::RadioButton(
"Roughness", &visualize_passes_, 6);
1538 ImGui::RadioButton(
"Metalness", &visualize_passes_, 7);
1539 ImGui::RadioButton(
"Emissive Color", &visualize_passes_, 8);
1540 ImGui::RadioButton(
"Subsurface Color", &visualize_passes_, 9);
1541 ImGui::RadioButton(
"Depth", &visualize_passes_, 10);
1545 ImGui::SetItemTooltipEx(
"%s",
"Visualize Render Passes");
1548void scene_panel::draw_snapping_menu(editing_manager& em)
1550 ImGui::SetNextWindowViewportToCurrent();
1554 ImGui::PushItemWidth(200.0f);
1555 ImGui::DragVecN(
"Translation Snap",
1556 ImGuiDataType_Float,
1557 math::value_ptr(em.snap_data.translation_snap),
1558 em.snap_data.translation_snap.length(),
1564 ImGui::DragFloat(
"Rotation Degree Snap", &em.snap_data.rotation_degree_snap);
1565 ImGui::DragFloat(
"Scale Snap", &em.snap_data.scale_snap);
1566 ImGui::PopItemWidth();
1569 ImGui::SetItemTooltipEx(
"%s",
"Snapping Properties");
1572void scene_panel::draw_inverse_kinematics_menu(editing_manager& em)
1574 ImGui::SetNextWindowViewportToCurrent();
1578 ImGui::PushItemWidth(200.0f);
1579 ImGui::InputInt(
"Inverse Kinematic Nodes", &em.ik_data.num_nodes);
1581 ImGui::PopItemWidth();
1584 ImGui::SetItemTooltipEx(
"%s",
"Inverse Kinematic Properties");
1587void scene_panel::draw_camera_settings_menu(
rtti::context& ctx)
1591 ImGui::SetNextWindowSizeConstraints({}, {400.0f, ImGui::GetContentRegionAvail().y});
1592 ImGui::SetNextWindowViewportToCurrent();
1596 if(ImGui::Button(
"Scene Camera"))
1603 ImGui::SetItemTooltipEx(
"%s",
"Reset the Scene camera.");
1612 ImGui::SetItemTooltipEx(
"%s",
"Settings for the Scene view camera.");
1615void scene_panel::handle_viewport_interaction(
rtti::context& ctx,
const camera& camera, editing_manager& em)
1617 bool is_using = ImGuizmo::IsUsing();
1618 bool is_over = ImGuizmo::IsOver();
1619 bool is_entity = em.is_selected_type<entt::handle>();
1622 handle_drag_selection(ctx, camera, em);
1626 auto& pick_manager = ctx.
get_cached<picking_manager>();
1629 math::vec2 area = {bounds.second.x - bounds.first.x, bounds.second.y - bounds.first.y};
1632 bounds.first.x + area.x * 0.5f,
1633 bounds.first.y + area.y * 0.5f
1636 pick_manager.request_pick(camera, em.get_select_mode(),
center, area);
1640 if(ImGui::IsItemClicked(ImGuiMouseButton_Left) && !is_using && !is_drag_selecting_)
1642 bool is_over_active_gizmo = is_over && is_entity;
1643 if(!is_over_active_gizmo)
1645 ImGui::SetWindowFocus();
1646 auto& pick_manager = ctx.
get_cached<picking_manager>();
1647 auto pos = ImGui::GetMousePos();
1649 pick_manager.request_pick(camera, em.get_select_mode(), {pos.x, pos.y});
1653 if(ImGui::IsItemClicked(ImGuiMouseButton_Middle) || ImGui::IsItemClicked(ImGuiMouseButton_Right))
1655 ImGui::SetWindowFocus();
1656 ImGui::SetMouseCursor(ImGuiMouseCursor_None);
1659 if(ImGui::IsItemReleased(ImGuiMouseButton_Middle) || ImGui::IsItemReleased(ImGuiMouseButton_Right))
1661 ImGui::SetMouseCursor(ImGuiMouseCursor_Arrow);
1665void scene_panel::handle_keyboard_shortcuts(editing_manager& em)
1671 auto selections = em.try_get_selections_as_copy<entt::handle>();
1673 if(is_delete_pressed)
1678 if(is_focus_pressed)
1683 if(is_duplicate_pressed)
1689void scene_panel::setup_camera_viewport(camera_component& camera_comp,
const ImVec2&
size,
const ImVec2& pos)
1693 camera_comp.get_camera().set_viewport_pos(
1694 {
static_cast<std::uint32_t
>(pos.x),
static_cast<std::uint32_t
>(pos.y)});
1695 camera_comp.set_viewport_size({
static_cast<std::uint32_t
>(
size.x),
static_cast<std::uint32_t
>(
size.y)});
1701 auto& em = ctx.
get_cached<editing_manager>();
1709 auto& camera_comp = camera_entity.get<camera_component>();
1710 const auto& camera = camera_comp.get_camera();
1711 const auto& rview = camera_comp.get_render_view();
1712 const auto& obuffer = rview.fbo_safe_get(
"OBUFFER");
1715 if(obuffer && obuffer->get_attachment_count() > 0)
1717 const auto& tex = obuffer->get_texture(0);
1722 ImGui::Text(
"No render view");
1725 if(em.is_prefab_mode())
1727 ImVec2 padding(2.0f, 2.0f);
1728 auto color = ImGui::GetColorU32(ImGuiCol_ButtonActive);
1729 auto min = ImGui::GetItemRectMin() - padding;
1730 auto max = ImGui::GetItemRectMax() + padding;
1731 ImGui::RenderFocusFrame(min, max, color, 4.0f);
1734 handle_viewport_interaction(ctx, camera, em);
1735 handle_keyboard_shortcuts(em);
1737 manipulation_gizmos(gizmo_at_center_, was_using_gizmo_,
get_center(), camera_entity, em);
1738 handle_camera_movement(camera_entity, move_dir_, acceleration_, is_dragging_);
1739 draw_selected_camera(ctx, camera_entity,
size);
1780 if(is_drag_selecting_)
1782 draw_drag_selection_rect(drag_start_pos_, drag_current_pos_);
1785 camera_comp.get_pipeline_data().get_pipeline()->set_debug_pass(visualize_passes_);
1792 auto& em = ctx.
get_cached<editing_manager>();
1795 bool has_edit_camera = camera_entity && camera_entity.all_of<transform_component, camera_component>();
1797 if(!has_edit_camera)
1802 auto size = ImGui::GetContentRegionAvail();
1806 auto pos = ImGui::GetCursorScreenPos();
1807 auto& camera_comp = camera_entity.get<camera_component>();
1809 setup_camera_viewport(camera_comp,
size, pos);
1810 draw_scene_viewport(ctx,
size);
1811 process_drag_drop_target(ctx, camera_comp);
1815void scene_panel::draw_framerate_display()
1818 auto& io = ImGui::GetIO();
1820 auto fps_size = ImGui::CalcTextSize(fmt::format(
"{:.1f}", io.Framerate).c_str()).x;
1825 ImGui::AlignedItem(1.0f,
1826 ImGui::GetContentRegionAvail().
x,
1831 ImGui::Text(
"%.1f", io.Framerate);
1838 auto& em = ctx.
get_cached<editing_manager>();
1840 if(ImGui::BeginMenuBar())
1842 draw_prefab_mode_header(ctx);
1843 draw_transform_tools(em);
1844 draw_gizmo_pivot_mode_menu(gizmo_at_center_);
1845 draw_coordinate_system_menu(em);
1846 draw_grid_settings_menu(em);
1847 draw_gizmos_settings_menu(em);
1848 draw_visualization_menu();
1849 draw_snapping_menu(em);
1850 draw_inverse_kinematics_menu(em);
1851 draw_camera_settings_menu(ctx);
1852 draw_framerate_display();
1854 ImGui::EndMenuBar();
1858void scene_panel::draw_selected_camera(
rtti::context& ctx, entt::handle editor_camera,
const ImVec2&
size)
1860 auto& em = ctx.
get_cached<editing_manager>();
1862 if(
auto sel = em.try_get_active_selection_as<entt::handle>())
1864 if(sel && sel->valid() && sel->all_of<camera_component>())
1866 const auto& selected_camera = sel->get<camera_component>();
1869 game_panel.set_visible_force(
true);
1871 const auto& camera = selected_camera.get_camera();
1872 const auto& render_view = selected_camera.get_render_view();
1873 const auto& viewport_size = camera.get_viewport_size();
1874 const auto& obuffer = render_view.fbo_safe_get(
"OBUFFER");
1880 float factor = std::min(
size.x /
float(viewport_size.width),
size.y /
float(viewport_size.height)) / 4.0f;
1881 ImVec2 bounds(viewport_size.width * factor, viewport_size.height * factor);
1884 ImVec2(ImGui::GetWindowSize().
x - 20 - bounds.x, ImGui::GetWindowSize().y - 20 - bounds.y);
1887 ImGui::SetCursorPos(image_pos);
1889 const auto& tex = obuffer->get_texture(0);
1894 auto&
transform = editor_camera.get<transform_component>();
1895 auto& transform_selected = sel->get<transform_component>();
1896 transform_selected.set_transform_global(
transform.get_transform_global());
Class that contains core camera data, used for rendering and other purposes.
Class representing a camera. Contains functionality for manipulating and updating a camera....
void focus_entities(entt::handle camera, const std::vector< entt::handle > &entities)
void duplicate_entities(const std::vector< entt::handle > &entities)
void on_frame_ui_render()
void delete_entities(const std::vector< entt::handle > &entities)
auto init(rtti::context &ctx) -> bool
void on_frame_render(rtti::context &ctx, scene &scn, entt::handle camera_entity)
auto deinit(rtti::context &ctx) -> bool
auto get_game_panel() -> game_panel &
Base class for different rendering paths in the ACE framework.
void on_frame_update(scene &scn, delta_t dt)
Prepares the scene for rendering.
void on_frame_before_render(scene &scn, delta_t dt)
auto is_focused() const -> bool
void on_frame_render(rtti::context &ctx, delta_t dt)
void on_frame_update(rtti::context &ctx, delta_t dt)
void init(rtti::context &ctx)
auto get_auto_save_prefab() const -> bool
auto is_drag_selection_active() const -> bool
void set_visible(bool visible)
auto get_drag_selection_bounds() const -> std::pair< ImVec2, ImVec2 >
void on_frame_before_render(rtti::context &ctx, delta_t dt)
auto get_center() -> entt::handle
void deinit(rtti::context &ctx)
auto get_camera() -> entt::handle
std::chrono::duration< float > delta_t
#define ICON_MDI_ROTATE_3D
#define ICON_MDI_ARROW_DOWN_BOLD
#define ICON_MDI_SELECTION_MARKER
#define ICON_MDI_GRID_LARGE
#define ICON_MDI_ROTATE_3D_VARIANT
#define ICON_MDI_DRAWING_BOX
#define ICON_MDI_CURSOR_MOVE
#define ICON_MDI_SET_CENTER
#define ICON_MDI_KEYBOARD_RETURN
#define ICON_MDI_RELATIVE_SCALE
#define ICON_MDI_MOVE_RESIZE
#define APPLOG_WARNING(...)
void Image(gfx::texture_handle _handle, uint8_t _mip, uint8_t _flags, const ImVec2 &_size, const ImVec2 &_uv0=ImVec2(0.0f, 0.0f), const ImVec2 &_uv1=ImVec2(1.0f, 1.0f))
void PushFont(Font::Enum _font)
ImTextureID ToId(gfx::texture_handle _handle, uint8_t _mip=0, uint8_t _flags=IMGUI_FLAGS_ALPHA_BLEND)
auto get_suported_formats() -> const std::vector< std::string > &
path convert_to_protocol(const path &_path)
Oposite of the resolve_protocol this function tries to convert to protocol path from an absolute one.
bgfx::Transform transform
transform_t< float > transform
void stop_all(const std::string &scope)
Stops all actions within the specified scope.
constexpr ImGuiKey delete_item
const ImGuiKeyCombination duplicate_item
constexpr ImGuiKeyChord snap_scene_camera_to_selected_camera
constexpr ImGuiKey toggle_local_global
constexpr ImGuiKey focus_selected
auto ik_set_position_ccd(entt::handle end_effector, const math::vec3 &target, size_t num_bones_in_chain, float threshold, int max_iterations) -> bool
auto ik_set_position_fabrik(entt::handle end_effector, const math::vec3 &target, size_t num_bones_in_chain, float threshold, int max_iterations) -> bool
auto make_proxy(entt::meta_any &var, const std::string &name) -> meta_any_proxy
Creates a simple proxy for direct variable access.
auto inspect_var(rtti::context &ctx, entt::meta_any &var, const meta_any_proxy &var_proxy, const var_info &info, const entt::meta_custom &custom) -> inspect_result
Main entry point for inspecting any variable with automatic type resolution.
std::vector< asset_handle< material > > original_materials
std::string current_drag_material
entt::handle last_preview_entity
Represents a handle to an asset, providing access and management functions.
auto add(Args &&... args) -> T &
static void focus_camera_on_entities(entt::handle camera, const std::vector< entt::handle > &entities)
Focuses a camera on a specified entity.
static auto create_camera_entity(rtti::context &ctx, scene &scn, const std::string &name) -> entt::handle
Creates a camera entity.
auto is_prefab_mode() const -> bool
auto get_active_scene(rtti::context &ctx) -> scene *
entt::handle prefab_entity
void exit_prefab_mode(rtti::context &ctx, save_option save_changes=save_option::prompt)
void save_prefab_changes(rtti::context &ctx)
asset_handle< prefab > edited_prefab
Root component structure for the ACE framework, serves as the base component.
auto create_entity(const std::string &tag={}, entt::handle parent={}) -> entt::handle
Creates an entity in the scene with an optional tag and parent.