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.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.gltf; 52 import dagon.resource.image; 53 import dagon.resource.texture; 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 T addAssetAs(T)(string filename, bool preload = false) 116 { 117 T newAsset; 118 if (assetManager.assetExists(filename)) 119 newAsset = cast(T)assetManager.getAsset(filename); 120 else 121 { 122 static if (is(T: ImageAsset) || is(T: TextureAsset)) 123 { 124 newAsset = New!T(assetManager.imageFactory, assetManager.hdrImageFactory, assetManager); 125 } 126 else static if (is(T: PackageAsset)) 127 { 128 newAsset = New!T(this, assetManager); 129 } 130 else 131 { 132 newAsset = New!T(assetManager); 133 } 134 addAsset(newAsset, filename, preload); 135 } 136 return newAsset; 137 } 138 139 alias addImageAsset = addAssetAs!ImageAsset; 140 141 alias addTextureAsset = addAssetAs!TextureAsset; 142 143 alias addOBJAsset = addAssetAs!OBJAsset; 144 145 alias addGLTFAsset = addAssetAs!GLTFAsset; 146 147 alias addTextAsset = addAssetAs!TextAsset; 148 149 alias addBinaryAsset = addAssetAs!BinaryAsset; 150 151 alias addPackageAsset = addAssetAs!PackageAsset; 152 153 Material addMaterial() 154 { 155 return New!Material(assetManager); 156 } 157 158 Material addDecalMaterial() 159 { 160 auto mat = addMaterial(); 161 mat.blending = Transparent; 162 mat.depthWrite = false; 163 mat.culling = false; 164 return mat; 165 } 166 167 Cubemap addCubemap(uint size) 168 { 169 return New!Cubemap(size, assetManager); 170 } 171 172 Entity addEntity(Entity parent = null) 173 { 174 Entity e = New!Entity(entityManager); 175 if (parent) 176 e.setParent(parent); 177 return e; 178 } 179 180 Entity useEntity(Entity e) 181 { 182 entityManager.addEntity(e); 183 return e; 184 } 185 186 Entity addEntityHUD(Entity parent = null) 187 { 188 Entity e = New!Entity(entityManager); 189 e.layer = EntityLayer.Foreground; 190 if (parent) 191 e.setParent(parent); 192 return e; 193 } 194 195 Camera addCamera(Entity parent = null) 196 { 197 Camera c = New!Camera(entityManager); 198 if (parent) 199 c.setParent(parent); 200 return c; 201 } 202 203 Light addLight(LightType type, Entity parent = null) 204 { 205 Light light = New!Light(entityManager); 206 if (parent) 207 light.setParent(parent); 208 light.type = type; 209 return light; 210 } 211 212 Entity addDecal(Entity parent = null) 213 { 214 Entity e = New!Entity(entityManager); 215 e.decal = true; 216 e.drawable = decalShape; 217 if (parent) 218 e.setParent(parent); 219 return e; 220 } 221 222 // Override me 223 void beforeLoad() 224 { 225 } 226 227 // Override me 228 void onLoad(Time t, float progress) 229 { 230 } 231 232 // Override me 233 void afterLoad() 234 { 235 } 236 237 // Override me 238 void onUpdate(Time t) 239 { 240 } 241 242 import std.stdio; 243 244 void update(Time t) 245 { 246 processEvents(); 247 248 if (isLoading) 249 { 250 onLoad(t, assetManager.nextLoadingPercentage); 251 isLoading = assetManager.isLoading; 252 } 253 else 254 { 255 if (!loaded) 256 { 257 assetManager.loadThreadUnsafePart(); 258 loaded = true; 259 afterLoad(); 260 onLoad(t, 1.0f); 261 canRender = true; 262 } 263 264 onUpdate(t); 265 266 foreach(e; entityManager.entities) 267 { 268 e.update(t); 269 } 270 } 271 } 272 } 273 274 class EntityGroupSpatial: Owner, EntityGroup 275 { 276 EntityManager entityManager; 277 278 this(EntityManager entityManager, Owner owner) 279 { 280 super(owner); 281 this.entityManager = entityManager; 282 } 283 284 int opApply(scope int delegate(Entity) dg) 285 { 286 int res = 0; 287 auto entities = entityManager.entities.data; 288 for(size_t i = 0; i < entities.length; i++) 289 { 290 auto e = entities[i]; 291 if (e.layer == EntityLayer.Spatial && !e.decal) 292 { 293 res = dg(e); 294 if (res) 295 break; 296 } 297 } 298 return res; 299 } 300 } 301 302 class EntityGroupDecals: Owner, EntityGroup 303 { 304 EntityManager entityManager; 305 306 this(EntityManager entityManager, Owner owner) 307 { 308 super(owner); 309 this.entityManager = entityManager; 310 } 311 312 int opApply(scope int delegate(Entity) dg) 313 { 314 int res = 0; 315 auto entities = entityManager.entities.data; 316 for(size_t i = 0; i < entities.length; i++) 317 { 318 auto e = entities[i]; 319 if (e.decal) 320 { 321 res = dg(e); 322 if (res) 323 break; 324 } 325 } 326 return res; 327 } 328 } 329 330 class EntityGroupSpatialOpaque: Owner, EntityGroup 331 { 332 EntityManager entityManager; 333 bool dynamic = true; 334 335 this(EntityManager entityManager, bool dynamic, Owner owner) 336 { 337 super(owner); 338 this.entityManager = entityManager; 339 this.dynamic = dynamic; 340 } 341 342 int opApply(scope int delegate(Entity) dg) 343 { 344 int res = 0; 345 auto entities = entityManager.entities.data; 346 for(size_t i = 0; i < entities.length; i++) 347 { 348 auto e = entities[i]; 349 if (e.layer == EntityLayer.Spatial && !e.decal) 350 { 351 bool transparent = false; 352 353 if (e.material) 354 transparent = e.material.isTransparent; 355 356 transparent = transparent || e.transparent || e.opacity < 1.0f; 357 358 if (!transparent && e.dynamic == dynamic) 359 { 360 res = dg(e); 361 if (res) 362 break; 363 } 364 } 365 } 366 return res; 367 } 368 } 369 370 class EntityGroupSpatialTransparent: Owner, EntityGroup 371 { 372 EntityManager entityManager; 373 374 this(EntityManager entityManager, Owner owner) 375 { 376 super(owner); 377 this.entityManager = entityManager; 378 } 379 380 int opApply(scope int delegate(Entity) dg) 381 { 382 int res = 0; 383 auto entities = entityManager.entities.data; 384 for(size_t i = 0; i < entities.length; i++) 385 { 386 auto e = entities[i]; 387 if (e.layer == EntityLayer.Spatial && !e.decal) 388 { 389 bool transparent = false; 390 391 if (e.material) 392 transparent = e.material.isTransparent; 393 394 transparent = transparent || e.transparent || e.opacity < 1.0f; 395 396 if (transparent) 397 { 398 res = dg(e); 399 if (res) 400 break; 401 } 402 } 403 } 404 return res; 405 } 406 } 407 408 class EntityGroupBackground: Owner, EntityGroup 409 { 410 EntityManager entityManager; 411 412 this(EntityManager entityManager, Owner owner) 413 { 414 super(owner); 415 this.entityManager = entityManager; 416 } 417 418 int opApply(scope int delegate(Entity) dg) 419 { 420 int res = 0; 421 auto entities = entityManager.entities.data; 422 for(size_t i = 0; i < entities.length; i++) 423 { 424 auto e = entities[i]; 425 if (e.layer == EntityLayer.Background) 426 { 427 res = dg(e); 428 if (res) 429 break; 430 } 431 } 432 return res; 433 } 434 } 435 436 class EntityGroupForeground: Owner, EntityGroup 437 { 438 EntityManager entityManager; 439 440 this(EntityManager entityManager, Owner owner) 441 { 442 super(owner); 443 this.entityManager = entityManager; 444 } 445 446 int opApply(scope int delegate(Entity) dg) 447 { 448 int res = 0; 449 auto entities = entityManager.entities.data; 450 for(size_t i = 0; i < entities.length; i++) 451 { 452 auto e = entities[i]; 453 if (e.layer == EntityLayer.Foreground) 454 { 455 res = dg(e); 456 if (res) 457 break; 458 } 459 } 460 return res; 461 } 462 } 463 464 class EntityGroupLights: Owner, EntityGroup 465 { 466 EntityManager entityManager; 467 468 this(EntityManager entityManager, Owner owner) 469 { 470 super(owner); 471 this.entityManager = entityManager; 472 } 473 474 int opApply(scope int delegate(Entity) dg) 475 { 476 int res = 0; 477 auto entities = entityManager.entities.data; 478 for(size_t i = 0; i < entities.length; i++) 479 { 480 auto e = entities[i]; 481 Light light = cast(Light)e; 482 if (light) 483 { 484 res = dg(e); 485 if (res) 486 break; 487 } 488 } 489 return res; 490 } 491 } 492 493 class EntityGroupSunLights: Owner, EntityGroup 494 { 495 EntityManager entityManager; 496 497 this(EntityManager entityManager, Owner owner) 498 { 499 super(owner); 500 this.entityManager = entityManager; 501 } 502 503 int opApply(scope int delegate(Entity) dg) 504 { 505 int res = 0; 506 auto entities = entityManager.entities.data; 507 for(size_t i = 0; i < entities.length; i++) 508 { 509 auto e = entities[i]; 510 Light light = cast(Light)e; 511 if (light) 512 { 513 if (light.type == LightType.Sun) 514 { 515 res = dg(e); 516 if (res) 517 break; 518 } 519 } 520 } 521 return res; 522 } 523 } 524 525 class EntityGroupAreaLights: Owner, EntityGroup 526 { 527 EntityManager entityManager; 528 529 this(EntityManager entityManager, Owner owner) 530 { 531 super(owner); 532 this.entityManager = entityManager; 533 } 534 535 int opApply(scope int delegate(Entity) dg) 536 { 537 int res = 0; 538 auto entities = entityManager.entities.data; 539 for(size_t i = 0; i < entities.length; i++) 540 { 541 auto e = entities[i]; 542 Light light = cast(Light)e; 543 if (light) 544 { 545 if (light.type == LightType.AreaSphere || 546 light.type == LightType.AreaTube || 547 light.type == LightType.Spot) 548 { 549 res = dg(e); 550 if (res) 551 break; 552 } 553 } 554 } 555 return res; 556 } 557 }