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 }