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 }