1 /*
2 Copyright (c) 2019-2020 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 */
27 
28 module dagon.graphics.entity;
29 
30 import std.math;
31 
32 import dlib.core.ownership;
33 import dlib.container.array;
34 import dlib.math.vector;
35 import dlib.math.matrix;
36 import dlib.math.quaternion;
37 import dlib.math.transformation;
38 import dlib.math.utils;
39 import dlib.geometry.aabb;
40 
41 import dagon.core.bindings;
42 import dagon.core.event;
43 import dagon.core.time;
44 import dagon.graphics.updateable;
45 import dagon.graphics.drawable;
46 import dagon.graphics.mesh;
47 import dagon.graphics.terrain;
48 import dagon.graphics.material;
49 import dagon.graphics.tween;
50 
51 class EntityManager: Owner
52 {
53     Array!Entity entities;
54 
55     this(Owner owner)
56     {
57         super(owner);
58     }
59 
60     void addEntity(Entity e)
61     {
62         entities.append(e);
63     }
64 
65     ~this()
66     {
67         entities.free();
68     }
69 }
70 
71 enum EntityLayer: int
72 {
73     Background = 0,
74     Spatial = 1,
75     Foreground = 2
76 }
77 
78 class Entity: Owner, Updateable
79 {
80    public:
81     EntityLayer layer = EntityLayer.Spatial;
82     bool visible = true;
83     bool castShadow = true;
84     bool solid = false;
85     bool dynamic = true;
86     bool decal = false;
87     bool transparent = false;
88     float opacity = 1.0f;
89     float blurMask = 1.0f;
90 
91     EntityManager manager;
92 
93     Entity parent = null;
94     Array!Entity children;
95 
96     Array!EntityComponent components;
97     Array!Tween tweens;
98 
99     Drawable drawable;
100     Material material;
101 
102     Vector3f position;
103     Quaternionf rotation;
104     Vector3f scaling;
105 
106     Matrix4x4f transformation;
107     Matrix4x4f invTransformation;
108 
109     Matrix4x4f absoluteTransformation;
110     Matrix4x4f invAbsoluteTransformation;
111 
112     Matrix4x4f prevTransformation;
113     Matrix4x4f prevAbsoluteTransformation;
114 
115     Vector3f boundingBoxSize;
116 
117    protected:
118     AABB aabb;
119 
120    public:
121     this(Owner owner)
122     {
123         super(owner);
124 
125         EntityManager mngr = cast(EntityManager)owner;
126         if (mngr)
127         {
128             manager = mngr;
129             manager.addEntity(this);
130         }
131 
132         position = Vector3f(0, 0, 0);
133         rotation = Quaternionf.identity;
134         scaling = Vector3f(1, 1, 1);
135 
136         transformation = Matrix4x4f.identity;
137         invTransformation = Matrix4x4f.identity;
138 
139         absoluteTransformation = Matrix4x4f.identity;
140         invAbsoluteTransformation = Matrix4x4f.identity;
141 
142         prevTransformation = Matrix4x4f.identity;
143         prevAbsoluteTransformation = Matrix4x4f.identity;
144 
145         tweens.reserve(10);
146 
147         boundingBoxSize = Vector3f(1.0f, 1.0f, 1.0f);
148         aabb = AABB(position, boundingBoxSize);
149     }
150 
151     void setParent(Entity e)
152     {
153         if (parent)
154             parent.removeChild(this);
155 
156         parent = e;
157         parent.addChild(this);
158     }
159 
160     void addChild(Entity e)
161     {
162         if (e.parent)
163             e.parent.removeChild(e);
164         children.append(e);
165         e.parent = this;
166     }
167 
168     void removeChild(Entity e)
169     {
170         children.removeFirst(e);
171         e.parent = null;
172     }
173 
174     void addComponent(EntityComponent ec)
175     {
176         components.append(ec);
177     }
178 
179     void removeComponent(EntityComponent ec)
180     {
181         components.removeFirst(ec);
182     }
183     
184     void updateAbsoluteTransformation()
185     {
186         invTransformation = transformation.inverse;
187         
188         if (parent)
189         {
190             absoluteTransformation = parent.absoluteTransformation * transformation;
191             invAbsoluteTransformation = invTransformation * parent.invAbsoluteTransformation;
192             prevAbsoluteTransformation = parent.prevAbsoluteTransformation * prevTransformation;
193         }
194         else
195         {
196             absoluteTransformation = transformation;
197             invAbsoluteTransformation = invTransformation;
198             prevAbsoluteTransformation = prevTransformation;
199         }
200 
201         aabb = AABB(absoluteTransformation.translation, boundingBoxSize);
202     }
203 
204     void updateTransformation()
205     {
206         prevTransformation = transformation;
207 
208         transformation =
209             translationMatrix(position) *
210             rotation.toMatrix4x4 *
211             scaleMatrix(scaling);
212         
213         updateAbsoluteTransformation();
214     }
215 
216     void updateTransformationDeep()
217     {
218         if (parent)
219             parent.updateTransformationDeep();
220         updateTransformation();
221     }
222     
223     void updateTransformationTopDown()
224     {
225         updateTransformation();
226         
227         foreach(child; children)
228         {
229             child.updateTransformationTopDown();
230         }
231     }
232 
233     void update(Time t)
234     {
235         foreach(i, ref tween; tweens.data)
236         {
237             tween.update(t.delta);
238         }
239 
240         updateTransformation();
241 
242         foreach(c; components)
243         {
244             c.update(t);
245         }
246     }
247 
248     void release()
249     {
250         if (parent)
251             parent.removeChild(this);
252 
253         for (size_t i = 0; i < children.data.length; i++)
254             children.data[i].parent = null;
255 
256         children.free();
257         components.free();
258         tweens.free();
259     }
260 
261     Vector3f positionAbsolute()
262     {
263         return absoluteTransformation.translation;
264     }
265 
266     Quaternionf rotationAbsolute()
267     {
268         if (parent)
269             return parent.rotationAbsolute * rotation;
270         else
271             return rotation;
272     }
273 
274     void translate(Vector3f v)
275     {
276         position += v;
277     }
278 
279     void translate(float vx, float vy, float vz)
280     {
281         position += Vector3f(vx, vy, vz);
282     }
283 
284     void move(float speed)
285     {
286         position += transformation.forward * speed;
287     }
288 
289     void moveToPoint(Vector3f p, float speed)
290     {
291         Vector3f dir = (p - position).normalized;
292         float d = distance(p, position);
293         if (d > speed)
294             position += dir * speed;
295         else
296             position += dir * d;
297     }
298 
299     void strafe(float speed)
300     {
301         position += transformation.right * speed;
302     }
303 
304     void lift(float speed)
305     {
306         position += transformation.up * speed;
307     }
308 
309     void angles(Vector3f v)
310     {
311         rotation =
312             rotationQuaternion!float(Axis.x, degtorad(v.x)) *
313             rotationQuaternion!float(Axis.y, degtorad(v.y)) *
314             rotationQuaternion!float(Axis.z, degtorad(v.z));
315     }
316 
317     void rotate(Vector3f v)
318     {
319         auto r =
320             rotationQuaternion!float(Axis.x, degtorad(v.x)) *
321             rotationQuaternion!float(Axis.y, degtorad(v.y)) *
322             rotationQuaternion!float(Axis.z, degtorad(v.z));
323         rotation *= r;
324     }
325 
326     void rotate(float x, float y, float z)
327     {
328         rotate(Vector3f(x, y, z));
329     }
330 
331     void pitch(float angle)
332     {
333         rotation *= rotationQuaternion!float(Axis.x, degtorad(angle));
334     }
335 
336     void turn(float angle)
337     {
338         rotation *= rotationQuaternion!float(Axis.y, degtorad(angle));
339     }
340 
341     void roll(float angle)
342     {
343         rotation *= rotationQuaternion!float(Axis.z, degtorad(angle));
344     }
345 
346     void scale(float s)
347     {
348         scaling += Vector3f(s, s, s);
349     }
350 
351     void scale(Vector3f s)
352     {
353         scaling += s;
354     }
355 
356     void scaleX(float s)
357     {
358         scaling.x += s;
359     }
360 
361     void scaleY(float s)
362     {
363         scaling.y += s;
364     }
365 
366     void scaleZ(float s)
367     {
368         scaling.z += s;
369     }
370 
371     Vector3f direction() @property
372     {
373         return transformation.forward;
374     }
375 
376     Vector3f right() @property
377     {
378         return transformation.right;
379     }
380 
381     Vector3f up() @property
382     {
383         return transformation.up;
384     }
385 
386     Vector3f directionAbsolute() @property
387     {
388         return absoluteTransformation.forward;
389     }
390 
391     Vector3f rightAbsolute() @property
392     {
393         return absoluteTransformation.right;
394     }
395 
396     Vector3f upAbsolute() @property
397     {
398         return absoluteTransformation.up;
399     }
400 
401     Tween* getInactiveTween()
402     {
403         Tween* inactiveTween = null;
404         foreach(i, ref t; tweens.data)
405         {
406             if (!t.active)
407             {
408                 inactiveTween = &tweens.data[i];
409                 break;
410             }
411         }
412         return inactiveTween;
413     }
414 
415     Tween* moveFromTo(Vector3f pointFrom, Vector3f pointTo, double duration, Easing easing = Easing.Linear)
416     {
417         Tween* existingTween = getInactiveTween();
418 
419         if (existingTween)
420         {
421             *existingTween = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing);
422             return existingTween;
423         }
424         else
425         {
426             Tween t = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing);
427             tweens.append(t);
428             return &tweens.data[$-1];
429         }
430     }
431 
432     Tween* rotateFromTo(Vector3f anglesFrom, Vector3f anglesTo, double duration, Easing easing = Easing.Linear)
433     {
434         Tween* existingTween = getInactiveTween();
435 
436         if (existingTween)
437         {
438             *existingTween = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing);
439             return existingTween;
440         }
441         else
442         {
443             Tween t = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing);
444             tweens.append(t);
445             return &tweens.data[$-1];
446         }
447     }
448 
449     Tween* scaleFromTo(Vector3f sFrom, Vector3f sTo, double duration, Easing easing = Easing.Linear)
450     {
451         Tween* existingTween = getInactiveTween();
452 
453         if (existingTween)
454         {
455             *existingTween = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing);
456             return existingTween;
457         }
458         else
459         {
460             Tween t = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing);
461             tweens.append(t);
462             return &tweens.data[$-1];
463         }
464     }
465 
466     AABB boundingBox() @property
467     {
468         if (drawable)
469         {
470             Mesh mesh = cast(Mesh)drawable;
471             Terrain terrain = cast(Terrain)drawable;
472 
473             if (terrain)
474             {
475                 mesh = terrain.mesh;
476             }
477 
478             if (mesh)
479             {
480                 auto bb = mesh.boundingBox;
481                 // TODO: transform bb with absoluteTransformation
482                 return AABB(absoluteTransformation.translation + bb.center, bb.size * matrixScale(absoluteTransformation));
483             }
484             else
485                 return aabb;
486         }
487         else
488             return aabb;
489     }
490 
491     ~this()
492     {
493         release();
494     }
495 
496     void processEvents()
497     {
498         foreach(c; components)
499         {
500             c.processEvents();
501         }
502     }
503 }
504 
505 class EntityComponent: EventListener, Updateable, Drawable
506 {
507     Entity entity;
508 
509     this(EventManager em, Entity e)
510     {
511         super(em, e);
512         entity = e;
513         entity.addComponent(this);
514     }
515 
516     // Override me
517     void update(Time t)
518     {
519     }
520 
521     // Override me
522     void render(GraphicsState* state)
523     {
524     }
525 }
526 
527 interface EntityGroup
528 {
529     int opApply(scope int delegate(Entity) dg);
530 }
531 
532 Vector3f matrixScale(Matrix4x4f m)
533 {
534     float sx = Vector3f(m.a11, m.a12, m.a13).length;
535     float sy = Vector3f(m.a21, m.a22, m.a23).length;
536     float sz = Vector3f(m.a31, m.a32, m.a33).length;
537     return Vector3f(sx, sy, sz);
538 }