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