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 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 rotate(Vector3f v) 327 { 328 auto r = 329 rotationQuaternion!float(Axis.x, degtorad(v.x)) * 330 rotationQuaternion!float(Axis.y, degtorad(v.y)) * 331 rotationQuaternion!float(Axis.z, degtorad(v.z)); 332 rotation *= r; 333 } 334 335 void rotate(float x, float y, float z) 336 { 337 rotate(Vector3f(x, y, z)); 338 } 339 340 void pitch(float angle) 341 { 342 rotation *= rotationQuaternion!float(Axis.x, degtorad(angle)); 343 } 344 345 void turn(float angle) 346 { 347 rotation *= rotationQuaternion!float(Axis.y, degtorad(angle)); 348 } 349 350 void roll(float angle) 351 { 352 rotation *= rotationQuaternion!float(Axis.z, degtorad(angle)); 353 } 354 355 void scale(float s) 356 { 357 scaling += Vector3f(s, s, s); 358 } 359 360 void scale(Vector3f s) 361 { 362 scaling += s; 363 } 364 365 void scaleX(float s) 366 { 367 scaling.x += s; 368 } 369 370 void scaleY(float s) 371 { 372 scaling.y += s; 373 } 374 375 void scaleZ(float s) 376 { 377 scaling.z += s; 378 } 379 380 Vector3f direction() @property 381 { 382 return transformation.forward; 383 } 384 385 Vector3f right() @property 386 { 387 return transformation.right; 388 } 389 390 Vector3f up() @property 391 { 392 return transformation.up; 393 } 394 395 Vector3f directionAbsolute() @property 396 { 397 return absoluteTransformation.forward; 398 } 399 400 Vector3f rightAbsolute() @property 401 { 402 return absoluteTransformation.right; 403 } 404 405 Vector3f upAbsolute() @property 406 { 407 return absoluteTransformation.up; 408 } 409 410 Tween* getInactiveTween() 411 { 412 Tween* inactiveTween = null; 413 foreach(i, ref t; tweens.data) 414 { 415 if (!t.active) 416 { 417 inactiveTween = &tweens.data[i]; 418 break; 419 } 420 } 421 return inactiveTween; 422 } 423 424 Tween* moveFromTo(Vector3f pointFrom, Vector3f pointTo, double duration, Easing easing = Easing.Linear) 425 { 426 Tween* existingTween = getInactiveTween(); 427 428 if (existingTween) 429 { 430 *existingTween = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing); 431 return existingTween; 432 } 433 else 434 { 435 Tween t = Tween(this, TweenType.Position, pointFrom, pointTo, duration, easing); 436 tweens.append(t); 437 return &tweens.data[$-1]; 438 } 439 } 440 441 Tween* rotateFromTo(Vector3f anglesFrom, Vector3f anglesTo, double duration, Easing easing = Easing.Linear) 442 { 443 Tween* existingTween = getInactiveTween(); 444 445 if (existingTween) 446 { 447 *existingTween = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing); 448 return existingTween; 449 } 450 else 451 { 452 Tween t = Tween(this, TweenType.Rotation, anglesFrom, anglesTo, duration, easing); 453 tweens.append(t); 454 return &tweens.data[$-1]; 455 } 456 } 457 458 Tween* scaleFromTo(Vector3f sFrom, Vector3f sTo, double duration, Easing easing = Easing.Linear) 459 { 460 Tween* existingTween = getInactiveTween(); 461 462 if (existingTween) 463 { 464 *existingTween = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing); 465 return existingTween; 466 } 467 else 468 { 469 Tween t = Tween(this, TweenType.Scaling, sFrom, sTo, duration, easing); 470 tweens.append(t); 471 return &tweens.data[$-1]; 472 } 473 } 474 475 AABB boundingBox() @property 476 { 477 if (drawable) 478 { 479 Mesh mesh = cast(Mesh)drawable; 480 Terrain terrain = cast(Terrain)drawable; 481 482 if (terrain) 483 { 484 mesh = terrain.mesh; 485 } 486 487 if (mesh) 488 { 489 auto bb = mesh.boundingBox; 490 // TODO: transform bb with absoluteTransformation 491 return AABB(absoluteTransformation.translation + bb.center, bb.size * matrixScale(absoluteTransformation)); 492 } 493 else 494 return aabb; 495 } 496 else 497 return aabb; 498 } 499 500 ~this() 501 { 502 release(); 503 } 504 505 void processEvents() 506 { 507 foreach(c; components) 508 { 509 c.processEvents(); 510 } 511 } 512 } 513 514 class EntityComponent: EventListener, Updateable, Drawable 515 { 516 Entity entity; 517 518 this(EventManager em, Entity e) 519 { 520 super(em, e); 521 entity = e; 522 entity.addComponent(this); 523 } 524 525 // Override me 526 void update(Time t) 527 { 528 } 529 530 // Override me 531 void render(GraphicsState* state) 532 { 533 } 534 } 535 536 interface EntityGroup 537 { 538 int opApply(scope int delegate(Entity) dg); 539 } 540 541 Vector3f matrixScale(Matrix4x4f m) 542 { 543 float sx = Vector3f(m.a11, m.a12, m.a13).length; 544 float sy = Vector3f(m.a21, m.a22, m.a23).length; 545 float sz = Vector3f(m.a31, m.a32, m.a33).length; 546 return Vector3f(sx, sy, sz); 547 }