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 }