Files
simian/src/AssetManager.cpp
T
nick 3e23f7da8e
CI / build-and-test (push) Failing after 10m16s
CI / build-and-test (pull_request) Successful in 3m2s
feat: added physFS
2026-03-11 16:43:36 +13:00

1084 lines
34 KiB
C++

#include "AssetManager.h"
#include "ModelManager.h"
#include "ShaderManager.h"
#include "MaterialManager.h"
#include "TextureManager.h"
#include "PhysFSManager.h"
#include "log/log.h"
#include <algorithm>
#include <cctype>
#include <iomanip>
#include <sstream>
namespace {
std::string TrimAsset(const std::string& value) {
size_t start = 0;
while (start < value.size() && std::isspace(static_cast<unsigned char>(value[start]))) {
start++;
}
size_t end = value.size();
while (end > start && std::isspace(static_cast<unsigned char>(value[end - 1]))) {
end--;
}
return value.substr(start, end - start);
}
std::string StripCommentAsset(const std::string& line) {
bool inString = false;
for (size_t i = 0; i < line.size(); ++i) {
char c = line[i];
if (c == '"') {
inString = !inString;
}
if (!inString && c == '#') {
return line.substr(0, i);
}
}
return line;
}
bool ParseStringAsset(const std::string& value, std::string& out) {
std::string trimmed = TrimAsset(value);
if (trimmed.size() >= 2 && trimmed.front() == '"' && trimmed.back() == '"') {
out = trimmed.substr(1, trimmed.size() - 2);
return true;
}
return false;
}
bool ParseFloatList(const std::string& value, std::vector<float>& out) {
std::string trimmed = TrimAsset(value);
if (trimmed.size() < 2 || trimmed.front() != '[' || trimmed.back() != ']') {
return false;
}
std::string inner = trimmed.substr(1, trimmed.size() - 2);
std::stringstream ss(inner);
std::string token;
out.clear();
while (std::getline(ss, token, ',')) {
std::string piece = TrimAsset(token);
if (piece.empty()) {
continue;
}
try {
out.push_back(std::stof(piece));
} catch (...) {
return false;
}
}
return !out.empty();
}
std::string EscapeStringAsset(const std::string& value) {
std::string out;
out.reserve(value.size());
for (char c : value) {
if (c == '\\' || c == '"') {
out.push_back('\\');
}
out.push_back(c);
}
return out;
}
void WriteFloatList(std::ostream& out, const std::vector<float>& values) {
out << '[';
for (size_t i = 0; i < values.size(); ++i) {
if (i > 0) {
out << ", ";
}
out << values[i];
}
out << ']';
}
}
AssetManager::AssetManager() = default;
AssetManager::~AssetManager() = default;
void AssetManager::SetManagers(ModelManager* modelMgr, ShaderManager* shaderMgr,
MaterialManager* materialMgr, TextureManager* textureMgr)
{
modelManager = modelMgr;
shaderManager = shaderMgr;
materialManager = materialMgr;
textureManager = textureMgr;
}
bool AssetManager::RegisterTexture(const std::string& key, unsigned int id, const std::string& source)
{
if (key.empty() || id == 0) {
return false;
}
if (textureAssets.find(key) != textureAssets.end()) {
return textureAssets[key].id == id;
}
textureAssets[key] = AssetEntry{id, source};
textureIds[id] = key;
return true;
}
bool AssetManager::RegisterShader(const std::string& key, unsigned int id, const std::string& source)
{
if (key.empty() || id == 0) {
return false;
}
if (shaderAssets.find(key) != shaderAssets.end()) {
return shaderAssets[key].id == id;
}
shaderAssets[key] = AssetEntry{id, source};
shaderIds[id] = key;
return true;
}
bool AssetManager::RegisterModel(const std::string& key, unsigned int id, const std::string& source)
{
if (key.empty() || id == 0) {
return false;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id == id;
}
modelAssets[key] = AssetEntry{id, source};
modelIds[id] = key;
return true;
}
bool AssetManager::RegisterMaterial(const std::string& key, unsigned int id, const std::string& source)
{
if (key.empty() || id == 0) {
return false;
}
if (materialAssets.find(key) != materialAssets.end()) {
return materialAssets[key].id == id;
}
materialAssets[key] = AssetEntry{id, source};
materialIds[id] = key;
return true;
}
unsigned int AssetManager::LoadTexture(const std::string& key, const std::string& path)
{
if (!textureManager) {
log_warn("AssetManager: texture manager not set");
return 0;
}
if (textureAssets.find(key) != textureAssets.end()) {
return textureAssets[key].id;
}
unsigned int id = textureManager->Load(path);
if (id != 0) {
RegisterTexture(key, id, path);
textureDefs[key] = TextureDefinition{path};
}
return id;
}
unsigned int AssetManager::LoadShader(const std::string& key, const std::string& vsPath, const std::string& fsPath)
{
if (!shaderManager) {
log_warn("AssetManager: shader manager not set");
return 0;
}
if (shaderAssets.find(key) != shaderAssets.end()) {
return shaderAssets[key].id;
}
unsigned int id = shaderManager->Load(vsPath, fsPath);
if (id != 0) {
RegisterShader(key, id, vsPath + "|" + fsPath);
shaderDefs[key] = ShaderDefinition{vsPath, fsPath};
}
return id;
}
unsigned int AssetManager::LoadModel(const std::string& key, const std::string& path)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
unsigned int id = modelManager->Load(path);
if (id != 0) {
RegisterModel(key, id, path);
ModelDefinition def;
def.type = ModelDefinition::Type::Path;
def.path = path;
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadCube(const std::string& key, float width, float height, float length)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
unsigned int id = modelManager->LoadCube(width, height, length);
if (id != 0) {
RegisterModel(key, id, "cube");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "cube";
def.params = {width, height, length};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadPoly(const std::string& key, int sides, float radius)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
Mesh mesh = GenMeshPoly(sides, radius);
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, "poly");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "poly";
def.params = {static_cast<float>(sides), radius};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadSphere(const std::string& key, float radius, int rings, int slices)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
unsigned int id = modelManager->LoadSphere(radius, rings, slices);
if (id != 0) {
RegisterModel(key, id, "sphere");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "sphere";
def.params = {radius, static_cast<float>(rings), static_cast<float>(slices)};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadHemiSphere(const std::string& key, float radius, int rings, int slices)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
Mesh mesh = GenMeshHemiSphere(radius, rings, slices);
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, "hemisphere");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "hemisphere";
def.params = {radius, static_cast<float>(rings), static_cast<float>(slices)};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadPlane(const std::string& key, float width, float length, int resX, int resZ)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
unsigned int id = modelManager->LoadPlane(width, length, resX, resZ);
if (id != 0) {
RegisterModel(key, id, "plane");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "plane";
def.params = {width, length, static_cast<float>(resX), static_cast<float>(resZ)};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadCylinder(const std::string& key, float radius, float height, int slices)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
Mesh mesh = GenMeshCylinder(radius, height, slices);
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, "cylinder");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "cylinder";
def.params = {radius, height, static_cast<float>(slices)};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadCone(const std::string& key, float radius, float height, int slices)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
Mesh mesh = GenMeshCone(radius, height, slices);
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, "cone");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "cone";
def.params = {radius, height, static_cast<float>(slices)};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadTorus(const std::string& key, float radius, float size, int radSeg, int sides)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
Mesh mesh = GenMeshTorus(radius, size, radSeg, sides);
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, "torus");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "torus";
def.params = {radius, size, static_cast<float>(radSeg), static_cast<float>(sides)};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadKnot(const std::string& key, float radius, float size, int radSeg, int sides)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
Mesh mesh = GenMeshKnot(radius, size, radSeg, sides);
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, "knot");
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = "knot";
def.params = {radius, size, static_cast<float>(radSeg), static_cast<float>(sides)};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadHeightmap(const std::string& key, const std::string& heightmapPath, float sizeX, float sizeY, float sizeZ)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
Image heightmap = LoadImage(heightmapPath.c_str());
if (!heightmap.data) {
log_warn("AssetManager: failed to load heightmap %s", heightmapPath.c_str());
return 0;
}
Mesh mesh = GenMeshHeightmap(heightmap, Vector3{sizeX, sizeY, sizeZ});
UnloadImage(heightmap);
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, "heightmap:" + heightmapPath);
ModelDefinition def;
def.type = ModelDefinition::Type::Heightmap;
def.path = heightmapPath;
def.params = {sizeX, sizeY, sizeZ};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadCubicmap(const std::string& key, const std::string& cubicmapPath, float sizeX, float sizeY, float sizeZ)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
Image cubicmap = LoadImage(cubicmapPath.c_str());
if (!cubicmap.data) {
log_warn("AssetManager: failed to load cubicmap %s", cubicmapPath.c_str());
return 0;
}
Mesh mesh = GenMeshCubicmap(cubicmap, Vector3{sizeX, sizeY, sizeZ});
UnloadImage(cubicmap);
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, "cubicmap:" + cubicmapPath);
ModelDefinition def;
def.type = ModelDefinition::Type::Cubicmap;
def.path = cubicmapPath;
def.params = {sizeX, sizeY, sizeZ};
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::LoadFromMesh(const std::string& key, Mesh mesh, const std::string& source)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return 0;
}
if (modelAssets.find(key) != modelAssets.end()) {
return modelAssets[key].id;
}
unsigned int id = modelManager->LoadFromMesh(mesh);
if (id != 0) {
RegisterModel(key, id, source);
ModelDefinition def;
def.type = ModelDefinition::Type::Mesh;
def.path = source;
modelDefs[key] = def;
}
return id;
}
unsigned int AssetManager::CreateMaterial(const std::string& key, unsigned int shaderId, Color albedo)
{
if (!materialManager) {
log_warn("AssetManager: material manager not set");
return 0;
}
if (materialAssets.find(key) != materialAssets.end()) {
return materialAssets[key].id;
}
unsigned int id = materialManager->Create(shaderId, albedo);
if (id != 0) {
RegisterMaterial(key, id, "shader_id=" + std::to_string(shaderId));
MaterialDefinition def;
def.albedo = albedo;
if (shaderId != 0) {
const std::string& shaderKey = GetShaderKey(shaderId);
if (!shaderKey.empty()) {
def.shaderKey = shaderKey;
def.hasShaderKey = true;
} else {
def.shaderId = shaderId;
def.hasShaderId = true;
}
}
materialDefs[key] = def;
}
return id;
}
bool AssetManager::ApplyMeshTangents(const std::string& key, int meshIndex)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return false;
}
unsigned int id = GetModelId(key);
if (id == 0) {
return false;
}
Model* model = modelManager->Get(id);
if (!model || model->meshCount <= 0) {
return false;
}
if (meshIndex < 0 || meshIndex >= model->meshCount) {
return false;
}
GenMeshTangents(&model->meshes[meshIndex]);
UploadMesh(&model->meshes[meshIndex], false);
return true;
}
bool AssetManager::UnloadTexture(const std::string& key)
{
if (!textureManager) {
log_warn("AssetManager: texture manager not set");
return false;
}
auto it = textureAssets.find(key);
if (it == textureAssets.end()) {
return false;
}
textureManager->Unload(it->second.id);
textureIds.erase(it->second.id);
textureAssets.erase(it);
textureDefs.erase(key);
return true;
}
bool AssetManager::UnloadShader(const std::string& key)
{
if (!shaderManager) {
log_warn("AssetManager: shader manager not set");
return false;
}
auto it = shaderAssets.find(key);
if (it == shaderAssets.end()) {
return false;
}
shaderManager->Unload(it->second.id);
shaderIds.erase(it->second.id);
shaderAssets.erase(it);
shaderDefs.erase(key);
return true;
}
bool AssetManager::UnloadModel(const std::string& key)
{
if (!modelManager) {
log_warn("AssetManager: model manager not set");
return false;
}
auto it = modelAssets.find(key);
if (it == modelAssets.end()) {
return false;
}
modelManager->Unload(it->second.id);
modelIds.erase(it->second.id);
modelAssets.erase(it);
modelDefs.erase(key);
return true;
}
bool AssetManager::UnloadMaterial(const std::string& key)
{
if (!materialManager) {
log_warn("AssetManager: material manager not set");
return false;
}
auto it = materialAssets.find(key);
if (it == materialAssets.end()) {
return false;
}
materialManager->Remove(it->second.id);
materialIds.erase(it->second.id);
materialAssets.erase(it);
materialDefs.erase(key);
return true;
}
unsigned int AssetManager::GetTextureId(const std::string& key) const
{
auto it = textureAssets.find(key);
return (it != textureAssets.end()) ? it->second.id : 0;
}
unsigned int AssetManager::GetShaderId(const std::string& key) const
{
auto it = shaderAssets.find(key);
return (it != shaderAssets.end()) ? it->second.id : 0;
}
unsigned int AssetManager::GetModelId(const std::string& key) const
{
auto it = modelAssets.find(key);
return (it != modelAssets.end()) ? it->second.id : 0;
}
unsigned int AssetManager::GetMaterialId(const std::string& key) const
{
auto it = materialAssets.find(key);
return (it != materialAssets.end()) ? it->second.id : 0;
}
const std::string& AssetManager::GetTextureKey(unsigned int id) const
{
return GetKeyForId(textureIds, id);
}
const std::string& AssetManager::GetShaderKey(unsigned int id) const
{
return GetKeyForId(shaderIds, id);
}
const std::string& AssetManager::GetModelKey(unsigned int id) const
{
return GetKeyForId(modelIds, id);
}
const std::string& AssetManager::GetMaterialKey(unsigned int id) const
{
return GetKeyForId(materialIds, id);
}
std::vector<std::string> AssetManager::ListTextureKeys() const
{
return ListKeys(textureAssets);
}
std::vector<std::string> AssetManager::ListShaderKeys() const
{
return ListKeys(shaderAssets);
}
std::vector<std::string> AssetManager::ListModelKeys() const
{
return ListKeys(modelAssets);
}
std::vector<std::string> AssetManager::ListMaterialKeys() const
{
return ListKeys(materialAssets);
}
std::string AssetManager::GetTextureSource(const std::string& key) const
{
auto it = textureAssets.find(key);
return (it != textureAssets.end()) ? it->second.source : std::string();
}
std::string AssetManager::GetShaderSource(const std::string& key) const
{
auto it = shaderAssets.find(key);
return (it != shaderAssets.end()) ? it->second.source : std::string();
}
std::string AssetManager::GetModelSource(const std::string& key) const
{
auto it = modelAssets.find(key);
return (it != modelAssets.end()) ? it->second.source : std::string();
}
std::string AssetManager::GetMaterialSource(const std::string& key) const
{
auto it = materialAssets.find(key);
return (it != materialAssets.end()) ? it->second.source : std::string();
}
void AssetManager::Clear()
{
textureAssets.clear();
shaderAssets.clear();
modelAssets.clear();
materialAssets.clear();
textureDefs.clear();
shaderDefs.clear();
modelDefs.clear();
materialDefs.clear();
textureIds.clear();
shaderIds.clear();
modelIds.clear();
materialIds.clear();
}
const std::string& AssetManager::GetKeyForId(const std::unordered_map<unsigned int, std::string>& map, unsigned int id) const
{
static const std::string empty;
auto it = map.find(id);
return (it != map.end()) ? it->second : empty;
}
std::vector<std::string> AssetManager::ListKeys(const std::unordered_map<std::string, AssetEntry>& map) const
{
std::vector<std::string> keys;
keys.reserve(map.size());
for (const auto& pair : map) {
keys.push_back(pair.first);
}
return keys;
}
bool AssetManager::SaveRegistry(const std::string& path) const
{
auto parentPos = path.find_last_of("/\\");
if (parentPos != std::string::npos) {
PhysFSManager::EnsureDir(path.substr(0, parentPos));
}
std::ostringstream file;
file << "# Simian asset registry\n";
file << "# Auto-generated - edits may be overwritten\n\n";
file << std::setprecision(6);
for (const auto& [key, def] : textureDefs) {
if (key.empty() || def.path.empty()) {
continue;
}
file << "[[texture]]\n";
file << "key = \"" << EscapeStringAsset(key) << "\"\n";
file << "path = \"" << EscapeStringAsset(def.path) << "\"\n\n";
}
for (const auto& [key, def] : shaderDefs) {
if (key.empty() || def.vsPath.empty() || def.fsPath.empty()) {
continue;
}
file << "[[shader]]\n";
file << "key = \"" << EscapeStringAsset(key) << "\"\n";
file << "vs = \"" << EscapeStringAsset(def.vsPath) << "\"\n";
file << "fs = \"" << EscapeStringAsset(def.fsPath) << "\"\n\n";
}
for (const auto& [key, def] : modelDefs) {
if (key.empty()) {
continue;
}
if (def.type == ModelDefinition::Type::Mesh) {
continue;
}
file << "[[model]]\n";
file << "key = \"" << EscapeStringAsset(key) << "\"\n";
switch (def.type) {
case ModelDefinition::Type::Path:
if (!def.path.empty()) {
file << "type = \"path\"\n";
file << "path = \"" << EscapeStringAsset(def.path) << "\"\n\n";
}
break;
case ModelDefinition::Type::Primitive:
if (!def.primitive.empty() && !def.params.empty()) {
file << "type = \"primitive\"\n";
file << "primitive = \"" << EscapeStringAsset(def.primitive) << "\"\n";
file << "params = ";
WriteFloatList(file, def.params);
file << "\n\n";
}
break;
case ModelDefinition::Type::Heightmap:
if (!def.path.empty() && def.params.size() >= 3) {
file << "type = \"heightmap\"\n";
file << "path = \"" << EscapeStringAsset(def.path) << "\"\n";
file << "size = ";
WriteFloatList(file, def.params);
file << "\n\n";
}
break;
case ModelDefinition::Type::Cubicmap:
if (!def.path.empty() && def.params.size() >= 3) {
file << "type = \"cubicmap\"\n";
file << "path = \"" << EscapeStringAsset(def.path) << "\"\n";
file << "size = ";
WriteFloatList(file, def.params);
file << "\n\n";
}
break;
case ModelDefinition::Type::Mesh:
break;
}
}
for (const auto& [key, def] : materialDefs) {
if (key.empty()) {
continue;
}
file << "[[material]]\n";
file << "key = \"" << EscapeStringAsset(key) << "\"\n";
if (def.hasShaderKey && !def.shaderKey.empty()) {
file << "shader_key = \"" << EscapeStringAsset(def.shaderKey) << "\"\n";
} else if (def.hasShaderId && def.shaderId > 0) {
file << "shader_id = " << def.shaderId << "\n";
}
std::vector<float> albedo = {
static_cast<float>(def.albedo.r),
static_cast<float>(def.albedo.g),
static_cast<float>(def.albedo.b),
static_cast<float>(def.albedo.a)
};
file << "albedo = ";
WriteFloatList(file, albedo);
file << "\n\n";
}
return PhysFSManager::WriteTextFile(path, file.str());
}
bool AssetManager::LoadRegistry(const std::string& path)
{
std::string contents;
if (!PhysFSManager::ReadTextFile(path, contents)) {
log_warn("Asset registry not found: %s", path.c_str());
return false;
}
enum class Section {
None,
Texture,
Shader,
Model,
Material
};
Section section = Section::None;
std::string entryKey;
std::unordered_map<std::string, std::string> fields;
auto flushEntry = [&]() {
if (section == Section::None || entryKey.empty()) {
entryKey.clear();
fields.clear();
return;
}
if (section == Section::Texture) {
auto it = fields.find("path");
if (it != fields.end()) {
std::string pathValue;
if (ParseStringAsset(it->second, pathValue)) {
textureDefs[entryKey] = TextureDefinition{pathValue};
if (GetTextureId(entryKey) == 0) {
LoadTexture(entryKey, pathValue);
}
}
}
} else if (section == Section::Shader) {
std::string vsPath;
std::string fsPath;
auto itVs = fields.find("vs");
auto itFs = fields.find("fs");
if (itVs != fields.end() && itFs != fields.end() &&
ParseStringAsset(itVs->second, vsPath) && ParseStringAsset(itFs->second, fsPath)) {
shaderDefs[entryKey] = ShaderDefinition{vsPath, fsPath};
if (GetShaderId(entryKey) == 0) {
LoadShader(entryKey, vsPath, fsPath);
}
}
} else if (section == Section::Model) {
std::string typeValue;
auto itType = fields.find("type");
if (itType != fields.end() && ParseStringAsset(itType->second, typeValue)) {
if (typeValue == "path") {
std::string modelPath;
auto itPath = fields.find("path");
if (itPath != fields.end() && ParseStringAsset(itPath->second, modelPath)) {
ModelDefinition def;
def.type = ModelDefinition::Type::Path;
def.path = modelPath;
modelDefs[entryKey] = def;
if (GetModelId(entryKey) == 0) {
LoadModel(entryKey, modelPath);
}
}
} else if (typeValue == "primitive") {
std::string primitive;
std::vector<float> params;
auto itPrim = fields.find("primitive");
auto itParams = fields.find("params");
if (itPrim != fields.end() && itParams != fields.end() &&
ParseStringAsset(itPrim->second, primitive) && ParseFloatList(itParams->second, params)) {
ModelDefinition def;
def.type = ModelDefinition::Type::Primitive;
def.primitive = primitive;
def.params = params;
modelDefs[entryKey] = def;
if (GetModelId(entryKey) == 0) {
if (primitive == "cube" && params.size() >= 3) {
LoadCube(entryKey, params[0], params[1], params[2]);
} else if (primitive == "poly" && params.size() >= 2) {
LoadPoly(entryKey, static_cast<int>(params[0]), params[1]);
} else if (primitive == "sphere" && params.size() >= 3) {
LoadSphere(entryKey, params[0], static_cast<int>(params[1]), static_cast<int>(params[2]));
} else if (primitive == "hemisphere" && params.size() >= 3) {
LoadHemiSphere(entryKey, params[0], static_cast<int>(params[1]), static_cast<int>(params[2]));
} else if (primitive == "plane" && params.size() >= 4) {
LoadPlane(entryKey, params[0], params[1], static_cast<int>(params[2]), static_cast<int>(params[3]));
} else if (primitive == "cylinder" && params.size() >= 3) {
LoadCylinder(entryKey, params[0], params[1], static_cast<int>(params[2]));
} else if (primitive == "cone" && params.size() >= 3) {
LoadCone(entryKey, params[0], params[1], static_cast<int>(params[2]));
} else if (primitive == "torus" && params.size() >= 4) {
LoadTorus(entryKey, params[0], params[1], static_cast<int>(params[2]), static_cast<int>(params[3]));
} else if (primitive == "knot" && params.size() >= 4) {
LoadKnot(entryKey, params[0], params[1], static_cast<int>(params[2]), static_cast<int>(params[3]));
}
}
}
} else if (typeValue == "heightmap" || typeValue == "cubicmap") {
std::string mapPath;
std::vector<float> sizeValues;
auto itPath = fields.find("path");
auto itSize = fields.find("size");
if (itPath != fields.end() && itSize != fields.end() &&
ParseStringAsset(itPath->second, mapPath) && ParseFloatList(itSize->second, sizeValues) && sizeValues.size() >= 3) {
ModelDefinition def;
def.type = (typeValue == "heightmap") ? ModelDefinition::Type::Heightmap : ModelDefinition::Type::Cubicmap;
def.path = mapPath;
def.params = sizeValues;
modelDefs[entryKey] = def;
if (GetModelId(entryKey) == 0) {
if (typeValue == "heightmap") {
LoadHeightmap(entryKey, mapPath, sizeValues[0], sizeValues[1], sizeValues[2]);
} else {
LoadCubicmap(entryKey, mapPath, sizeValues[0], sizeValues[1], sizeValues[2]);
}
}
}
}
}
} else if (section == Section::Material) {
MaterialDefinition def;
std::vector<float> albedoVals;
auto itShaderKey = fields.find("shader_key");
if (itShaderKey != fields.end()) {
std::string shaderKey;
if (ParseStringAsset(itShaderKey->second, shaderKey)) {
def.shaderKey = shaderKey;
def.hasShaderKey = true;
}
}
auto itShaderId = fields.find("shader_id");
if (!def.hasShaderKey && itShaderId != fields.end()) {
try {
def.shaderId = static_cast<unsigned int>(std::stoul(TrimAsset(itShaderId->second), nullptr, 0));
def.hasShaderId = def.shaderId > 0;
} catch (...) {
}
}
auto itAlbedo = fields.find("albedo");
if (itAlbedo != fields.end() && ParseFloatList(itAlbedo->second, albedoVals) && albedoVals.size() >= 4) {
def.albedo = {
static_cast<unsigned char>(std::clamp(albedoVals[0], 0.0f, 255.0f)),
static_cast<unsigned char>(std::clamp(albedoVals[1], 0.0f, 255.0f)),
static_cast<unsigned char>(std::clamp(albedoVals[2], 0.0f, 255.0f)),
static_cast<unsigned char>(std::clamp(albedoVals[3], 0.0f, 255.0f))
};
}
materialDefs[entryKey] = def;
if (GetMaterialId(entryKey) == 0) {
unsigned int shaderId = 0;
if (def.hasShaderKey) {
shaderId = GetShaderId(def.shaderKey);
} else if (def.hasShaderId) {
shaderId = def.shaderId;
}
CreateMaterial(entryKey, shaderId, def.albedo);
materialDefs[entryKey] = def;
}
}
entryKey.clear();
fields.clear();
};
std::string line;
std::istringstream file(contents);
while (std::getline(file, line)) {
line = StripCommentAsset(line);
line = TrimAsset(line);
if (line.empty()) {
continue;
}
if (line == "[[texture]]") {
flushEntry();
section = Section::Texture;
continue;
}
if (line == "[[shader]]") {
flushEntry();
section = Section::Shader;
continue;
}
if (line == "[[model]]") {
flushEntry();
section = Section::Model;
continue;
}
if (line == "[[material]]") {
flushEntry();
section = Section::Material;
continue;
}
size_t eq = line.find('=');
if (eq == std::string::npos) {
continue;
}
std::string key = TrimAsset(line.substr(0, eq));
std::string value = TrimAsset(line.substr(eq + 1));
if (key == "key") {
ParseStringAsset(value, entryKey);
} else {
fields[key] = value;
}
}
flushEntry();
return true;
}