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