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 }