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 }