1 /* 2 Copyright (c) 2019 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.resource.scene; 29 30 import std.path; 31 32 import dlib.core.memory; 33 import dlib.core.ownership; 34 import dlib.math.vector; 35 36 import dagon.core.application; 37 import dagon.core.bindings; 38 import dagon.core.event; 39 import dagon.core.time; 40 41 import dagon.graphics.entity; 42 import dagon.graphics.camera; 43 import dagon.graphics.light; 44 import dagon.graphics.environment; 45 import dagon.graphics.shapes; 46 import dagon.graphics.material; 47 import dagon.graphics.cubemap; 48 49 import dagon.resource.asset; 50 import dagon.resource.obj; 51 import dagon.resource.image; 52 import dagon.resource.texture; 53 //import dagon.resource.font; 54 import dagon.resource.text; 55 import dagon.resource.binary; 56 import dagon.resource.packageasset; 57 58 class Scene: EventListener 59 { 60 Application application; 61 AssetManager assetManager; 62 EntityManager entityManager; 63 EntityGroupSpatial spatial; 64 EntityGroupSpatialOpaque spatialOpaqueStatic; 65 EntityGroupSpatialOpaque spatialOpaqueDynamic; 66 EntityGroupSpatialTransparent spatialTransparent; 67 EntityGroupBackground background; 68 EntityGroupForeground foreground; 69 EntityGroupLights lights; 70 EntityGroupSunLights sunLights; 71 EntityGroupAreaLights areaLights; 72 EntityGroupDecals decals; 73 Environment environment; 74 ShapeBox decalShape; 75 bool isLoading = false; 76 bool loaded = false; 77 bool canRender = false; 78 79 this(Application application) 80 { 81 super(application.eventManager, application); 82 this.application = application; 83 entityManager = New!EntityManager(this); 84 spatial = New!EntityGroupSpatial(entityManager, this); 85 spatialOpaqueStatic = New!EntityGroupSpatialOpaque(entityManager, false, this); 86 spatialOpaqueDynamic = New!EntityGroupSpatialOpaque(entityManager, true, this); 87 spatialTransparent = New!EntityGroupSpatialTransparent(entityManager, this); 88 background = New!EntityGroupBackground(entityManager, this); 89 foreground = New!EntityGroupForeground(entityManager, this); 90 lights = New!EntityGroupLights(entityManager, this); 91 sunLights = New!EntityGroupSunLights(entityManager, this); 92 areaLights = New!EntityGroupAreaLights(entityManager, this); 93 decals = New!EntityGroupDecals(entityManager, this); 94 95 environment = New!Environment(this); 96 decalShape = New!ShapeBox(Vector3f(1, 1, 1), this); 97 98 assetManager = New!AssetManager(eventManager, this); 99 beforeLoad(); 100 isLoading = true; 101 assetManager.loadThreadSafePart(); 102 } 103 104 // Set preload to true if you want to load the asset immediately 105 // before actual loading (e.g., to render a loading screen) 106 Asset addAsset(Asset asset, string filename, bool preload = false) 107 { 108 if (preload) 109 assetManager.preloadAsset(asset, filename); 110 else 111 assetManager.addAsset(asset, filename); 112 return asset; 113 } 114 115 ImageAsset addImageAsset(string filename, bool preload = false) 116 { 117 ImageAsset img; 118 if (assetManager.assetExists(filename)) 119 img = cast(ImageAsset)assetManager.getAsset(filename); 120 else 121 { 122 img = New!ImageAsset(assetManager.imageFactory, assetManager.hdrImageFactory, assetManager); 123 addAsset(img, filename, preload); 124 } 125 return img; 126 } 127 128 TextureAsset addTextureAsset(string filename, bool preload = false) 129 { 130 TextureAsset tex; 131 if (assetManager.assetExists(filename)) 132 tex = cast(TextureAsset)assetManager.getAsset(filename); 133 else 134 { 135 tex = New!TextureAsset(assetManager.imageFactory, assetManager.hdrImageFactory, assetManager); 136 addAsset(tex, filename, preload); 137 } 138 return tex; 139 } 140 141 OBJAsset addOBJAsset(string filename, bool preload = false) 142 { 143 OBJAsset obj; 144 if (assetManager.assetExists(filename)) 145 obj = cast(OBJAsset)assetManager.getAsset(filename); 146 else 147 { 148 obj = New!OBJAsset(assetManager); 149 addAsset(obj, filename, preload); 150 } 151 return obj; 152 } 153 154 TextAsset addTextAsset(string filename, bool preload = false) 155 { 156 TextAsset text; 157 if (assetManager.assetExists(filename)) 158 text = cast(TextAsset)assetManager.getAsset(filename); 159 else 160 { 161 text = New!TextAsset(assetManager); 162 addAsset(text, filename, preload); 163 } 164 return text; 165 } 166 167 BinaryAsset addBinaryAsset(string filename, bool preload = false) 168 { 169 BinaryAsset bin; 170 if (assetManager.assetExists(filename)) 171 bin = cast(BinaryAsset)assetManager.getAsset(filename); 172 else 173 { 174 bin = New!BinaryAsset(assetManager); 175 addAsset(bin, filename, preload); 176 } 177 return bin; 178 } 179 180 PackageAsset addPackageAsset(string filename, bool preload = false) 181 { 182 PackageAsset pa; 183 if (assetManager.assetExists(filename)) 184 pa = cast(PackageAsset)assetManager.getAsset(filename); 185 else 186 { 187 pa = New!PackageAsset(this, assetManager); 188 addAsset(pa, filename, preload); 189 } 190 return pa; 191 } 192 193 Material addMaterial() 194 { 195 return New!Material(assetManager); 196 } 197 198 Material addDecalMaterial() 199 { 200 auto mat = addMaterial(); 201 mat.blending = Transparent; 202 mat.depthWrite = false; 203 mat.culling = false; 204 return mat; 205 } 206 207 Cubemap addCubemap(uint size) 208 { 209 return New!Cubemap(size, assetManager); 210 } 211 212 Entity addEntity(Entity parent = null) 213 { 214 Entity e = New!Entity(entityManager); 215 if (parent) 216 e.setParent(parent); 217 return e; 218 } 219 220 Entity useEntity(Entity e) 221 { 222 entityManager.addEntity(e); 223 return e; 224 } 225 226 Entity addEntityHUD(Entity parent = null) 227 { 228 Entity e = New!Entity(entityManager); 229 e.layer = EntityLayer.Foreground; 230 if (parent) 231 e.setParent(parent); 232 return e; 233 } 234 235 Camera addCamera(Entity parent = null) 236 { 237 Camera c = New!Camera(entityManager); 238 if (parent) 239 c.setParent(parent); 240 return c; 241 } 242 243 Light addLight(LightType type, Entity parent = null) 244 { 245 Light light = New!Light(entityManager); 246 if (parent) 247 light.setParent(parent); 248 light.type = type; 249 return light; 250 } 251 252 Entity addDecal(Entity parent = null) 253 { 254 Entity e = New!Entity(entityManager); 255 e.decal = true; 256 e.drawable = decalShape; 257 if (parent) 258 e.setParent(parent); 259 return e; 260 } 261 262 // Override me 263 void beforeLoad() 264 { 265 } 266 267 // Override me 268 void onLoad(Time t, float progress) 269 { 270 } 271 272 // Override me 273 void afterLoad() 274 { 275 } 276 277 // Override me 278 void onUpdate(Time t) 279 { 280 } 281 282 import std.stdio; 283 284 void update(Time t) 285 { 286 processEvents(); 287 288 if (isLoading) 289 { 290 onLoad(t, assetManager.nextLoadingPercentage); 291 isLoading = assetManager.isLoading; 292 } 293 else 294 { 295 if (!loaded) 296 { 297 assetManager.loadThreadUnsafePart(); 298 debug writeln("Scene loaded"); 299 loaded = true; 300 afterLoad(); 301 302 onLoad(t, 1.0f); 303 304 canRender = true; 305 } 306 307 onUpdate(t); 308 309 foreach(e; entityManager.entities) 310 { 311 e.update(t); 312 } 313 } 314 } 315 } 316 317 class EntityGroupSpatial: Owner, EntityGroup 318 { 319 EntityManager entityManager; 320 321 this(EntityManager entityManager, Owner owner) 322 { 323 super(owner); 324 this.entityManager = entityManager; 325 } 326 327 int opApply(scope int delegate(Entity) dg) 328 { 329 int res = 0; 330 auto entities = entityManager.entities.data; 331 for(size_t i = 0; i < entities.length; i++) 332 { 333 auto e = entities[i]; 334 if (e.layer == EntityLayer.Spatial && !e.decal) 335 { 336 res = dg(e); 337 if (res) 338 break; 339 } 340 } 341 return res; 342 } 343 } 344 345 class EntityGroupDecals: Owner, EntityGroup 346 { 347 EntityManager entityManager; 348 349 this(EntityManager entityManager, Owner owner) 350 { 351 super(owner); 352 this.entityManager = entityManager; 353 } 354 355 int opApply(scope int delegate(Entity) dg) 356 { 357 int res = 0; 358 auto entities = entityManager.entities.data; 359 for(size_t i = 0; i < entities.length; i++) 360 { 361 auto e = entities[i]; 362 if (e.decal) 363 { 364 res = dg(e); 365 if (res) 366 break; 367 } 368 } 369 return res; 370 } 371 } 372 373 class EntityGroupSpatialOpaque: Owner, EntityGroup 374 { 375 EntityManager entityManager; 376 bool dynamic = true; 377 378 this(EntityManager entityManager, bool dynamic, Owner owner) 379 { 380 super(owner); 381 this.entityManager = entityManager; 382 this.dynamic = dynamic; 383 } 384 385 int opApply(scope int delegate(Entity) dg) 386 { 387 int res = 0; 388 auto entities = entityManager.entities.data; 389 for(size_t i = 0; i < entities.length; i++) 390 { 391 auto e = entities[i]; 392 if (e.layer == EntityLayer.Spatial && !e.decal) 393 { 394 bool opaque = true; 395 if (e.material) 396 opaque = !e.material.isTransparent; 397 398 if (opaque && e.dynamic == dynamic) 399 { 400 res = dg(e); 401 if (res) 402 break; 403 } 404 } 405 } 406 return res; 407 } 408 } 409 410 class EntityGroupSpatialTransparent: Owner, EntityGroup 411 { 412 EntityManager entityManager; 413 414 this(EntityManager entityManager, Owner owner) 415 { 416 super(owner); 417 this.entityManager = entityManager; 418 } 419 420 int opApply(scope int delegate(Entity) dg) 421 { 422 int res = 0; 423 auto entities = entityManager.entities.data; 424 for(size_t i = 0; i < entities.length; i++) 425 { 426 auto e = entities[i]; 427 if (e.layer == EntityLayer.Spatial && !e.decal) 428 { 429 bool transparent = false; 430 if (e.material) 431 transparent = e.material.isTransparent; 432 433 if (transparent) 434 { 435 res = dg(e); 436 if (res) 437 break; 438 } 439 } 440 } 441 return res; 442 } 443 } 444 445 class EntityGroupBackground: Owner, EntityGroup 446 { 447 EntityManager entityManager; 448 449 this(EntityManager entityManager, Owner owner) 450 { 451 super(owner); 452 this.entityManager = entityManager; 453 } 454 455 int opApply(scope int delegate(Entity) dg) 456 { 457 int res = 0; 458 auto entities = entityManager.entities.data; 459 for(size_t i = 0; i < entities.length; i++) 460 { 461 auto e = entities[i]; 462 if (e.layer == EntityLayer.Background) 463 { 464 res = dg(e); 465 if (res) 466 break; 467 } 468 } 469 return res; 470 } 471 } 472 473 class EntityGroupForeground: Owner, EntityGroup 474 { 475 EntityManager entityManager; 476 477 this(EntityManager entityManager, Owner owner) 478 { 479 super(owner); 480 this.entityManager = entityManager; 481 } 482 483 int opApply(scope int delegate(Entity) dg) 484 { 485 int res = 0; 486 auto entities = entityManager.entities.data; 487 for(size_t i = 0; i < entities.length; i++) 488 { 489 auto e = entities[i]; 490 if (e.layer == EntityLayer.Foreground) 491 { 492 res = dg(e); 493 if (res) 494 break; 495 } 496 } 497 return res; 498 } 499 } 500 501 class EntityGroupLights: Owner, EntityGroup 502 { 503 EntityManager entityManager; 504 505 this(EntityManager entityManager, Owner owner) 506 { 507 super(owner); 508 this.entityManager = entityManager; 509 } 510 511 int opApply(scope int delegate(Entity) dg) 512 { 513 int res = 0; 514 auto entities = entityManager.entities.data; 515 for(size_t i = 0; i < entities.length; i++) 516 { 517 auto e = entities[i]; 518 Light light = cast(Light)e; 519 if (light) 520 { 521 res = dg(e); 522 if (res) 523 break; 524 } 525 } 526 return res; 527 } 528 } 529 530 class EntityGroupSunLights: Owner, EntityGroup 531 { 532 EntityManager entityManager; 533 534 this(EntityManager entityManager, Owner owner) 535 { 536 super(owner); 537 this.entityManager = entityManager; 538 } 539 540 int opApply(scope int delegate(Entity) dg) 541 { 542 int res = 0; 543 auto entities = entityManager.entities.data; 544 for(size_t i = 0; i < entities.length; i++) 545 { 546 auto e = entities[i]; 547 Light light = cast(Light)e; 548 if (light) 549 { 550 if (light.type == LightType.Sun) 551 { 552 res = dg(e); 553 if (res) 554 break; 555 } 556 } 557 } 558 return res; 559 } 560 } 561 562 class EntityGroupAreaLights: Owner, EntityGroup 563 { 564 EntityManager entityManager; 565 566 this(EntityManager entityManager, Owner owner) 567 { 568 super(owner); 569 this.entityManager = entityManager; 570 } 571 572 int opApply(scope int delegate(Entity) dg) 573 { 574 int res = 0; 575 auto entities = entityManager.entities.data; 576 for(size_t i = 0; i < entities.length; i++) 577 { 578 auto e = entities[i]; 579 Light light = cast(Light)e; 580 if (light) 581 { 582 if (light.type == LightType.AreaSphere || 583 light.type == LightType.AreaTube || 584 light.type == LightType.Spot) 585 { 586 res = dg(e); 587 if (res) 588 break; 589 } 590 } 591 } 592 return res; 593 } 594 }