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 }