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 }