1313#include < glm/glm.hpp>
1414#include < gtc/type_ptr.hpp>
1515#include < imgui.h>
16+ #include < stack>
1617
1718using namespace ZEngine ;
1819using namespace ZEngine ::Helpers;
@@ -58,15 +59,15 @@ namespace Tetragrama::Components
5859
5960 void HierarchyViewUIComponent::Render (ZEngine::Rendering::Renderers::GraphicRenderer* const renderer, ZEngine::Hardwares::CommandBuffer* const command_buffer)
6061 {
61- auto ctx = reinterpret_cast <EditorContext*>(ParentLayer->ParentContext );
62- auto render_scene = ctx->CurrentScenePtr -> RenderScene ;
62+ auto ctx = reinterpret_cast <EditorContext*>(ParentLayer->ParentContext );
63+ auto current_scene = ctx->CurrentScenePtr ;
6364
6465 ImGui::Begin (Name, (CanBeClosed ? &CanBeClosed : NULL ), ImGuiWindowFlags_NoCollapse);
6566 if (ImGui::BeginPopupContextWindow (Name))
6667 {
6768 if (ImGui::MenuItem (" Create Empty" ))
6869 {
69- render_scene-> CreateEntityAsync ();
70+ current_scene-> CreateSceneNode ();
7071 }
7172 ImGui::EndPopup ();
7273 }
@@ -76,8 +77,8 @@ namespace Tetragrama::Components
7677 // 0 means left buttom
7778 if (ImGui::IsMouseDown (0 ) && ImGui::IsWindowHovered ())
7879 {
79- m_selected_node_identifier = - 1 ;
80- Messengers::IMessenger::SendAsync<Components::UIComponent, Messengers::EmptyMessage>(EDITOR_COMPONENT_HIERARCHYVIEW_NODE_UNSELECTED, Messengers::EmptyMessage{});
80+ ctx-> SelectedSceneNode . store (- 1 , std::memory_order_release) ;
81+ // Messengers::IMessenger::SendAsync<Components::UIComponent, Messengers::EmptyMessage>(EDITOR_COMPONENT_HIERARCHYVIEW_NODE_UNSELECTED, Messengers::EmptyMessage{});
8182 }
8283
8384 RenderGuizmo ();
@@ -87,37 +88,48 @@ namespace Tetragrama::Components
8788
8889 void HierarchyViewUIComponent::RenderTreeNodes ()
8990 {
90- auto ctx = reinterpret_cast <EditorContext*>(ParentLayer->ParentContext );
91- auto render_scene = ctx->CurrentScenePtr -> RenderScene ;
91+ auto ctx = reinterpret_cast <EditorContext*>(ParentLayer->ParentContext );
92+ auto current_scene = ctx->CurrentScenePtr ;
9293
93- auto root_nodes = render_scene->GetRootSceneNodes ();
94+ if (current_scene->IsDirty ())
95+ {
96+ return ;
97+ }
9498
95- for (int node : root_nodes )
99+ for (int i = 0 ; i < ( int ) current_scene-> Hierarchies . size (); ++i )
96100 {
97- RenderSceneNodeTree (node);
101+ if (!current_scene->IsSceneNodeDeleted (i) && current_scene->Hierarchies [i].Parent == -1 )
102+ {
103+ RenderNode (current_scene, i, ctx->SelectedSceneNode );
104+ }
98105 }
99106 }
100107
101108 void HierarchyViewUIComponent::RenderGuizmo ()
102109 {
103- if (m_selected_node_identifier <= -1 )
110+ auto ctx = reinterpret_cast <EditorContext*>(ParentLayer->ParentContext );
111+ auto current_scene = ctx->CurrentScenePtr ;
112+
113+ if (current_scene->IsDirty ())
104114 {
105115 return ;
106116 }
107117
108- // auto entity_wrapper = GraphicScene::GetSceneNodeEntityWrapper(m_selected_node_identifier);
109- auto ctx = reinterpret_cast <EditorContext*>(ParentLayer->ParentContext );
110- auto render_scene = ctx->CurrentScenePtr ->RenderScene ;
118+ int selected_node = ctx->SelectedSceneNode .load (std::memory_order_acquire);
119+ if (selected_node == -1 )
120+ {
121+ return ;
122+ }
111123
112124 if (auto active_editor_camera = ctx->CameraControllerPtr )
113125 {
114126 auto camera = active_editor_camera->GetCamera ();
115127 const auto camera_projection = camera->GetPerspectiveMatrix ();
116128 const auto camera_view_matrix = camera->GetViewMatrix ();
117129
118- auto & global_transform = render_scene-> GetSceneNodeGlobalTransform (m_selected_node_identifier) ;
130+ auto & global_transform = current_scene-> GlobalTransforms [selected_node] ;
119131 auto initial_transform = global_transform;
120- auto & local_transform = render_scene-> GetSceneNodeLocalTransform (m_selected_node_identifier) ;
132+ auto & local_transform = current_scene-> LocalTransforms [selected_node] ;
121133
122134 if (camera && IDevice::As<Keyboard>()->IsKeyPressed (ZENGINE_KEY_F, Engine::GetWindow ()))
123135 {
@@ -140,7 +152,7 @@ namespace Tetragrama::Components
140152
141153 auto delta_transform = glm::inverse (initial_transform) * global_transform;
142154 local_transform = local_transform * delta_transform;
143- render_scene ->MarkSceneNodeAsChanged (m_selected_node_identifier);
155+ // current_scene ->MarkSceneNodeAsChanged(m_selected_node_identifier);
144156
145157 if (ImGuizmo::IsUsing ())
146158 {
@@ -154,72 +166,139 @@ namespace Tetragrama::Components
154166 }
155167 }
156168
157- void HierarchyViewUIComponent::RenderSceneNodeTree ( int node_identifier )
169+ void HierarchyViewUIComponent::RenderNode (EditorScene* scene, int root_id, std::atomic_int& selected_node )
158170 {
159- if (node_identifier < 0 )
171+ struct StackEntry
160172 {
161- return ;
162- }
173+ int node_id;
174+ bool open;
175+ };
163176
164- auto ctx = reinterpret_cast <EditorContext*>(ParentLayer-> ParentContext ) ;
165- auto render_scene = ctx-> CurrentScenePtr -> RenderScene ;
177+ std::stack<StackEntry> stack ;
178+ stack. push ({root_id, false }) ;
166179
167- const auto & node_hierarchy = render_scene->GetSceneNodeHierarchy (node_identifier);
168- auto node_name = render_scene->GetSceneNodeName (node_identifier);
169- auto node_identifier_string = fmt::format (" SceneNode_{0}" , node_identifier);
170- auto flags = (node_hierarchy.FirstChild < 0 ) ? (ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | m_node_flag) : m_node_flag;
171- flags |= (m_selected_node_identifier == node_identifier) ? ImGuiTreeNodeFlags_Selected : 0 ;
172- auto label = (!node_name.empty ()) ? std::string (node_name) : fmt::format (" Node_{0}" , node_identifier);
173- bool is_node_opened = ImGui::TreeNodeEx (node_identifier_string.c_str (), flags, " %s" , label.c_str ());
174-
175- if (ImGui::IsItemClicked ())
180+ while (!stack.empty ())
176181 {
177- m_selected_node_identifier = node_identifier;
182+ auto entry = stack.top ();
183+ stack.pop ();
178184
179- auto entity = render_scene->GetSceneNodeEntityWrapper (m_selected_node_identifier);
180- Messengers::IMessenger::SendAsync<Components::UIComponent, Messengers::GenericMessage<SceneEntity>>(EDITOR_COMPONENT_HIERARCHYVIEW_NODE_SELECTED, Messengers::GenericMessage<SceneEntity>{std::move (entity)});
181- }
185+ // Handle manual TreePop marker
186+ if (entry.node_id == -1 )
187+ {
188+ ImGui::TreePop ();
189+ continue ;
190+ }
182191
183- if (is_node_opened)
184- {
185- /*
186- * Popup features
187- */
188- bool request_entity_removal = false ;
189- if (ImGui::BeginPopupContextItem (node_identifier_string.c_str ()))
192+ if (scene->IsSceneNodeDeleted (entry.node_id ))
193+ {
194+ continue ;
195+ }
196+ const auto & node = scene->Hierarchies [entry.node_id ];
197+
198+ auto name_id = scene->NodeNames [entry.node_id ];
199+
200+ bool is_selected = (selected_node == entry.node_id );
201+ bool has_children = (node.FirstChild != -1 );
202+
203+ ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanFullWidth;
204+ if (!has_children)
205+ flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
206+ if (is_selected)
207+ flags |= ImGuiTreeNodeFlags_Selected;
208+
209+ auto node_id = fmt::format (" SceneNode_{0}" , entry.node_id );
210+ bool open = ImGui::TreeNodeEx (node_id.c_str (), flags, " %s" , scene->Names [name_id].c_str ());
211+
212+ if (ImGui::IsItemClicked (ImGuiMouseButton_Left))
213+ {
214+ selected_node.store (entry.node_id , std::memory_order_release);
215+ }
216+
217+ // === Drag source ===
218+ if (ImGui::BeginDragDropSource ())
219+ {
220+ ImGui::SetDragDropPayload (" NODE_DRAG" , &entry.node_id , sizeof (int ));
221+ ImGui::EndDragDropSource ();
222+ }
223+
224+ // === Drop target ===
225+ if (ImGui::BeginDragDropTarget ())
226+ {
227+ if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload (" NODE_DRAG" ))
228+ {
229+ int dragged_id = *(const int *) payload->Data ;
230+ if (dragged_id != entry.node_id && !scene->IsSceneNodeDeleted (dragged_id))
231+ {
232+ // prevent making it a child of itself or its descendants
233+ int test = entry.node_id ;
234+ bool is_descendant = false ;
235+ while (test != -1 )
236+ {
237+ if (test == dragged_id)
238+ {
239+ is_descendant = true ;
240+ break ;
241+ }
242+ test = scene->Hierarchies [test].Parent ;
243+ }
244+
245+ if (!is_descendant)
246+ {
247+ scene->ReparentNode (dragged_id, entry.node_id );
248+ }
249+ }
250+ }
251+ ImGui::EndDragDropTarget ();
252+ }
253+
254+ if (ImGui::BeginPopupContextItem (node_id.c_str ()))
190255 {
191256 if (ImGui::MenuItem (" Create Empty child" ))
192257 {
193- render_scene-> CreateEntityAsync ( " Empty Entity " , m_selected_node_identifier, node_hierarchy .DepthLevel + 1 );
258+ scene-> CreateSceneNode (entry. node_id , node .DepthLevel + 1 );
194259 }
195260
196261 if (ImGui::MenuItem (" Rename" ))
197262 {
198263 }
264+
199265 if (ImGui::MenuItem (" Delete" ))
200266 {
201- Messengers::IMessenger::SendAsync<Components::UIComponent, Messengers::EmptyMessage>(EDITOR_COMPONENT_HIERARCHYVIEW_NODE_DELETED, Messengers::EmptyMessage{});
202- request_entity_removal = true ;
267+ scene->RemoveSceneNode (entry.node_id );
203268 }
204269 ImGui::EndPopup ();
205270 }
206271
207- if (request_entity_removal )
272+ if (open && has_children )
208273 {
209- render_scene-> RemoveNodeAsync (node_identifier);
210- }
274+ // Push TreePop manually
275+ stack. push ({- 1 , 0 }); // Marker for TreePop
211276
212- if (node_hierarchy. FirstChild > - 1 )
213- {
214- auto sibling_scene_node_collection = render_scene-> GetSceneNodeSiblingCollection (node_hierarchy. FirstChild ) ;
215- // We consider first child as sibling node
216- sibling_scene_node_collection. emplace ( std::begin (sibling_scene_node_collection), node_hierarchy. FirstChild );
217- for (auto sibling_identifier : sibling_scene_node_collection )
277+ // Push children in reverse order
278+ auto scratch = ZGetScratch (&ParentLayer-> LayerArena );
279+ ZEngine::Core::Containers::Array< int > children ;
280+ children. init (scratch. Arena , 5 );
281+
282+ for (int child = node. FirstChild ; child != - 1 ; child = scene-> Hierarchies [child]. RightSibling )
218283 {
219- RenderSceneNodeTree (sibling_identifier);
284+ if (!scene->IsSceneNodeDeleted (child))
285+ {
286+ children.push (child);
287+ }
220288 }
289+
290+ for (int i = static_cast <int >(children.size ()) - 1 ; i >= 0 ; --i)
291+ {
292+ stack.push ({children[i], false });
293+ }
294+
295+ ZReleaseScratch (scratch);
296+ }
297+ else if (!has_children && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
298+ {
299+ // Only pop if not marked as Leaf
300+ ImGui::TreePop ();
221301 }
222- ImGui::TreePop ();
223302 }
224303 }
225304} // namespace Tetragrama::Components
0 commit comments