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 }