1 module re.content;
2 
3 import re.util.cache;
4 import re.util.interop;
5 import std.string;
6 import std.file;
7 import std.conv;
8 import std.path;
9 import std.stdio;
10 static import raylib;
11 
12 /// manages external content loading
13 class ContentManager {
14     alias TexCache = KeyedCache!(raylib.Texture2D);
15     private TexCache _tex_cache;
16     alias ModelCache = KeyedCache!(raylib.Model);
17     private ModelCache _mdl_cache;
18     alias ShaderCache = KeyedCache!(raylib.Shader);
19     private ShaderCache _shd_cache;
20 
21     /// search paths for content
22     public string[] paths;
23 
24     /// initializes the content manager
25     this() {
26         // setup
27         _tex_cache = TexCache((tex) { raylib.UnloadTexture(tex); });
28         _mdl_cache = ModelCache((mdl) { raylib.UnloadModel(mdl); });
29         _shd_cache = ShaderCache((shd) { raylib.UnloadShader(shd); });
30     }
31 
32     private const char* get_path(string path) {
33         auto base = string.init;
34         alias join_paths = std.path.buildNormalizedPath;
35         // check search paths first
36         foreach (search_path; paths) {
37             // if the combination path exists, then make this base
38             if (std.file.exists(join_paths(search_path, path))) {
39                 base = search_path;
40                 break;
41             }
42         }
43         return join_paths(base, path).c_str();
44     }
45 
46     /// loads a texture from disk
47     public raylib.Texture2D load_texture2d(string path) {
48         raylib.Texture2D tex;
49         auto cached = _tex_cache.get(path);
50         if (cached.isNull) {
51             auto image = raylib.LoadImage(get_path(path));
52             tex = raylib.LoadTextureFromImage(image);
53             raylib.UnloadImage(image);
54             _tex_cache.put(path, tex);
55         } else {
56             tex = cached.get;
57         }
58 
59         // copy image to VRAM
60         return tex;
61     }
62 
63     /// loads a model from disk
64     public raylib.Model load_model(string path) {
65         raylib.Model mdl;
66         auto cached = _mdl_cache.get(path);
67         if (cached.isNull) {
68             mdl = raylib.LoadModel(get_path(path));
69             _mdl_cache.put(path, mdl);
70         } else {
71             mdl = cached.get;
72         }
73         return mdl;
74     }
75 
76     /// loads a shader from disk (vertex shader, fragment shader).
77     /// pass null to either arg to use the default
78     public raylib.Shader load_shader(string vs_path, string fs_path) {
79         raylib.Shader shd;
80         import std.digest.sha : sha1Of, toHexString;
81 
82         auto path_hash = to!string(sha1Of(vs_path ~ fs_path).toHexString);
83         auto cached = _shd_cache.get(path_hash);
84         if (cached.isNull) {
85             auto vs = vs_path.length > 0 ? get_path(vs_path) : null;
86             auto fs = fs_path.length > 0 ? get_path(fs_path) : null;
87             shd = raylib.LoadShader(vs, fs);
88             _shd_cache.put(path_hash, shd);
89         } else {
90             shd = cached.get;
91         }
92         return shd;
93     }
94 
95     /// releases all resources
96     public void destroy() {
97         // delete textures
98         _tex_cache.drop();
99         // delete models
100         _mdl_cache.drop();
101         // delete shaders
102         _shd_cache.drop();
103     }
104 }