Last active
May 13, 2024 06:05
-
-
Save JeffM2501/bd1092ce0eaedd26fe3ca60e1743ce40 to your computer and use it in GitHub Desktop.
Basic platform independent asset folder management for raylib.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************************* | |
* Welcome to RLAssets!* | |
* RLAssets is licensed under an unmodified zlib/libpng license (View raylib.h for details) | |
* | |
* Copyright (c) 2020 Jeffery Myers | |
* | |
********************************************************************************************/ | |
#include "RLAssets.h" | |
#include "raylib.h" | |
#include <map> | |
#include <string> | |
#include <vector> | |
#include <algorithm> | |
#if defined(_WIN32) | |
constexpr char PathDelim = '\\'; | |
#else | |
constexpr char PathDelim = '/'; | |
#endif // OSs | |
typedef struct | |
{ | |
std::string RelativeName; | |
std::string PathOnDisk; | |
}rlas_AssetMeta; | |
typedef std::map<std::string, rlas_AssetMeta> MetaMap; | |
MetaMap AssetMap; | |
std::vector<std::string> AssetRootPaths; | |
std::string GetRelPath(const char* c) | |
{ | |
std::string upperPath = c; | |
for (auto& c : upperPath) | |
c = toupper(c); | |
return upperPath; | |
} | |
void rlas_SetAssetRootPath(const char* path, bool relativeToApp) | |
{ | |
AssetRootPaths.clear(); | |
if (relativeToApp) | |
{ | |
std::string appPath = rlas_GetApplicationBasePath(); | |
if (path != nullptr) | |
{ | |
appPath += path; | |
appPath += PathDelim; | |
} | |
rlas_AddAssetResourcePath(appPath.c_str()); | |
} | |
else | |
{ | |
rlas_AddAssetResourcePath(path); | |
} | |
} | |
const char* rlas_GetAssetRootPath() | |
{ | |
if (AssetRootPaths.size() == 0) | |
return nullptr; | |
return AssetRootPaths[0].c_str(); | |
} | |
void RecurseAddFiles(const std::string& root, const std::string& relRootPath) | |
{ | |
int count = 0; | |
char** path = GetDirectoryFiles(root.c_str(), &count); | |
std::vector<std::string> subDirs; | |
for (int i = 0; i < count; ++i) | |
{ | |
if (path[i] == nullptr || path[i][0] == '.') | |
continue; | |
std::string relPath = relRootPath + path[i]; | |
std::string fullPath = root + path[i]; | |
if (FileExists(fullPath.c_str())) | |
{ | |
std::string upperPath = GetRelPath(relPath.c_str()); | |
rlas_AssetMeta meta; | |
meta.RelativeName = relPath; | |
meta.PathOnDisk = fullPath; | |
AssetMap[upperPath] = meta; | |
} | |
else | |
{ | |
subDirs.push_back(path[i]); | |
} | |
} | |
ClearDirectoryFiles(); | |
for (auto subDir : subDirs) | |
{ | |
RecurseAddFiles(root + subDir + PathDelim , relRootPath + subDir + "/"); | |
} | |
} | |
void rlas_AddAssetResourcePath(const char* path) | |
{ | |
if (path == nullptr) | |
return; | |
std::string root = path; | |
AssetRootPaths.emplace_back(root); | |
RecurseAddFiles(root, "/"); | |
} | |
const char* rlas_GetAssetPath(const char* path) | |
{ | |
MetaMap::iterator itr = AssetMap.find(GetRelPath(path)); | |
if (itr == AssetMap.end()) | |
return nullptr; | |
return itr->second.PathOnDisk.c_str(); | |
} | |
int rlas_AppendPath(const char* path, const char* subpath, char* destination, int lenght) | |
{ | |
std::string p = path; | |
std::string sp = subpath; | |
std::string result = p + PathDelim + sp; | |
if (result.size() > lenght - 1) | |
return -1; | |
#ifdef _WIN32 | |
strncpy_s(destination, lenght, result.c_str(), result.size()); | |
#else | |
strncpy(destination, result.c_str(), result.size()); | |
#endif //_WIN32 | |
destination[result.size()] = '\0'; | |
return static_cast<int>(result.size()); | |
} | |
int rlas_GetAssetsInPath(const char* path, bool recursive, char* results[]) | |
{ | |
int count = 0; | |
std::string upperPath = GetRelPath(path); | |
for (auto& asset : AssetMap) | |
{ | |
if (asset.first.rfind(upperPath) == 0) | |
{ | |
bool isFile = asset.first.find_first_of('/', upperPath.length()) > asset.first.size(); | |
if (isFile || recursive) | |
{ | |
if (results != nullptr) | |
results[count] = (char*)asset.second.RelativeName.c_str(); | |
++count; | |
} | |
} | |
} | |
return count; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************************* | |
* Welcome to RLAssets!* | |
* RLAssets is licensed under an unmodified zlib/libpng license (View raylib.h for details) | |
* | |
* Copyright (c) 2020 Jeffery Myers | |
* | |
********************************************************************************************/ | |
#ifndef RLASSETS_H | |
#define RLASSETS_H | |
/// <summary> | |
/// Gets the application (exe) directory for the currently running program | |
/// </summary> | |
/// <returns>The path on disk in the current OSs format</returns> | |
const char* rlas_GetApplicationBasePath(); | |
/// <summary> | |
/// adds a subpath (folder or file) to the specified path with the correct characters for the current OS | |
/// </summary> | |
/// <param name="path">the root path</param> | |
/// <param name="subpath">the sub path to append</param> | |
/// <param name="destination">the destination string</param> | |
/// <param name="lenght">the lenght of the destination string</param> | |
/// <returns>the lenght of the resulting combined path, -1 if the destination was not long enough</returns> | |
int rlas_AppendPath(const char* path, const char* subpath, char* destination, int lenght); | |
/// <summary> | |
/// Sets the initial asset path on disk | |
/// </summary> | |
/// <param name="path">The path to use as the asset root</param> | |
/// <param name="relativeToApp">When true the specified path will be used relative to the application root and should be in unix (/) format, when false the path specified is in the OSs format</param> | |
void rlas_SetAssetRootPath(const char* path, bool relativeToApp); | |
/// <summary> | |
/// Returns the top level asset root path | |
/// </summary> | |
/// <returns>The path on dis (OS format) of the inital asset root</returns> | |
const char* rlas_GetAssetRootPath(); | |
/// <summary> | |
/// Adds an additional asset path to the search path for assets | |
/// The the specified path will be treated as '/' for relative paths | |
/// Any files that are duplicated in resource paths will be 'merged' into the virtual file structure and override older paths | |
/// </summary> | |
/// <param name="path">The resource path root to add</param> | |
void rlas_AddAssetResourcePath(const char* path); | |
/// <summary> | |
/// Gets the path on disk for an assets relative path | |
/// If multiple resource paths exist with the asset, the one added last will be returned. | |
/// </summary> | |
/// <param name="path">The relative path of the asset to look up</param> | |
/// <returns>The path on disk of the asset</returns> | |
const char* rlas_GetAssetPath(const char* path); | |
/// <summary> | |
/// Returns a list of all relative asset names in a resource path | |
/// Call once with results as NULL to get the count to allocate a result buffer large enough | |
/// Then call again with buffer to get results. | |
/// </summary> | |
/// <param name="path">The relative path to search </param> | |
/// <param name="includeSubDirectories">Search into subdirectories</param> | |
/// <param name="results">A pointer to a character array to store the results, when null not used.</param> | |
/// <returns>The number of asset items found</returns> | |
int rlas_GetAssetsInPath(const char* path, bool includeSubDirectories, char** results); | |
#endif //RLASSETS_H | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************************* | |
* Welcome to RLAssets!* | |
* RLAssets is licensed under an unmodified zlib/libpng license (View raylib.h for details) | |
* | |
* Copyright (c) 2020 Jeffery Myers | |
* | |
********************************************************************************************/ | |
#include "RLAssets.h" | |
#include <string> | |
#if defined(_WIN32) | |
#include <windows.h> | |
constexpr char PathDelim = '\\'; | |
#elif defined(__linux__) | |
#include <unistd.h> | |
constexpr char PathDelim = '/'; | |
#elif defined(__APPLE__) | |
#include <sys/syslimits.h> | |
constexpr char PathDelim = '/'; | |
#endif // OSs | |
std::string appDir; | |
const char* rlas_GetApplicationBasePath() | |
{ | |
if (appDir.size() == 0) | |
{ | |
appDir = "/"; // default for everyone to start out with | |
#if defined(_WIN32) | |
typedef DWORD(WINAPI* GetModuleFileNameFunc)(HANDLE, HMODULE, LPSTR, DWORD); | |
GetModuleFileNameFunc getModuleFileNameExWPtr = nullptr; | |
HMODULE lib = LoadLibrary(L"psapi.dll"); | |
if (lib == nullptr) | |
{ | |
appDir = "\\"; | |
} | |
else | |
{ | |
getModuleFileNameExWPtr = (GetModuleFileNameFunc)GetProcAddress(lib, "GetModuleFileNameExA"); | |
if (getModuleFileNameExWPtr == nullptr) | |
{ | |
appDir = "\\"; | |
} | |
else | |
{ | |
CHAR path[MAX_PATH]; | |
int len = getModuleFileNameExWPtr(GetCurrentProcess(), nullptr, path, MAX_PATH); | |
if (len > 0) | |
{ | |
for (int i = len; i >= 0; --i) | |
{ | |
if (path[i] == '\\') | |
{ | |
path[i + 1] = '\0'; | |
i = -1; | |
} | |
} | |
appDir = path; | |
} | |
} | |
FreeLibrary(lib); | |
} | |
#elif defined(__linux__) | |
char path[4096 + 1]; | |
uint32_t size = sizeof(path); | |
ssize_t len = readlink("/proc/self/exe", path, size); | |
if (len > 0) | |
{ | |
for (int i = len; i >= 0; --i) | |
{ | |
if (path[i] == '/') | |
{ | |
path[i + 1] = '\0'; | |
i = -1; | |
} | |
} | |
appDir = path; | |
} | |
#elif defined(__APPLE__) | |
char path[PATH_MAX + 1]; | |
uint32_t size = sizeof(path); | |
if (_NSGetExecutablePath(path, &size) == 0) | |
{ | |
int len = strlne(path); | |
for (int i = len; i >= 0; --i) | |
{ | |
if (path[i] == '/') | |
{ | |
path[i + 1] = '\0'; | |
i = -1; | |
} | |
} | |
appDir = path; | |
} | |
#endif | |
} | |
return appDir.c_str(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a simple asset management system that works with raylib. It lets a game define a set of root folders to use for assets and then will managed all the OS specific bookeeping of getting paths correct. It has functions to find the currently running application on any OS, regardless of how it's started or what the current working directory is set to. It will also merge multiple roots into one virtual relative file system, so a game can have a base set of assets with the game program but an option set of "mod" files in other paths that override root assets.
Usage.