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 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 rotate(Vector3f v)
327     {
328         auto r =
329             rotationQuaternion!float(Axis.x, degtorad(v.x)) *
330             rotationQuaternion!float(Axis.y, degtorad(v.y)) *
331             rotationQuaternion!float(Axis.z, degtorad(v.z));
332         rotation *= r;
333     }
334 
335     void rotate(float x, float y, float z)
336     {
337         rotate(Vector3f(x, y, z));
338     }
339 
340     void pitch(float angle)
341     {
342         rotation *= rotationQuaternion!float(Axis.x, degtorad(angle));
343     }
344 
345     void turn(float angle)
346     {
347         rotation *= rotationQuaternion!float(Axis.y, degtorad(angle));
348     }
349 
350     void roll(float angle)
351     {
352         rotation *= rotationQuaternion!float(Axis.z, degtorad(angle));
353     }
354 
355     void scale(float s)
356     {
357         scaling += Vector3f(s, s, s);
358     }
359 
360     void scale(Vector3f s)
361     {
362         scaling += s;
363     }
364 
365     void scaleX(float s)
366     {
367         scaling.x += s;
368     }
369 
370     void scaleY(float s)
371     {
372         scaling.y += s;
373     }
374 
375     void scaleZ(float s)
376     {
377         scaling.z += s;
378     }
379 
380     Vector3f direction() @property
381     {
382         return transformation.forward;
383     }
384 
385     Vector3f right() @property
386     {
387         return transformation.right;
388     }
389 
390     Vector3f up() @property
391     {
392         return transformation.up;
393     }
394 
395     Vector3f directionAbsolute() @property
396     {
397         return absoluteTransformation.forward;
398     }
399 
400     Vector3f rightAbsolute() @property
401     {
402         return absoluteTransformation.right;
403     }
404 
405     Vector3f upAbsolute() @property
406     {
407         return absoluteTransformation.up;
408     }
409 
410     Tween* getInactiveTween()
411     {
412         Tween* inactiveTween = null;
413         foreach(i, ref t; tweens.data)
414         {
415             if (!t.active)
416             {
417                 inactiveTween = &tweens.data[i];
418                 break;
419             }
420         }
421         return inactiveTween;
422     }
423 
424     Tween* moveFromTo(Vector3f pointFrom, Vector3f pointTo, double duration, Easing easing = Easing.Linear)
425     {
426         Tween* existingTween = getInactiveTween();
427 
428         if (existingTween)
429         {
430             *existingTween = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing);
431             return existingTween;
432         }
433         else
434         {
435             Tween t = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing);
436             tweens.append(t);
437             return &tweens.data[$-1];
438         }
439     }
440 
441     Tween* rotateFromTo(Vector3f anglesFrom, Vector3f anglesTo, double duration, Easing easing = Easing.Linear)
442     {
443         Tween* existingTween = getInactiveTween();
444 
445         if (existingTween)
446         {
447             *existingTween = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing);
448             return existingTween;
449         }
450         else
451         {
452             Tween t = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing);
453             tweens.append(t);
454             return &tweens.data[$-1];
455         }
456     }
457 
458     Tween* scaleFromTo(Vector3f sFrom, Vector3f sTo, double duration, Easing easing = Easing.Linear)
459     {
460         Tween* existingTween = getInactiveTween();
461 
462         if (existingTween)
463         {
464             *existingTween = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing);
465             return existingTween;
466         }
467         else
468         {
469             Tween t = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing);
470             tweens.append(t);
471             return &tweens.data[$-1];
472         }
473     }
474 
475     AABB boundingBox() @property
476     {
477         if (drawable)
478         {
479             Mesh mesh = cast(Mesh)drawable;
480             Terrain terrain = cast(Terrain)drawable;
481 
482             if (terrain)
483             {
484                 mesh = terrain.mesh;
485             }
486 
487             if (mesh)
488             {
489                 auto bb = mesh.boundingBox;
490                 // TODO: transform bb with absoluteTransformation
491                 return AABB(absoluteTransformation.translation + bb.center, bb.size * matrixScale(absoluteTransformation));
492             }
493             else
494                 return aabb;
495         }
496         else
497             return aabb;
498     }
499 
500     ~this()
501     {
502         release();
503     }
504 
505     void processEvents()
506     {
507         foreach(c; components)
508         {
509             c.processEvents();
510         }
511     }
512 }
513 
514 class EntityComponent: EventListener, Updateable, Drawable
515 {
516     Entity entity;
517 
518     this(EventManager em, Entity e)
519     {
520         super(em, e);
521         entity = e;
522         entity.addComponent(this);
523     }
524 
525     // Override me
526     void update(Time t)
527     {
528     }
529 
530     // Override me
531     void render(GraphicsState* state)
532     {
533     }
534 }
535 
536 interface EntityGroup
537 {
538     int opApply(scope int delegate(Entity) dg);
539 }
540 
541 Vector3f matrixScale(Matrix4x4f m)
542 {
543     float sx = Vector3f(m.a11, m.a12, m.a13).length;
544     float sy = Vector3f(m.a21, m.a22, m.a23).length;
545     float sz = Vector3f(m.a31, m.a32, m.a33).length;
546     return Vector3f(sx, sy, sz);
547 }