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