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