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 
38 import dagon.core.libs;
39 import dagon.core.interfaces;
40 import dagon.core.ownership;
41 import dagon.core.event;
42 import dagon.logics.controller;
43 import dagon.logics.behaviour;
44 import dagon.graphics.material;
45 import dagon.graphics.rc;
46 
47 Matrix4x4f rotationPart(Matrix4x4f m)
48 {
49     Matrix4x4f res = m;
50     res.a14 = 0.0f;
51     res.a24 = 0.0f;
52     res.a34 = 0.0f;
53     return m;
54 }
55 
56 enum Attach
57 {
58     Parent,
59     Camera
60 }
61 
62 class Entity: Owner, Drawable
63 {
64     uint id;
65     uint groupID = 0;
66 
67     struct BehaviourListEntry
68     {
69         Behaviour behaviour;
70         bool valid;
71     }
72 
73     DynamicArray!BehaviourListEntry behaviours;
74     Drawable drawable;
75     EventManager eventManager;
76 
77     Entity parent = null;
78     DynamicArray!Entity children;
79 
80     Vector3f position;
81     Quaternionf rotation;
82     Vector3f scaling;
83 
84     Matrix4x4f transformation;
85     Matrix4x4f invTransformation;
86 
87     Matrix4x4f absoluteTransformation;
88     Matrix4x4f invAbsoluteTransformation;
89 
90     Matrix4x4f prevTransformation;
91     Matrix4x4f prevAbsoluteTransformation;
92 
93     EntityController controller;
94     DefaultEntityController defaultController;
95 
96     Material material;
97     RenderingContext rcLocal;
98 
99     bool visible = true;
100     bool castShadow = true;
101     Attach attach = Attach.Parent;
102 
103     bool useMotionBlur = true;
104 
105     bool clearZbuffer = false;
106 
107     int layer = 1;
108 
109     bool solid = false;
110 
111     this(EventManager emngr, Owner owner)
112     {
113         super(owner);
114         eventManager = emngr;
115 
116         transformation = Matrix4x4f.identity;
117         invTransformation = Matrix4x4f.identity;
118 
119         position = Vector3f(0, 0, 0);
120         rotation = Quaternionf.identity;
121         scaling = Vector3f(1, 1, 1);
122 
123         defaultController = New!DefaultEntityController(this);
124         controller = defaultController;
125 
126         absoluteTransformation = Matrix4x4f.identity;
127         invAbsoluteTransformation = Matrix4x4f.identity;
128         prevTransformation = Matrix4x4f.identity;
129         prevAbsoluteTransformation = Matrix4x4f.identity;
130     }
131 
132     this(Entity parent)
133     {
134         this(parent.eventManager, parent);
135         parent.children.append(this);
136         this.parent = parent;
137     }
138 
139     this(Entity parent, Owner owner)
140     {
141         this(parent.eventManager, owner);
142         parent.children.append(this);
143         this.parent = parent;
144     }
145 
146     void release()
147     {
148         behaviours.free();
149         children.free();
150     }
151 
152     ~this()
153     {
154         release();
155     }
156 
157     Vector3f absolutePosition()
158     {
159         if (parent)
160             return position * parent.transformation;
161         else
162             return position;
163     }
164 
165     Behaviour addBehaviour(Behaviour b)
166     {
167         behaviours.append(BehaviourListEntry(b, true));
168         return b;
169     }
170 
171     void removeBehaviour(Behaviour b)
172     {
173         foreach(i, ble; behaviours)
174         {
175             if (ble.behaviour is b)
176                 behaviours[i].valid = false;
177         }
178     }
179 
180     bool hasBehaviour(T)()
181     {
182         return this.behaviour!T() !is null;
183     }
184 
185     T behaviour(T)()
186     {
187         T result = null;
188 
189         foreach(i, ble; behaviours)
190         {
191             T b = cast(T)ble.behaviour;
192             if (b)
193             {
194                 result = b;
195                 break;
196             }
197         }
198 
199         return result;
200     }
201 
202     void processEvents()
203     {
204         foreach(i, ble; behaviours)
205         {
206             if (ble.valid)
207             {
208                 ble.behaviour.processEvents();
209             }
210         }
211 
212         foreach(child; children)
213         {
214             child.processEvents();
215         }
216     }
217 
218     void updateTransformation()
219     {
220         prevTransformation = transformation;
221 
222         if (controller)
223             controller.update(0.0);
224 
225         if (parent)
226         {
227             absoluteTransformation = parent.absoluteTransformation * transformation;
228             prevAbsoluteTransformation = parent.prevAbsoluteTransformation * prevTransformation;
229         }
230         else
231         {
232             absoluteTransformation = transformation;
233             prevAbsoluteTransformation = prevTransformation;
234         }
235     }
236 
237     void update(double dt)
238     {
239         updateTransformation();
240 
241         foreach(i, ble; behaviours)
242         {
243             if (ble.valid)
244             {
245                 ble.behaviour.update(dt);
246             }
247         }
248 
249         foreach(child; children)
250         {
251             child.update(dt);
252         }
253 
254         if (drawable)
255             drawable.update(dt);
256     }
257 
258     void render(RenderingContext* rc)
259     {
260         if (!visible)
261             return;
262 
263         bool transparent = false;
264         bool ignore = false;
265         if (material)
266         {
267             if (material.isTransparent || material.usesCustomShader)
268             {
269                 ignore = rc.ignoreTransparentEntities;
270                 transparent = true;
271             }
272             else
273                 ignore = rc.ignoreOpaqueEntities;
274         }
275 
276         if (!ignore)
277         foreach(i, ble; behaviours)
278         {
279             if (ble.valid)
280                 ble.behaviour.bind();
281         }
282 
283         rcLocal = *rc;
284 
285         if (!ignore)
286         {
287             rcLocal.layer = layer;
288 
289             if (attach == Attach.Camera)
290             {
291                 rcLocal.modelMatrix = translationMatrix(rcLocal.cameraPosition) * transformation;
292                 rcLocal.invModelMatrix = invTransformation * translationMatrix(-rcLocal.cameraPosition);
293 
294                 if (useMotionBlur)
295                     rcLocal.prevModelViewProjMatrix = rcLocal.projectionMatrix * (rcLocal.prevViewMatrix * (translationMatrix(rcLocal.prevCameraPosition) * prevTransformation));
296                 else
297                     rcLocal.prevModelViewProjMatrix = rcLocal.projectionMatrix * (rcLocal.viewMatrix * (translationMatrix(rcLocal.cameraPosition) * transformation));
298             }
299             else
300             {
301                 rcLocal.modelMatrix = absoluteTransformation;
302                 rcLocal.invModelMatrix = invAbsoluteTransformation;
303 
304                 if (useMotionBlur)
305                     rcLocal.prevModelViewProjMatrix = rcLocal.projectionMatrix * (rcLocal.prevViewMatrix * prevAbsoluteTransformation);
306                 else
307                     rcLocal.prevModelViewProjMatrix = rcLocal.projectionMatrix * (rcLocal.viewMatrix * absoluteTransformation);
308             }
309 
310             rcLocal.modelViewMatrix = rcLocal.viewMatrix * rcLocal.modelMatrix;
311             rcLocal.normalMatrix = rcLocal.modelViewMatrix.inverse.transposed;
312 
313             rcLocal.blurModelViewProjMatrix = rcLocal.projectionMatrix * rcLocal.modelViewMatrix;
314 
315             if (useMotionBlur)
316                 rcLocal.blurMask = 1.0f;
317             else
318                 rcLocal.blurMask = 0.0f;
319         }
320 
321         bool shouldUseOverrideMat = true;
322         if (transparent)
323             shouldUseOverrideMat = !rcLocal.shadowPass;
324 
325         if (!ignore)
326         {
327             if (rcLocal.overrideMaterial && shouldUseOverrideMat)
328                 rcLocal.overrideMaterial.bind(&rcLocal);
329             else if (material)
330                 material.bind(&rcLocal);
331 
332             if (clearZbuffer)
333                 glClear(GL_DEPTH_BUFFER_BIT);
334         }
335 
336         if (drawable)
337         {
338             Entity drawableEntity = cast(Entity)drawable;
339 
340             if (drawableEntity)
341             {
342                 auto absTrans = drawableEntity.absoluteTransformation;
343                 auto invAbsTrans = drawableEntity.invAbsoluteTransformation;
344                 auto prevAbsTrans = drawableEntity.prevAbsoluteTransformation;
345 
346                 drawableEntity.absoluteTransformation = absoluteTransformation;
347                 drawableEntity.invAbsoluteTransformation = invAbsoluteTransformation;
348                 drawableEntity.prevAbsoluteTransformation = prevAbsoluteTransformation;
349 
350                 foreach(child; drawableEntity.children)
351                 {
352                     child.updateTransformation();
353                 }
354 
355                 drawableEntity.render(&rcLocal);
356 
357                 drawableEntity.absoluteTransformation = absTrans;
358                 drawableEntity.invAbsoluteTransformation = invAbsTrans;
359                 drawableEntity.prevAbsoluteTransformation = prevAbsTrans;
360             }
361             else if (!ignore)
362             {
363                 drawable.render(&rcLocal);
364             }
365         }
366 
367         if (!ignore)
368         {
369             if (rcLocal.overrideMaterial && shouldUseOverrideMat)
370                 rcLocal.overrideMaterial.unbind(&rcLocal);
371             else if (material)
372                 material.unbind(&rcLocal);
373         }
374 
375         if (!ignore)
376         foreach(i, ble; behaviours)
377         {
378             if (ble.valid)
379                 ble.behaviour.render(&rcLocal);
380         }
381 
382         foreach(child; children)
383         {
384             child.render(&rcLocal);
385         }
386 
387         if (!ignore)
388         foreach_reverse(i, ble; behaviours.data)
389         {
390             if (ble.valid)
391                 ble.behaviour.unbind();
392         }
393     }
394 }
395 
396 unittest
397 {
398     EventManager emngr = null;
399     class B1 : Behaviour
400     {
401         this(Entity e) {super(e);}
402     }
403     class B2 : Behaviour
404     {
405         this(Entity e) {super(e);}
406     }
407     auto e = New!Entity(emngr, null);
408     New!B1(e);
409     assert(e.hasBehaviour!B1());
410     New!B2(e);
411     assert(e.hasBehaviour!B2());
412 
413     auto b1 = e.behaviour!B1();
414     assert(b1);
415     auto b2 = e.behaviour!B2();
416     assert(b2);
417 
418     // sets `valid` to false, but does not delete the behaviour
419     e.removeBehaviour(b1);
420     // ... so hasBehaviour reports true
421     assert(e.hasBehaviour!B1());
422 }