1 /*
2 Copyright (c) 2017-2018 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.logics.entity;
29 
30 import dlib.core.memory;
31 import dlib.container.array;
32 
33 import dlib.math.vector;
34 import dlib.math.matrix;
35 import dlib.math.transformation;
36 import dlib.math.quaternion;
37 import dlib.math.utils;
38 
39 import dagon.core.libs;
40 import dagon.core.interfaces;
41 import dagon.core.ownership;
42 import dagon.core.event;
43 import dagon.logics.controller;
44 import dagon.logics.behaviour;
45 import dagon.logics.tween;
46 import dagon.graphics.material;
47 import dagon.graphics.rc;
48 
49 Matrix4x4f rotationPart(Matrix4x4f m)
50 {
51     Matrix4x4f res = m;
52     res.a14 = 0.0f;
53     res.a24 = 0.0f;
54     res.a34 = 0.0f;
55     return m;
56 }
57 
58 enum Attach
59 {
60     Parent,
61     Camera
62 }
63 
64 class Entity: Owner, Drawable
65 {
66     uint id;
67     uint groupID = 0;
68 
69     struct BehaviourListEntry
70     {
71         Behaviour behaviour;
72         bool valid;
73     }
74 
75     DynamicArray!BehaviourListEntry behaviours;
76     DynamicArray!Tween tweens;
77 
78     Drawable drawable;
79     EventManager eventManager;
80 
81     Entity parent = null;
82     DynamicArray!Entity children;
83 
84     Vector3f position;
85     Quaternionf rotation;
86     Vector3f scaling;
87 
88     bool swapZY = false;
89 
90     Vector3f angles;
91     bool useRotationAngles = true;
92 
93     Matrix4x4f transformation;
94     Matrix4x4f invTransformation;
95 
96     Matrix4x4f absoluteTransformation;
97     Matrix4x4f invAbsoluteTransformation;
98 
99     Matrix4x4f prevTransformation;
100     Matrix4x4f prevAbsoluteTransformation;
101 
102     EntityController controller;
103 
104     Material material;
105     RenderingContext rcLocal;
106 
107     bool visible = true;
108     bool castShadow = true;
109     Attach attach = Attach.Parent;
110 
111     bool useMotionBlur = true;
112 
113     bool clearZbuffer = false;
114 
115     int layer = 1;
116 
117     bool solid = false;
118 
119     bool dynamic = true;
120 
121     this(EventManager emngr, Owner owner)
122     {
123         super(owner);
124         eventManager = emngr;
125 
126         transformation = Matrix4x4f.identity;
127         invTransformation = Matrix4x4f.identity;
128 
129         position = Vector3f(0, 0, 0);
130         rotation = Quaternionf.identity;
131         scaling = Vector3f(1, 1, 1);
132 
133         angles = Vector3f(0, 0, 0);
134 
135         absoluteTransformation = Matrix4x4f.identity;
136         invAbsoluteTransformation = Matrix4x4f.identity;
137         prevTransformation = Matrix4x4f.identity;
138         prevAbsoluteTransformation = Matrix4x4f.identity;
139 
140         tweens.reserve(10);
141     }
142 
143     this(Entity parent)
144     {
145         this(parent.eventManager, parent);
146         parent.children.append(this);
147         this.parent = parent;
148     }
149 
150     this(Entity parent, Owner owner)
151     {
152         this(parent.eventManager, owner);
153         parent.children.append(this);
154         this.parent = parent;
155     }
156 
157     void removeChild(Entity e)
158     {
159         children.removeFirst(e);
160     }
161 
162     void release()
163     {
164         if (parent)
165             parent.removeChild(this);
166 
167         behaviours.free();
168 
169         for (size_t i = 0; i < children.data.length; i++)
170             children.data[i].parent = null;
171 
172         children.free();
173 
174         tweens.free();
175     }
176 
177     ~this()
178     {
179         release();
180     }
181 
182     Vector3f absolutePosition()
183     {
184         if (parent)
185             return position * parent.transformation;
186         else
187             return position;
188     }
189 
190     void translate(Vector3f v)
191     {
192         position += v;
193     }
194 
195     void translate(float vx, float vy, float vz)
196     {
197         position += Vector3f(vx, vy, vz);
198     }
199 
200     void move(float speed)
201     {
202         position += transformation.forward * speed;
203     }
204 
205     void moveToPoint(Vector3f p, float speed)
206     {
207         Vector3f dir = (p - position).normalized;
208         float d = distance(p, position);
209         if (d > speed)
210             position += dir * speed;
211         else
212             position += dir * d;
213     }
214 
215     void strafe(float speed)
216     {
217         position += transformation.right * speed;
218     }
219 
220     void lift(float speed)
221     {
222         position += transformation.up * speed;
223     }
224 
225     void rotate(Vector3f angles)
226     {
227         this.angles += angles;
228     }
229 
230     void rotate(float pitch, float turn, float roll)
231     {
232         this.angles += Vector3f(pitch, turn, roll);
233     }
234 
235     void pitch(float angle)
236     {
237         angles.x += angle;
238     }
239 
240     void turn(float angle)
241     {
242         angles.y += angle;
243     }
244 
245     void roll(float angle)
246     {
247         angles.z += angle;
248     }
249     
250     void scale(float s)
251     {
252         scaling += Vector3f(s, s, s);
253     }
254     
255     void scale(Vector3f s)
256     {
257         scaling += s;
258     }
259     
260     void scaleX(float s)
261     {
262         scaling.x += s;
263     }
264     
265     void scaleY(float s)
266     {
267         scaling.y += s;
268     }
269     
270     void scaleZ(float s)
271     {
272         scaling.z += s;
273     }
274 
275     Vector3f direction() @property
276     {
277         return transformation.forward;
278     }
279 
280     Vector3f right() @property
281     {
282         return transformation.right;
283     }
284 
285     Vector3f up() @property
286     {
287         return transformation.up;
288     }
289 
290     Behaviour addBehaviour(Behaviour b)
291     {
292         behaviours.append(BehaviourListEntry(b, true));
293         return b;
294     }
295 
296     void removeBehaviour(Behaviour b)
297     {
298         foreach(i, ble; behaviours)
299         {
300             if (ble.behaviour is b)
301                 behaviours[i].valid = false;
302         }
303     }
304 
305     bool hasBehaviour(T)()
306     {
307         return this.behaviour!T() !is null;
308     }
309 
310     T behaviour(T)()
311     {
312         T result = null;
313 
314         foreach(i, ble; behaviours)
315         {
316             T b = cast(T)ble.behaviour;
317             if (b)
318             {
319                 result = b;
320                 break;
321             }
322         }
323 
324         return result;
325     }
326 
327     Tween* getInactiveTween()
328     {
329         Tween* inactiveTween = null;
330         foreach(i, ref t; tweens.data)
331         {
332             if (!t.active)
333             {
334                 inactiveTween = &tweens.data[i];
335                 break;
336             }
337         }
338         return inactiveTween;
339     }
340 
341     Tween* moveFromTo(Vector3f pointFrom, Vector3f pointTo, double duration, Easing easing = Easing.Linear)
342     {
343         Tween* existingTween = getInactiveTween();
344 
345         if (existingTween)
346         {
347             *existingTween = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing);
348             return existingTween;
349         }
350         else
351         {
352             Tween t = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing);
353             tweens.append(t);
354             return &tweens.data[$-1];
355         }
356     }
357 
358     Tween* moveFrom(Vector3f point, double duration, Easing easing = Easing.Linear)
359     {
360         return moveFromTo(point, position, duration, easing);
361     }
362 
363     Tween* moveTo(Vector3f point, double duration, Easing easing = Easing.Linear)
364     {
365         return moveFromTo(position, point, duration, easing);
366     }
367     
368     Tween* rotateFromTo(Vector3f anglesFrom, Vector3f anglesTo, double duration, Easing easing = Easing.Linear)
369     {
370         Tween* existingTween = getInactiveTween();
371 
372         if (existingTween)
373         {
374             *existingTween = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing);
375             return existingTween;
376         }
377         else
378         {
379             Tween t = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing);
380             tweens.append(t);
381             return &tweens.data[$-1];
382         }
383     }
384 
385     Tween* rotateFrom(Vector3f anglesFrom, double duration, Easing easing = Easing.Linear)
386     {
387         return rotateFromTo(anglesFrom, angles, duration, easing);
388     }
389 
390     Tween* rotateTo(Vector3f anglesTo, double duration, Easing easing = Easing.Linear)
391     {
392         return rotateFromTo(angles, anglesTo, duration, easing);
393     }
394     
395     Tween* scaleFromTo(Vector3f sFrom, Vector3f sTo, double duration, Easing easing = Easing.Linear)
396     {
397         Tween* existingTween = getInactiveTween();
398 
399         if (existingTween)
400         {
401             *existingTween = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing);
402             return existingTween;
403         }
404         else
405         {
406             Tween t = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing);
407             tweens.append(t);
408             return &tweens.data[$-1];
409         }
410     }
411 
412     Tween* scaleFrom(Vector3f sFrom, double duration, Easing easing = Easing.Linear)
413     {
414         return scaleFromTo(sFrom, scaling, duration, easing);
415     }
416 
417     Tween* scaleTo(Vector3f sTo, double duration, Easing easing = Easing.Linear)
418     {
419         return scaleFromTo(scaling, sTo, duration, easing);
420     }
421 
422     void processEvents()
423     {
424         foreach(i, ble; behaviours)
425         {
426             if (ble.valid)
427             {
428                 ble.behaviour.processEvents();
429             }
430         }
431 
432         foreach(child; children)
433         {
434             child.processEvents();
435         }
436     }
437 
438     void updateTransformation(double dt)
439     {
440         prevTransformation = transformation;
441 
442         if (controller)
443             controller.update(dt);
444         else
445         {
446             Quaternionf rot = rotation;
447             
448             if (useRotationAngles)
449                 rot *= rotationQuaternion!float(Axis.x, degtorad(angles.x)) *
450                        rotationQuaternion!float(Axis.y, degtorad(angles.y)) * 
451                        rotationQuaternion!float(Axis.z, degtorad(angles.z));
452 
453             transformation =
454                 translationMatrix(position) *
455                 rot.toMatrix4x4 *
456                 scaleMatrix(scaling);
457 
458             if (swapZY)
459                 transformation = transformation * rotationMatrix(Axis.x, degtorad(90.0f));
460 
461             invTransformation = transformation.inverse;
462         }
463 
464         if (parent)
465         {
466             absoluteTransformation = parent.absoluteTransformation * transformation;
467             prevAbsoluteTransformation = parent.prevAbsoluteTransformation * prevTransformation;
468         }
469         else
470         {
471             absoluteTransformation = transformation;
472             prevAbsoluteTransformation = prevTransformation;
473         }
474     }
475 
476     void update(double dt)
477     {
478         foreach(i, ref tween; tweens.data)
479         {
480             tween.update(dt);
481         }
482 
483         updateTransformation(dt);
484 
485         foreach(i, ble; behaviours)
486         {
487             if (ble.valid)
488             {
489                 ble.behaviour.update(dt);
490             }
491         }
492 
493         foreach(child; children)
494         {
495             child.update(dt);
496         }
497 
498         if (drawable)
499             drawable.update(dt);
500     }
501 
502     void render(RenderingContext* rc)
503     {
504         render(rc, false);
505     }
506 
507     void render(RenderingContext* rc, bool renderChildren)
508     {
509         if (!visible)
510             return;
511 
512         bool transparent = false;
513         bool ignore = false;
514         if (material)
515         {
516             if (material.isTransparent || material.usesCustomShader)
517             {
518                 ignore = rc.ignoreTransparentEntities;
519                 transparent = true;
520             }
521             else
522                 ignore = rc.ignoreOpaqueEntities;
523         }
524 
525         if (!ignore)
526         foreach(i, ble; behaviours)
527         {
528             if (ble.valid)
529                 ble.behaviour.bind();
530         }
531 
532         rcLocal = *rc;
533 
534         if (!ignore)
535         {
536             rcLocal.layer = layer;
537 
538             if (attach == Attach.Camera)
539             {
540                 rcLocal.modelMatrix = translationMatrix(rcLocal.cameraPosition) * transformation;
541                 rcLocal.invModelMatrix = invTransformation * translationMatrix(-rcLocal.cameraPosition);
542 
543                 if (useMotionBlur)
544                     rcLocal.prevModelViewProjMatrix = rcLocal.projectionMatrix * (rcLocal.prevViewMatrix * (translationMatrix(rcLocal.prevCameraPosition) * prevTransformation));
545                 else
546                     rcLocal.prevModelViewProjMatrix = rcLocal.projectionMatrix * (rcLocal.viewMatrix * (translationMatrix(rcLocal.cameraPosition) * transformation));
547             }
548             else
549             {
550                 rcLocal.modelMatrix = absoluteTransformation;
551                 rcLocal.invModelMatrix = invTransformation; //TODO: parent transformation
552 
553                 if (useMotionBlur)
554                     rcLocal.prevModelViewProjMatrix = rcLocal.projectionMatrix * (rcLocal.prevViewMatrix * prevAbsoluteTransformation);
555                 else
556                     rcLocal.prevModelViewProjMatrix = rcLocal.projectionMatrix * (rcLocal.viewMatrix * absoluteTransformation);
557             }
558 
559             rcLocal.modelViewMatrix = rcLocal.viewMatrix * rcLocal.modelMatrix;
560             rcLocal.normalMatrix = rcLocal.modelViewMatrix.inverse.transposed;
561 
562             rcLocal.blurModelViewProjMatrix = rcLocal.projectionMatrix * rcLocal.modelViewMatrix;
563 
564             if (useMotionBlur)
565                 rcLocal.blurMask = 1.0f;
566             else
567                 rcLocal.blurMask = 0.0f;
568         }
569 
570         bool shouldUseOverrideMat = true;
571         if (transparent)
572             shouldUseOverrideMat = !rcLocal.shadowPass;
573 
574         if (!ignore)
575         {
576             if (rcLocal.overrideMaterial && shouldUseOverrideMat)
577                 rcLocal.overrideMaterial.bind(&rcLocal);
578             else if (material)
579                 material.bind(&rcLocal);
580 
581             if (clearZbuffer)
582                 glClear(GL_DEPTH_BUFFER_BIT);
583         }
584 
585         if (drawable)
586         {
587             Entity drawableEntity = cast(Entity)drawable;
588 
589             if (drawableEntity)
590             {
591                 auto absTrans = drawableEntity.absoluteTransformation;
592                 auto invAbsTrans = drawableEntity.invAbsoluteTransformation;
593                 auto prevAbsTrans = drawableEntity.prevAbsoluteTransformation;
594 
595                 drawableEntity.absoluteTransformation = absoluteTransformation;
596                 drawableEntity.invAbsoluteTransformation = invAbsoluteTransformation;
597                 drawableEntity.prevAbsoluteTransformation = prevAbsoluteTransformation;
598 
599                 foreach(child; drawableEntity.children)
600                 {
601                     child.updateTransformation(0.0);
602                 }
603 
604                 drawableEntity.render(&rcLocal, true);
605 
606                 drawableEntity.absoluteTransformation = absTrans;
607                 drawableEntity.invAbsoluteTransformation = invAbsTrans;
608                 drawableEntity.prevAbsoluteTransformation = prevAbsTrans;
609             }
610             else if (!ignore)
611             {
612                 drawable.render(&rcLocal);
613             }
614         }
615 
616         if (!ignore)
617         {
618             if (rcLocal.overrideMaterial && shouldUseOverrideMat)
619                 rcLocal.overrideMaterial.unbind(&rcLocal);
620             else if (material)
621                 material.unbind(&rcLocal);
622         }
623 
624         if (!ignore)
625         foreach(i, ble; behaviours)
626         {
627             if (ble.valid)
628                 ble.behaviour.render(&rcLocal);
629         }
630 
631         if (renderChildren)
632         foreach(child; children)
633         {
634             child.render(&rcLocal);
635         }
636 
637         if (!ignore)
638         foreach_reverse(i, ble; behaviours.data)
639         {
640             if (ble.valid)
641                 ble.behaviour.unbind();
642         }
643     }
644 }
645 
646 unittest
647 {
648     EventManager emngr = null;
649     class B1 : Behaviour
650     {
651         this(Entity e) {super(e);}
652     }
653     class B2 : Behaviour
654     {
655         this(Entity e) {super(e);}
656     }
657     auto e = New!Entity(emngr, null);
658     New!B1(e);
659     assert(e.hasBehaviour!B1());
660     New!B2(e);
661     assert(e.hasBehaviour!B2());
662 
663     auto b1 = e.behaviour!B1();
664     assert(b1);
665     auto b2 = e.behaviour!B2();
666     assert(b2);
667 
668     // sets `valid` to false, but does not delete the behaviour
669     e.removeBehaviour(b1);
670     // ... so hasBehaviour reports true
671     assert(e.hasBehaviour!B1());
672 }