diff --git a/src/BoE.vsproj/Common/Common.vcxproj b/src/BoE.vsproj/Common/Common.vcxproj index a59c5fce..69b15264 100644 --- a/src/BoE.vsproj/Common/Common.vcxproj +++ b/src/BoE.vsproj/Common/Common.vcxproj @@ -118,6 +118,7 @@ + diff --git a/src/BoE.vsproj/Common/Common.vcxproj.filters b/src/BoE.vsproj/Common/Common.vcxproj.filters index ee2bc911..f0a9e59b 100644 --- a/src/BoE.vsproj/Common/Common.vcxproj.filters +++ b/src/BoE.vsproj/Common/Common.vcxproj.filters @@ -333,6 +333,9 @@ Tools\Source Files + + Tools\Source Files + Tools\Source Files diff --git a/src/BoE.xcodeproj/project.pbxproj b/src/BoE.xcodeproj/project.pbxproj index bf78c7d5..998a9f5e 100755 --- a/src/BoE.xcodeproj/project.pbxproj +++ b/src/BoE.xcodeproj/project.pbxproj @@ -137,6 +137,7 @@ 91870F84190C90980081C150 /* scenedit.xib in Resources */ = {isa = PBXBuildFile; fileRef = 914CA49F190C4E9200B6ADD1 /* scenedit.xib */; }; 919145FC18E3AB1B005CF3A4 /* boe.appleevents.mm in Sources */ = {isa = PBXBuildFile; fileRef = 919145FB18E3A32F005CF3A4 /* boe.appleevents.mm */; }; 9192C12018F2745C0088A580 /* game.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9192C11E18F271920088A580 /* game.xib */; }; + 91960ED41BB6157A008AF8F4 /* restypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91960ED31BB613E5008AF8F4 /* restypes.cpp */; }; 919CC2481B3772F300273FDA /* creatlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91AC620A0FA2853700EEAE67 /* creatlist.cpp */; }; 919CC2491B3772FB00273FDA /* creature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914698FE1A747C4500F20F5E /* creature.cpp */; }; 919CC24B1B37730300273FDA /* item.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91279D3D0F9D1D6A007B0D52 /* item.cpp */; }; @@ -657,6 +658,7 @@ 9191460018E63D8E005CF3A4 /* scrollbar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scrollbar.cpp; sourceTree = ""; }; 9191460118E6591F005CF3A4 /* boe.menus.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = boe.menus.hpp; sourceTree = ""; }; 9192C11E18F271920088A580 /* game.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = game.xib; path = ../rsrc/menus/game.xib; sourceTree = ""; }; + 91960ED31BB613E5008AF8F4 /* restypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = restypes.cpp; sourceTree = ""; }; 919DDBFA19006CC9003E7FED /* libboost_filesystem.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libboost_filesystem.dylib; path = /usr/local/lib/libboost_filesystem.dylib; sourceTree = ""; }; 919DDBFB19006CC9003E7FED /* libboost_system.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libboost_system.dylib; path = /usr/local/lib/libboost_system.dylib; sourceTree = ""; }; 919DDC091900750D003E7FED /* freetype.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = freetype.framework; path = ../../../../../../Library/Frameworks/freetype.framework; sourceTree = ""; }; @@ -999,6 +1001,7 @@ children = ( 912DFE8918E24B4C00B00D75 /* resmgr.hpp */, 912DFE8A18E24B4C00B00D75 /* restypes.hpp */, + 91960ED31BB613E5008AF8F4 /* restypes.cpp */, ); path = resmgr; sourceTree = ""; @@ -1788,6 +1791,7 @@ 919CC27D1B37743700273FDA /* tarball.cpp in Sources */, 919CC27E1B37743B00273FDA /* undo.cpp in Sources */, 919CC27F1B37744000273FDA /* winutil.mac.mm in Sources */, + 91960ED41BB6157A008AF8F4 /* restypes.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/tools/resmgr/resmgr.hpp b/src/tools/resmgr/resmgr.hpp index 73e20dcb..ebd4c63b 100644 --- a/src/tools/resmgr/resmgr.hpp +++ b/src/tools/resmgr/resmgr.hpp @@ -23,7 +23,9 @@ /// Resources include sounds, images, fonts, and cursors. /// /// To implement a new resource type, all you have to do is specialize -/// @a ResMgr::resLoader::operator() for the desired resource type. +/// @a ResMgr::resLoader::operator() and declare @a ResMgr::resLoader::file_ext +/// for the desired resource type. The operator() receives the +/// full file path with the extension already applied. namespace ResMgr { namespace fs = boost::filesystem; /// The signature of an ID map function. @@ -56,12 +58,13 @@ namespace ResMgr { /// Convert a relative path to an absolute path by checking the current search path stack. /// @param path The path to resolve. /// @return The resolved absolute path, or the relative path unchanged if resolution failed. - static fs::path rel2abs(fs::path path) { + static fs::path find(std::string name, std::string ext) { + fs::path path = name + "." + ext; std::stack tmpPaths = resPaths(); while(!tmpPaths.empty()) { fs::path thisPath = tmpPaths.top()/path; if(fs::exists(thisPath)) { - pathFound()[path] = tmpPaths.top(); + pathFound()[name] = thisPath; return thisPath; } tmpPaths.pop(); @@ -78,10 +81,12 @@ namespace ResMgr { /// @tparam type The type of resource. template struct resLoader { /// Load a resource of this type from the given file. - /// @param fname The path to the resource; this will be an absolute path unless resolution failed. + /// @param fpath The path to the resource; this will be an absolute path unless resolution failed. /// @return A pointer to the loaded resource. The resource manager takes responsibility for freeing it, /// so it must be a pointer allocated with `new` rather than `new[]`. - type* operator() (std::string fname); + type* operator() (fs::path path); + /// The standard file extension for this resource type; + static const std::string file_ext; }; /// Thrown if an error occurs while loading a resource. @@ -131,19 +136,19 @@ namespace ResMgr { template std::shared_ptr get(std::string name) { if(resPool::resources().find(name) != resPool::resources().end()) { if(resPool::pathFound().find(name) != resPool::pathFound().end()) { + resLoader load; std::string curPath = resPool::pathFound()[name].string(); - std::string checkPath = resPool::rel2abs(name).string(); - checkPath = checkPath.substr(0,curPath.length()); + std::string checkPath = resPool::find(name, load.file_ext).string(); if(checkPath != curPath) { free(name); - return get(name); + type* tmp = load(checkPath); + return resPool::resources()[name] = std::shared_ptr(tmp); } } return resPool::resources()[name]; } else { - type* tmp; resLoader load; - tmp = load(name); + type* tmp = load(resPool::find(name, load.file_ext)); return resPool::resources()[name] = std::shared_ptr(tmp); } } diff --git a/src/tools/resmgr/restypes.cpp b/src/tools/resmgr/restypes.cpp new file mode 100644 index 00000000..f984a35e --- /dev/null +++ b/src/tools/resmgr/restypes.cpp @@ -0,0 +1,17 @@ +// +// restypes.cpp +// BoE +// +// Created by Celtic Minstrel on 15-09-25. +// +// + +#include "restypes.hpp" + +namespace ResMgr { + template<> const std::string resLoader::file_ext = "png"; + template<> const std::string resLoader::file_ext = "gif"; + template<> const std::string resLoader::file_ext = "ttf"; + template<> const std::string resLoader::file_ext = "txt"; + template<> const std::string resLoader::file_ext = "wav"; +} diff --git a/src/tools/resmgr/restypes.hpp b/src/tools/resmgr/restypes.hpp index 8ad44349..7e413269 100644 --- a/src/tools/resmgr/restypes.hpp +++ b/src/tools/resmgr/restypes.hpp @@ -33,8 +33,7 @@ extern std::ostream& std_fmterr(std::ostream& out); namespace ResMgr { /// Load an image from a PNG file. - template<> inline ImageRsrc* resLoader::operator() (std::string fname) { - fs::path fpath = resPool::rel2abs(fname + ".png"); + template<> inline ImageRsrc* resLoader::operator() (fs::path fpath) { ImageRsrc* img = new ImageRsrc(); if(img->loadFromFile(fpath.string())) return img; delete img; @@ -44,10 +43,9 @@ namespace ResMgr { /// Load a cursor from a GIF file. /// The cursor's hotspot location is stored in a GIF comment, with the following syntax (case-sensitive): /// "Hotspot(x,y)" - template<> inline CursorRsrc* resLoader::operator() (std::string fname) { - fs::path fpath = resPool::rel2abs(fname + ".gif"); + template<> inline CursorRsrc* resLoader::operator() (fs::path fpath) { if(!fs::exists(fpath)) - throw xResMgrErr("Failed to load GIF cursor: " + fname); + throw xResMgrErr("Failed to load GIF cursor: " + fpath.string()); int x = 0, y = 0, f_sz; std::ifstream fin(fpath.c_str(), std::ios::binary); fin.seekg(0, std::ios::end); @@ -83,19 +81,16 @@ namespace ResMgr { } } if(!found_hotspot) - std::cerr << "Cursor hotspot missing: " << fname << std::endl; + std::cerr << "Cursor hotspot missing: " << fpath.string() << std::endl; // TODO: Handle errors? CursorRsrc* cur = new Cursor(fpath.string(),x,y); return cur; } /// Load a font from a TTF file. - template<> inline FontRsrc* resLoader::operator() (std::string fname) { - fs::path fpath = resPool::rel2abs(fname + ".ttf"); + template<> inline FontRsrc* resLoader::operator() (fs::path fpath) { FontRsrc* theFont = new FontRsrc; if(theFont->loadFromFile(fpath.string())) return theFont; - fpath = resPool::rel2abs(fname + ".otf"); - if(theFont->loadFromFile(fpath.string())) return theFont; delete theFont; throw xResMgrErr("Failed to find font: " + fpath.string()); } @@ -103,8 +98,7 @@ namespace ResMgr { /// Load a list of strings from a TXT file. /// Each line in the file becomes one string in the resulting list. /// (Empty lines are included too.) - template<> inline StringRsrc* resLoader::operator() (std::string fname) { - fs::path fpath = resPool::rel2abs(fname + ".txt"); + template<> inline StringRsrc* resLoader::operator() (fs::path fpath) { std::ifstream fin(fpath.c_str()); if(fin.fail()) { std::cerr << std_fmterr << ": Error opening file"; @@ -120,8 +114,7 @@ namespace ResMgr { } /// Load a sound from a WAV file. - template<> inline SoundRsrc* resLoader::operator() (std::string fname) { - fs::path fpath = resPool::rel2abs(fname + ".wav"); + template<> inline SoundRsrc* resLoader::operator() (fs::path fpath) { SoundRsrc* snd = new SoundRsrc; if(snd->loadFromFile(fpath.string())) return snd; delete snd;