1 module unecht.core.scenegraph;
2 
3 import std.uuid;
4 
5 import gl3n.linalg;
6 
7 import unecht.core.component;
8 import unecht.core.entity;
9 import unecht.core.components.sceneNode;
10 import unecht.core.object;
11 
12 ///
13 final class UEScenegraph
14 {
15 public:
16 
17 	///
18 	@property UESceneNode root() {return _root;}
19 	///
20 	@property void playing(bool _v) { _playing=_v; }
21 	///
22 	@property bool playing() const { return _playing; }
23 	///
24 	@property void step() { _singleStep = true; }
25 
26     ///
27     this()
28     {
29         _root = new UESceneNode();
30         import unecht.core.hideFlags:HideFlags;
31         _root.hideFlags.set(HideFlags.dontSaveInScene);
32     }
33 
34 	///
35 	void update()
36 	{
37         import unecht.ue:ue;
38         import unecht.core.events:UEEvent,UEEventType;
39 
40 		updateNode(_root);
41 
42         executeDestruction();
43 
44 		if(_playing || _singleStep)
45 		{
46 			_singleStep=false;
47 
48 			//TODO: optimize this
49 			auto allComponents = gatherAllComponents!UEComponent();
50 			foreach(c; allComponents)
51 				c.onUpdate();
52 		}
53         else
54         {
55             UEEvent ev;
56             ev.eventType = UEEventType.updateEditMode;
57             ue.events.trigger(ev);
58         }
59 	}
60 
61 	///
62 	auto gatherAllComponents(T : UEComponent)()
63 	{
64 		T[] res;
65 		gatherAllComponentsInNode!T(_root,res);
66 		return res;
67 	}
68 
69     ///
70     public UEObject findObject(UUID id)
71     {
72         return findObjectRecursive(root, id);
73     }
74 
75     ///
76     private UEObject findObjectRecursive(UESceneNode node, UUID id)
77     {
78         if(node.instanceId == id)
79             return node;
80 
81         if(node.entity)
82         {
83             foreach(c; node.entity.components)
84             {
85                 if(c.instanceId == id)
86                     return c;
87             }
88         }
89 
90         foreach(c; node.children)
91         {
92             if(c.instanceId == id)
93                 return c;
94         }
95 
96         return null;
97     }
98 
99 	private void gatherAllComponentsInNode(T : UEComponent)(UESceneNode _node, ref T[] _result)
100 	{
101 		if(_node.entity)
102 		{
103 			foreach(c; _node.entity.components)
104 			{
105 				auto componentAsT = cast(T)c;
106 				if(componentAsT)
107 					_result ~= componentAsT;
108 			}
109 		}
110 
111 		foreach(child; _node.children)
112 			gatherAllComponentsInNode!T(child,_result);
113 	}
114 
115 	private void updateNode(UESceneNode _node)
116 	{
117 		if(!_node)
118 			return;
119 
120         if(_node.entity && _node.entity.destroyed)
121             _destroyedEntites ~= _node.entity;
122 
123 		foreach(node; _node.children)
124 			updateNode(node);
125 	}
126 
127     private void executeDestruction()
128     {
129         if(_destroyedEntites.length > 0)
130         {
131             foreach(toDestroy; _destroyedEntites)
132                 UEEntity.destroyImmediate(toDestroy);
133             
134             _destroyedEntites.length = 0;
135         }
136     }
137 
138 private:
139     UESceneNode _root;
140     UEEntity[] _destroyedEntites;
141 	bool _playing=true;
142 	bool _singleStep=false;
143 }
144 
145 unittest
146 {
147 	//TODO:
148     import unecht.core.logger;
149 	log.info("TODO: write tests for scenegraph");
150 }