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         // check if this is already a valid path
34         if (std.file.exists(path)) {
35             return path.c_str();
36         }
37         auto base = string.init;
38         alias join_paths = std.path.buildNormalizedPath;
39         // check search paths first
40         foreach (search_path; paths) {
41             // if the combination path exists, then make this base
42             if (std.file.exists(join_paths(search_path, path))) {
43                 base = search_path;
44                 break;
45             }
46         }
47         return join_paths(base, path).c_str();
48     }
49 
50     /// loads a texture from disk
51     public raylib.Texture2D load_texture2d(string path) {
52         raylib.Texture2D tex;
53         auto cached = _tex_cache.get(path);
54         if (cached.isNull) {
55             auto image = raylib.LoadImage(get_path(path));
56             tex = raylib.LoadTextureFromImage(image);
57             raylib.UnloadImage(image);
58             _tex_cache.put(path, tex);
59         } else {
60             tex = cached.get;
61         }
62 
63         // copy image to VRAM
64         return tex;
65     }
66 
67     /// loads a model from disk
68     public raylib.Model load_model(string path) {
69         raylib.Model mdl;
70         auto cached = _mdl_cache.get(path);
71         if (cached.isNull) {
72             mdl = raylib.LoadModel(get_path(path));
73             _mdl_cache.put(path, mdl);
74         } else {
75             mdl = cached.get;
76         }
77         return mdl;
78     }
79 
80     /// loads a shader from disk (vertex shader, fragment shader).
81     /// pass null to either arg to use the default
82     public raylib.Shader load_shader(string vs_path, string fs_path) {
83         raylib.Shader shd;
84         import std.digest.sha : sha1Of, toHexString;
85 
86         auto path_hash = to!string(sha1Of(vs_path ~ fs_path).toHexString);
87         auto cached = _shd_cache.get(path_hash);
88         if (cached.isNull) {
89             auto vs = vs_path.length > 0 ? get_path(vs_path) : null;
90             auto fs = fs_path.length > 0 ? get_path(fs_path) : null;
91             shd = raylib.LoadShader(vs, fs);
92             _shd_cache.put(path_hash, shd);
93         } else {
94             shd = cached.get;
95         }
96         return shd;
97     }
98 
99     /// releases all resources
100     public void destroy() {
101         // delete textures
102         _tex_cache.drop();
103         // delete models
104         _mdl_cache.drop();
105         // delete shaders
106         _shd_cache.drop();
107     }
108 }