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