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