1 /* 2 Copyright (c) 2019-2020 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.graphics.entity; 29 30 import std.math; 31 32 import dlib.core.ownership; 33 import dlib.container.array; 34 import dlib.math.vector; 35 import dlib.math.matrix; 36 import dlib.math.quaternion; 37 import dlib.math.transformation; 38 import dlib.math.utils; 39 import dlib.geometry.aabb; 40 41 import dagon.core.bindings; 42 import dagon.core.event; 43 import dagon.core.time; 44 import dagon.graphics.updateable; 45 import dagon.graphics.drawable; 46 import dagon.graphics.mesh; 47 import dagon.graphics.terrain; 48 import dagon.graphics.material; 49 import dagon.graphics.tween; 50 51 class EntityManager: Owner 52 { 53 Array!Entity entities; 54 55 this(Owner owner) 56 { 57 super(owner); 58 } 59 60 void addEntity(Entity e) 61 { 62 entities.append(e); 63 } 64 65 ~this() 66 { 67 entities.free(); 68 } 69 } 70 71 enum EntityLayer: int 72 { 73 Background = 0, 74 Spatial = 1, 75 Foreground = 2 76 } 77 78 class Entity: Owner, Updateable 79 { 80 public: 81 EntityLayer layer = EntityLayer.Spatial; 82 bool visible = true; 83 bool castShadow = true; 84 bool solid = false; 85 bool dynamic = true; 86 bool decal = false; 87 bool transparent = false; 88 float opacity = 1.0f; 89 float blurMask = 1.0f; 90 91 EntityManager manager; 92 93 Entity parent = null; 94 Array!Entity children; 95 96 Array!EntityComponent components; 97 Array!Tween tweens; 98 99 Drawable drawable; 100 Material material; 101 102 Vector3f position; 103 Quaternionf rotation; 104 Vector3f scaling; 105 106 Matrix4x4f transformation; 107 Matrix4x4f invTransformation; 108 109 Matrix4x4f absoluteTransformation; 110 Matrix4x4f invAbsoluteTransformation; 111 112 Matrix4x4f prevTransformation; 113 Matrix4x4f prevAbsoluteTransformation; 114 115 Vector3f boundingBoxSize; 116 117 protected: 118 AABB aabb; 119 120 public: 121 this(Owner owner) 122 { 123 super(owner); 124 125 EntityManager mngr = cast(EntityManager)owner; 126 if (mngr) 127 { 128 manager = mngr; 129 manager.addEntity(this); 130 } 131 132 position = Vector3f(0, 0, 0); 133 rotation = Quaternionf.identity; 134 scaling = Vector3f(1, 1, 1); 135 136 transformation = Matrix4x4f.identity; 137 invTransformation = Matrix4x4f.identity; 138 139 absoluteTransformation = Matrix4x4f.identity; 140 invAbsoluteTransformation = Matrix4x4f.identity; 141 142 prevTransformation = Matrix4x4f.identity; 143 prevAbsoluteTransformation = Matrix4x4f.identity; 144 145 tweens.reserve(10); 146 147 boundingBoxSize = Vector3f(1.0f, 1.0f, 1.0f); 148 aabb = AABB(position, boundingBoxSize); 149 } 150 151 void setParent(Entity e) 152 { 153 if (parent) 154 parent.removeChild(this); 155 156 parent = e; 157 parent.addChild(this); 158 } 159 160 void addChild(Entity e) 161 { 162 if (e.parent) 163 e.parent.removeChild(e); 164 children.append(e); 165 e.parent = this; 166 } 167 168 void removeChild(Entity e) 169 { 170 children.removeFirst(e); 171 e.parent = null; 172 } 173 174 void addComponent(EntityComponent ec) 175 { 176 components.append(ec); 177 } 178 179 void removeComponent(EntityComponent ec) 180 { 181 components.removeFirst(ec); 182 } 183 184 void updateAbsoluteTransformation() 185 { 186 invTransformation = transformation.inverse; 187 188 if (parent) 189 { 190 absoluteTransformation = parent.absoluteTransformation * transformation; 191 invAbsoluteTransformation = invTransformation * parent.invAbsoluteTransformation; 192 prevAbsoluteTransformation = parent.prevAbsoluteTransformation * prevTransformation; 193 } 194 else 195 { 196 absoluteTransformation = transformation; 197 invAbsoluteTransformation = invTransformation; 198 prevAbsoluteTransformation = prevTransformation; 199 } 200 201 aabb = AABB(absoluteTransformation.translation, boundingBoxSize); 202 } 203 204 void updateTransformation() 205 { 206 prevTransformation = transformation; 207 208 transformation = 209 translationMatrix(position) * 210 rotation.toMatrix4x4 * 211 scaleMatrix(scaling); 212 213 updateAbsoluteTransformation(); 214 } 215 216 void updateTransformationDeep() 217 { 218 if (parent) 219 parent.updateTransformationDeep(); 220 updateTransformation(); 221 } 222 223 void updateTransformationTopDown() 224 { 225 updateTransformation(); 226 227 foreach(child; children) 228 { 229 child.updateTransformationTopDown(); 230 } 231 } 232 233 void update(Time t) 234 { 235 foreach(i, ref tween; tweens.data) 236 { 237 tween.update(t.delta); 238 } 239 240 updateTransformation(); 241 242 foreach(c; components) 243 { 244 c.update(t); 245 } 246 } 247 248 void release() 249 { 250 if (parent) 251 parent.removeChild(this); 252 253 for (size_t i = 0; i < children.data.length; i++) 254 children.data[i].parent = null; 255 256 children.free(); 257 components.free(); 258 tweens.free(); 259 } 260 261 Vector3f positionAbsolute() 262 { 263 return absoluteTransformation.translation; 264 } 265 266 Quaternionf rotationAbsolute() 267 { 268 if (parent) 269 return parent.rotationAbsolute * rotation; 270 else 271 return rotation; 272 } 273 274 void translate(Vector3f v) 275 { 276 position += v; 277 } 278 279 void translate(float vx, float vy, float vz) 280 { 281 position += Vector3f(vx, vy, vz); 282 } 283 284 void move(float speed) 285 { 286 position += transformation.forward * speed; 287 } 288 289 void moveToPoint(Vector3f p, float speed) 290 { 291 Vector3f dir = (p - position).normalized; 292 float d = distance(p, position); 293 if (d > speed) 294 position += dir * speed; 295 else 296 position += dir * d; 297 } 298 299 void strafe(float speed) 300 { 301 position += transformation.right * speed; 302 } 303 304 void lift(float speed) 305 { 306 position += transformation.up * speed; 307 } 308 309 void angles(Vector3f v) 310 { 311 rotation = 312 rotationQuaternion!float(Axis.x, degtorad(v.x)) * 313 rotationQuaternion!float(Axis.y, degtorad(v.y)) * 314 rotationQuaternion!float(Axis.z, degtorad(v.z)); 315 } 316 317 void rotate(Vector3f v) 318 { 319 auto r = 320 rotationQuaternion!float(Axis.x, degtorad(v.x)) * 321 rotationQuaternion!float(Axis.y, degtorad(v.y)) * 322 rotationQuaternion!float(Axis.z, degtorad(v.z)); 323 rotation *= r; 324 } 325 326 void rotate(float x, float y, float z) 327 { 328 rotate(Vector3f(x, y, z)); 329 } 330 331 void pitch(float angle) 332 { 333 rotation *= rotationQuaternion!float(Axis.x, degtorad(angle)); 334 } 335 336 void turn(float angle) 337 { 338 rotation *= rotationQuaternion!float(Axis.y, degtorad(angle)); 339 } 340 341 void roll(float angle) 342 { 343 rotation *= rotationQuaternion!float(Axis.z, degtorad(angle)); 344 } 345 346 void scale(float s) 347 { 348 scaling += Vector3f(s, s, s); 349 } 350 351 void scale(Vector3f s) 352 { 353 scaling += s; 354 } 355 356 void scaleX(float s) 357 { 358 scaling.x += s; 359 } 360 361 void scaleY(float s) 362 { 363 scaling.y += s; 364 } 365 366 void scaleZ(float s) 367 { 368 scaling.z += s; 369 } 370 371 Vector3f direction() @property 372 { 373 return transformation.forward; 374 } 375 376 Vector3f right() @property 377 { 378 return transformation.right; 379 } 380 381 Vector3f up() @property 382 { 383 return transformation.up; 384 } 385 386 Vector3f directionAbsolute() @property 387 { 388 return absoluteTransformation.forward; 389 } 390 391 Vector3f rightAbsolute() @property 392 { 393 return absoluteTransformation.right; 394 } 395 396 Vector3f upAbsolute() @property 397 { 398 return absoluteTransformation.up; 399 } 400 401 Tween* getInactiveTween() 402 { 403 Tween* inactiveTween = null; 404 foreach(i, ref t; tweens.data) 405 { 406 if (!t.active) 407 { 408 inactiveTween = &tweens.data[i]; 409 break; 410 } 411 } 412 return inactiveTween; 413 } 414 415 Tween* moveFromTo(Vector3f pointFrom, Vector3f pointTo, double duration, Easing easing = Easing.Linear) 416 { 417 Tween* existingTween = getInactiveTween(); 418 419 if (existingTween) 420 { 421 *existingTween = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing); 422 return existingTween; 423 } 424 else 425 { 426 Tween t = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing); 427 tweens.append(t); 428 return &tweens.data[$-1]; 429 } 430 } 431 432 Tween* rotateFromTo(Vector3f anglesFrom, Vector3f anglesTo, double duration, Easing easing = Easing.Linear) 433 { 434 Tween* existingTween = getInactiveTween(); 435 436 if (existingTween) 437 { 438 *existingTween = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing); 439 return existingTween; 440 } 441 else 442 { 443 Tween t = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing); 444 tweens.append(t); 445 return &tweens.data[$-1]; 446 } 447 } 448 449 Tween* scaleFromTo(Vector3f sFrom, Vector3f sTo, double duration, Easing easing = Easing.Linear) 450 { 451 Tween* existingTween = getInactiveTween(); 452 453 if (existingTween) 454 { 455 *existingTween = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing); 456 return existingTween; 457 } 458 else 459 { 460 Tween t = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing); 461 tweens.append(t); 462 return &tweens.data[$-1]; 463 } 464 } 465 466 AABB boundingBox() @property 467 { 468 if (drawable) 469 { 470 Mesh mesh = cast(Mesh)drawable; 471 Terrain terrain = cast(Terrain)drawable; 472 473 if (terrain) 474 { 475 mesh = terrain.mesh; 476 } 477 478 if (mesh) 479 { 480 auto bb = mesh.boundingBox; 481 // TODO: transform bb with absoluteTransformation 482 return AABB(absoluteTransformation.translation + bb.center, bb.size * matrixScale(absoluteTransformation)); 483 } 484 else 485 return aabb; 486 } 487 else 488 return aabb; 489 } 490 491 ~this() 492 { 493 release(); 494 } 495 496 void processEvents() 497 { 498 foreach(c; components) 499 { 500 c.processEvents(); 501 } 502 } 503 } 504 505 class EntityComponent: EventListener, Updateable, Drawable 506 { 507 Entity entity; 508 509 this(EventManager em, Entity e) 510 { 511 super(em, e); 512 entity = e; 513 entity.addComponent(this); 514 } 515 516 // Override me 517 void update(Time t) 518 { 519 } 520 521 // Override me 522 void render(GraphicsState* state) 523 { 524 } 525 } 526 527 interface EntityGroup 528 { 529 int opApply(scope int delegate(Entity) dg); 530 } 531 532 Vector3f matrixScale(Matrix4x4f m) 533 { 534 float sx = Vector3f(m.a11, m.a12, m.a13).length; 535 float sy = Vector3f(m.a21, m.a22, m.a23).length; 536 float sz = Vector3f(m.a31, m.a32, m.a33).length; 537 return Vector3f(sx, sy, sz); 538 }