1 /*
2 Copyright (c) 2019-2022 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 enum EntityType: int
79 {
80     General = 0,
81     Terrain = 1
82 }
83 
84 class Entity: Owner, Updateable
85 {
86    public:
87     EntityLayer layer = EntityLayer.Spatial;
88     EntityType type = EntityType.General;
89     
90     bool visible = true;
91     bool castShadow = true;
92     bool solid = false;
93     bool dynamic = true;
94     bool decal = false;
95     bool transparent = false;
96     float opacity = 1.0f;
97     float gbufferMask = 1.0f;
98     float blurMask = 1.0f;
99 
100     EntityManager manager;
101 
102     Entity parent = null;
103     Array!Entity children;
104 
105     Array!EntityComponent components;
106     Array!Tween tweens;
107 
108     Drawable drawable;
109     Material material;
110 
111     Vector3f position;
112     Quaternionf rotation;
113     Vector3f scaling;
114 
115     Matrix4x4f transformation;
116     Matrix4x4f invTransformation;
117 
118     Matrix4x4f absoluteTransformation;
119     Matrix4x4f invAbsoluteTransformation;
120 
121     Matrix4x4f prevTransformation;
122     Matrix4x4f prevAbsoluteTransformation;
123 
124     Vector3f boundingBoxSize;
125 
126    protected:
127     AABB aabb;
128 
129    public:
130     this(Owner owner)
131     {
132         super(owner);
133 
134         EntityManager mngr = cast(EntityManager)owner;
135         if (mngr)
136         {
137             manager = mngr;
138             manager.addEntity(this);
139         }
140 
141         position = Vector3f(0, 0, 0);
142         rotation = Quaternionf.identity;
143         scaling = Vector3f(1, 1, 1);
144 
145         transformation = Matrix4x4f.identity;
146         invTransformation = Matrix4x4f.identity;
147 
148         absoluteTransformation = Matrix4x4f.identity;
149         invAbsoluteTransformation = Matrix4x4f.identity;
150 
151         prevTransformation = Matrix4x4f.identity;
152         prevAbsoluteTransformation = Matrix4x4f.identity;
153 
154         tweens.reserve(10);
155 
156         boundingBoxSize = Vector3f(1.0f, 1.0f, 1.0f);
157         aabb = AABB(position, boundingBoxSize);
158     }
159 
160     void setParent(Entity e)
161     {
162         if (parent)
163             parent.removeChild(this);
164 
165         parent = e;
166         parent.addChild(this);
167     }
168 
169     void addChild(Entity e)
170     {
171         if (e.parent)
172             e.parent.removeChild(e);
173         children.append(e);
174         e.parent = this;
175     }
176 
177     void removeChild(Entity e)
178     {
179         children.removeFirst(e);
180         e.parent = null;
181     }
182 
183     void addComponent(EntityComponent ec)
184     {
185         components.append(ec);
186     }
187 
188     void removeComponent(EntityComponent ec)
189     {
190         components.removeFirst(ec);
191     }
192     
193     void updateAbsoluteTransformation()
194     {
195         invTransformation = transformation.inverse;
196         
197         if (parent)
198         {
199             absoluteTransformation = parent.absoluteTransformation * transformation;
200             invAbsoluteTransformation = invTransformation * parent.invAbsoluteTransformation;
201             prevAbsoluteTransformation = parent.prevAbsoluteTransformation * prevTransformation;
202         }
203         else
204         {
205             absoluteTransformation = transformation;
206             invAbsoluteTransformation = invTransformation;
207             prevAbsoluteTransformation = prevTransformation;
208         }
209 
210         aabb = AABB(absoluteTransformation.translation, boundingBoxSize);
211     }
212 
213     void updateTransformation()
214     {
215         prevTransformation = transformation;
216 
217         transformation =
218             translationMatrix(position) *
219             rotation.toMatrix4x4 *
220             scaleMatrix(scaling);
221         
222         updateAbsoluteTransformation();
223     }
224 
225     void updateTransformationDeep()
226     {
227         if (parent)
228             parent.updateTransformationDeep();
229         updateTransformation();
230     }
231     
232     void updateTransformationTopDown()
233     {
234         updateTransformation();
235         
236         foreach(child; children)
237         {
238             child.updateTransformationTopDown();
239         }
240     }
241 
242     void update(Time t)
243     {
244         foreach(i, ref tween; tweens.data)
245         {
246             tween.update(t.delta);
247         }
248 
249         updateTransformation();
250 
251         foreach(c; components)
252         {
253             c.update(t);
254         }
255     }
256 
257     void release()
258     {
259         if (parent)
260             parent.removeChild(this);
261 
262         for (size_t i = 0; i < children.data.length; i++)
263             children.data[i].parent = null;
264 
265         children.free();
266         components.free();
267         tweens.free();
268     }
269 
270     Vector3f positionAbsolute()
271     {
272         return absoluteTransformation.translation;
273     }
274 
275     Quaternionf rotationAbsolute()
276     {
277         if (parent)
278             return parent.rotationAbsolute * rotation;
279         else
280             return rotation;
281     }
282 
283     void translate(Vector3f v)
284     {
285         position += v;
286     }
287 
288     void translate(float vx, float vy, float vz)
289     {
290         position += Vector3f(vx, vy, vz);
291     }
292 
293     void move(float speed)
294     {
295         position += transformation.forward * speed;
296     }
297 
298     void moveToPoint(Vector3f p, float speed)
299     {
300         Vector3f dir = (p - position).normalized;
301         float d = distance(p, position);
302         if (d > speed)
303             position += dir * speed;
304         else
305             position += dir * d;
306     }
307 
308     void strafe(float speed)
309     {
310         position += transformation.right * speed;
311     }
312 
313     void lift(float speed)
314     {
315         position += transformation.up * speed;
316     }
317 
318     void angles(Vector3f v)
319     {
320         rotation =
321             rotationQuaternion!float(Axis.x, degtorad(v.x)) *
322             rotationQuaternion!float(Axis.y, degtorad(v.y)) *
323             rotationQuaternion!float(Axis.z, degtorad(v.z));
324     }
325 
326     void setRotation(float x, float y, float z)
327     {
328         angles = Vector3f(x, y, z);
329     }
330 
331     void rotate(Vector3f v)
332     {
333         auto r =
334             rotationQuaternion!float(Axis.x, degtorad(v.x)) *
335             rotationQuaternion!float(Axis.y, degtorad(v.y)) *
336             rotationQuaternion!float(Axis.z, degtorad(v.z));
337         rotation *= r;
338     }
339 
340     void rotate(float x, float y, float z)
341     {
342         rotate(Vector3f(x, y, z));
343     }
344 
345     void pitch(float angle)
346     {
347         rotation *= rotationQuaternion!float(Axis.x, degtorad(angle));
348     }
349 
350     void turn(float angle)
351     {
352         rotation *= rotationQuaternion!float(Axis.y, degtorad(angle));
353     }
354 
355     void roll(float angle)
356     {
357         rotation *= rotationQuaternion!float(Axis.z, degtorad(angle));
358     }
359 
360     void scale(float s)
361     {
362         scaling += Vector3f(s, s, s);
363     }
364 
365     void scale(Vector3f s)
366     {
367         scaling += s;
368     }
369 
370     void scaleX(float s)
371     {
372         scaling.x += s;
373     }
374 
375     void scaleY(float s)
376     {
377         scaling.y += s;
378     }
379 
380     void scaleZ(float s)
381     {
382         scaling.z += s;
383     }
384 
385     Vector3f direction() @property
386     {
387         return transformation.forward;
388     }
389 
390     Vector3f right() @property
391     {
392         return transformation.right;
393     }
394 
395     Vector3f up() @property
396     {
397         return transformation.up;
398     }
399 
400     Vector3f directionAbsolute() @property
401     {
402         return absoluteTransformation.forward;
403     }
404 
405     Vector3f rightAbsolute() @property
406     {
407         return absoluteTransformation.right;
408     }
409 
410     Vector3f upAbsolute() @property
411     {
412         return absoluteTransformation.up;
413     }
414 
415     Tween* getInactiveTween()
416     {
417         Tween* inactiveTween = null;
418         foreach(i, ref t; tweens.data)
419         {
420             if (!t.active)
421             {
422                 inactiveTween = &tweens.data[i];
423                 break;
424             }
425         }
426         return inactiveTween;
427     }
428 
429     Tween* moveFromTo(Vector3f pointFrom, Vector3f pointTo, double duration, Easing easing = Easing.Linear)
430     {
431         Tween* existingTween = getInactiveTween();
432 
433         if (existingTween)
434         {
435             *existingTween = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing);
436             return existingTween;
437         }
438         else
439         {
440             Tween t = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing);
441             tweens.append(t);
442             return &tweens.data[$-1];
443         }
444     }
445 
446     Tween* rotateFromTo(Vector3f anglesFrom, Vector3f anglesTo, double duration, Easing easing = Easing.Linear)
447     {
448         Tween* existingTween = getInactiveTween();
449 
450         if (existingTween)
451         {
452             *existingTween = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing);
453             return existingTween;
454         }
455         else
456         {
457             Tween t = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing);
458             tweens.append(t);
459             return &tweens.data[$-1];
460         }
461     }
462 
463     Tween* scaleFromTo(Vector3f sFrom, Vector3f sTo, double duration, Easing easing = Easing.Linear)
464     {
465         Tween* existingTween = getInactiveTween();
466 
467         if (existingTween)
468         {
469             *existingTween = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing);
470             return existingTween;
471         }
472         else
473         {
474             Tween t = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing);
475             tweens.append(t);
476             return &tweens.data[$-1];
477         }
478     }
479 
480     AABB boundingBox() @property
481     {
482         if (drawable)
483         {
484             Mesh mesh = cast(Mesh)drawable;
485             Terrain terrain = cast(Terrain)drawable;
486 
487             if (terrain)
488             {
489                 mesh = terrain.mesh;
490             }
491 
492             if (mesh)
493             {
494                 auto bb = mesh.boundingBox;
495                 // TODO: transform bb with absoluteTransformation
496                 return AABB(absoluteTransformation.translation + bb.center, bb.size * matrixScale(absoluteTransformation));
497             }
498             else
499                 return aabb;
500         }
501         else
502             return aabb;
503     }
504 
505     ~this()
506     {
507         release();
508     }
509 
510     void processEvents()
511     {
512         foreach(c; components)
513         {
514             c.processEvents();
515         }
516     }
517 }
518 
519 class EntityComponent: EventListener, Updateable, Drawable
520 {
521     Entity entity;
522 
523     this(EventManager em, Entity e)
524     {
525         super(em, e);
526         entity = e;
527         entity.addComponent(this);
528     }
529 
530     // Override me
531     void update(Time t)
532     {
533     }
534 
535     // Override me
536     void render(GraphicsState* state)
537     {
538     }
539 }
540 
541 interface EntityGroup
542 {
543     int opApply(scope int delegate(Entity) dg);
544 }
545 
546 Vector3f matrixScale(Matrix4x4f m)
547 {
548     float sx = Vector3f(m.a11, m.a12, m.a13).length;
549     float sy = Vector3f(m.a21, m.a22, m.a23).length;
550     float sz = Vector3f(m.a31, m.a32, m.a33).length;
551     return Vector3f(sx, sy, sz);
552 }