1 module unecht.core.components.sceneNode; 2 3 import gl3n.linalg; 4 5 import unecht.core.component; 6 import unecht.core.object; 7 import unecht.core.componentManager; 8 9 //TODO: create mixin 10 version(UEIncludeEditor) 11 @EditorInspector("UESceneNode") 12 static class UESceneNodeInspector : IComponentEditor 13 { 14 override bool render(UEObject _component) 15 { 16 auto thisT = cast(UESceneNode)_component; 17 18 import derelict.imgui.imgui; 19 import unecht.core.components.internal.gui; 20 import std.format; 21 22 UEGui.InputVec("pos",thisT._position); 23 24 auto angles = thisT.angles; 25 if(UEGui.InputVec("angles", angles)) 26 thisT.angles = angles; 27 28 UEGui.InputVec("scale",thisT._scaling); 29 30 UEGui.Text(format("to: %s",thisT.forward)); 31 UEGui.Text(format("up: %s",thisT.up)); 32 UEGui.Text(format("layer: %s",thisT.entity.layer)); 33 34 //TODO: impl 35 return false; 36 } 37 38 mixin UERegisterInspector!UESceneNodeInspector; 39 } 40 41 /// 42 final class UESceneNode : UEComponent 43 { 44 mixin(UERegisterObject!()); 45 46 public: 47 48 /// 49 @Serialize 50 UESceneNode[] children; 51 52 /// 53 override void onDestroy() { 54 if(_parent) 55 _parent.detachChild(this); 56 57 _parent = null; 58 } 59 60 /// 61 @property UESceneNode parent() { return _parent; } 62 /// 63 @property void parent(UESceneNode _parent) { setParent(_parent); } 64 /// 65 @property void position(vec3 _v) { _position = _v; } 66 /// 67 @property vec3 position() const { return _position; } 68 /// 69 @property void scaling(vec3 v) { _scaling = v; } 70 /// 71 @property vec3 scaling() const { return _scaling; } 72 /// 73 @property void rotation(quat v) { setRotation(v); } 74 /// 75 @property quat rotation() const { return _rotation; } 76 /// 77 @property void angles(vec3 v) { setAngles(v); } 78 /// 79 @property vec3 angles() const { return _angles; } 80 /// 81 @property vec3 forward() const { return _dir; } 82 /// 83 @property vec3 right() const { return cross(_dir,_up); } 84 /// 85 @property vec3 up() const { return _up; } 86 87 /// 88 bool hasChild(UESceneNode node) const nothrow 89 { 90 import std.algorithm:countUntil; 91 92 // make nothrow 93 try return countUntil(children, node) != -1; 94 catch(Throwable){} 95 96 return false; 97 } 98 99 private: 100 101 /// 102 void setParent(UESceneNode _node) 103 { 104 assert(_node, "null parent not allowed"); 105 106 if(this._parent) 107 { 108 this._parent.detachChild(this); 109 } 110 111 this._parent = _node; 112 113 this._parent.attachChild(this); 114 } 115 116 /// 117 public void detachChild(UESceneNode _node) 118 { 119 import unecht.core.stdex; 120 children = children.removeElement(_node); 121 } 122 123 /// 124 private void attachChild(UESceneNode _node) 125 { 126 assert(_node.parent is this); 127 children ~= _node; 128 } 129 130 /// 131 private void setAngles(in vec3 v) 132 { 133 import std.math:PI; 134 135 _angles = v; 136 137 auto anglesInRad = v * (PI/180.0f); 138 139 _rotation = quat.euler_rotation(anglesInRad.x,anglesInRad.y,anglesInRad.z); 140 141 updateDirections(anglesInRad); 142 } 143 144 /// 145 private void setRotation(in quat v) 146 { 147 _rotation = v; 148 149 _angles.z = v.yaw; 150 _angles.y = v.pitch; 151 _angles.x = v.roll; 152 153 const anglesInRad = _angles; 154 155 //_rotation = quat.euler_rotation(v.pitch,v.yaw,v.roll); 156 157 import gl3n.math:_180_PI; 158 _angles *= _180_PI; 159 160 updateDirections(anglesInRad); 161 } 162 163 /// 164 private void updateDirections(in ref vec3 anglesInRad) 165 { 166 _dir = ORIG_DIR * _rotation; 167 _up = ORIG_UP * _rotation; 168 } 169 170 private: 171 @Serialize 172 UESceneNode _parent; 173 174 @Serialize vec3 _position = vec3(0); 175 @Serialize vec3 _scaling = vec3(1); 176 @Serialize quat _rotation = quat.identity; 177 //TODO: calc on the fly -> 178 @Serialize vec3 _dir = ORIG_DIR; 179 @Serialize vec3 _up = ORIG_UP; 180 @Serialize vec3 _angles = vec3(0); 181 //<- 182 183 static immutable vec3 ORIG_DIR = vec3(0,0,1); 184 static immutable vec3 ORIG_UP = vec3(0,1,0); 185 }