Skip to content

feat(ecs/editor): scene graph — local transforms, HierarchySystem, UE5-style outliner - #673

Merged
JeanPhilippeKernel merged 4 commits into
developfrom
feat/scene-graph
Aug 25, 2026
Merged

feat(ecs/editor): scene graph — local transforms, HierarchySystem, UE5-style outliner#673
JeanPhilippeKernel merged 4 commits into
developfrom
feat/scene-graph

Conversation

@JeanPhilippeKernel

@JeanPhilippeKernel JeanPhilippeKernel commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Summary

  • Scene graph: TransformComponent.Position/Rotation/Scale are now local-space values. A new WorldTransform (Mat4f) field is computed each frame by HierarchySystem and consumed by TransformSyncSystem and LightSyncSystem. A new ParentComponent records the parent EntityID.
  • HierarchySystem: two-pass propagation — roots get WorldTransform = local, children get parent.WorldTransform × local; iterates until stable to handle arbitrary nesting depth.
  • UE5-style outliner: full rewrite of HierarchyViewUIComponent — O(n) DFS using first_child/next_sib linked-list arrays on a scratch arena, custom ImDrawList rendering (no TreeNodeEx), per-type icons (World, Collection, Light, Camera, StaticMesh), Item Label / Type / Level columns, filter bar, status bar, folder+ button.
  • Collapse/expand fix: scene root was using INVALID_ENTITY as its collapse key and as the removal sentinel — replaced with a dedicated bool m_scene_root_collapsed.
  • Gizmo: reads WorldTransform for position; decomposes back to local space via parent-inverse multiply when actor has a parent.

Files changed

File Change
ZEngine/ZEngine/ECS/Components/TransformComponent.h Add Mat4f WorldTransform; Position/Rotation/Scale are now local
ZEngine/ZEngine/ECS/Components/ParentComponent.h New — EntityID Parent
ZEngine/ZEngine/ECS/Systems/HierarchySystem.h/.cpp New — SyncHierarchy(Scene&)
ZEngine/ZEngine/Engine.cpp Call SyncHierarchy before other sync systems
ZEngine/ZEngine/ECS/Systems/TransformSyncSystem.cpp Use tc.WorldTransform
ZEngine/ZEngine/ECS/Systems/LightSyncSystem.cpp Extract direction/position from WorldTransform
Tetragrama/Components/HierarchyViewUIComponent.h/.cpp Full outliner rewrite + collapse fix + gizmo local-space

Test plan

  • Existing root actors move correctly with the gizmo (local == world for roots)
  • Outliner shows all actors with correct per-type icons
  • Collapse/expand on any row (including World root) toggles correctly and is re-expandable
  • Filter bar narrows the actor list
  • New Collection button is visible with folder+ icon
  • Build clean — no warnings

TransformComponent: Position/Rotation/Scale become local-space.
WorldTransform (Mat4f) added as a computed field — never user-edited.

ParentComponent: new, EntityID Parent field. Entities without it are roots.

HierarchySystem::SyncHierarchy(Scene&):
  Pass 1 — roots: WorldTransform = ComposeTransformMatrix(local)
  Pass 2+ — children: WorldTransform = parent.World × local_mat
  Repeats until stable for arbitrary hierarchy depth.
  Runs in Engine::MainThreadRun before SyncECSToRenderScene.

TransformSyncSystem: uses tc.WorldTransform directly.
LightSyncSystem: direction from WorldTransform col 2, position from col 3.
Gizmo: reads WorldTransform, decomposes result to local (with parent inverse).

Closes #629
EOF
)
…xpand/collapse

- Rewrite HierarchyViewUIComponent to match UE5 Outliner layout:
  custom ImDrawList rendering (no TreeNodeEx), per-type icons drawn
  with AddTriangleFilled/AddCircle/AddRectFilled, Item Label / Type
  columns, filter bar, status bar actor count.

- O(n) DFS using first_child/next_sib linked-list arrays built in one
  pass from ParentComponent; stack allocated on scratch arena; no
  std::vector, no std::function, no recursion.

- Fix expand/collapse never re-expanding: scene root was using
  INVALID_ENTITY as its collapse key and as the removal sentinel in
  m_collapsed — toggling it replaced the value with itself so
  IsCollapsed always returned true. Replace with a dedicated
  m_scene_root_collapsed bool.

- RenderGuizmo reads WorldTransform for gizmo position and decomposes
  back to local space when the actor has a parent (parent-inverse
  multiply), writing local Position/Rotation/Scale.
@JeanPhilippeKernel JeanPhilippeKernel added the enhancement New feature or request label Aug 25, 2026
@JeanPhilippeKernel JeanPhilippeKernel moved this to In Progress in ZEngine Board Aug 25, 2026
@JeanPhilippeKernel JeanPhilippeKernel self-assigned this Aug 25, 2026
@JeanPhilippeKernel
JeanPhilippeKernel merged commit c065b7e into develop Aug 25, 2026
17 checks passed
@JeanPhilippeKernel
JeanPhilippeKernel deleted the feat/scene-graph branch August 25, 2026 03:23
@github-project-automation github-project-automation Bot moved this from In Progress to Done in ZEngine Board Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant