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 }