15#include "medialoader/Exception.h"
16#include "medialoader/model/ModelLoader.h"
28std::string extensionOf(
const std::string &path) {
29 const auto pos = path.find_last_of(
'.');
30 if (
pos == std::string::npos)
return {};
31 std::string ext = path.substr(
pos);
32 for (
char &
c : ext)
c = static_cast<char>(std::tolower(static_cast<unsigned char>(
c)));
36bool isModelPath(
const std::string &path) {
37 const std::string ext = extensionOf(path);
38 return ext ==
".obj" || ext ==
".fbx" || ext ==
".gltf" || ext ==
".glb" || ext ==
".dae" ||
39 ext ==
".3ds" || ext ==
".blend" || ext ==
".stl" || ext ==
".ply" || ext ==
".x" ||
40 ext ==
".lwo" || ext ==
".lws" || ext ==
".md5mesh" || ext ==
".md5anim" ||
41 ext ==
".b3d" || ext ==
".csm" || ext ==
".irr" || ext ==
".irrmesh" || ext ==
".md2" ||
42 ext ==
".md3" || ext ==
".ms3d" || ext ==
".smd" || ext ==
".vta" || ext ==
".bvh" ||
43 ext ==
".ac" || ext ==
".off" || ext ==
".raw" || ext ==
".ter" || ext ==
".nff" ||
48medialoader::LoadOptions toMedialoader(
const ModelLoadOptions &opt) {
49 medialoader::LoadOptions
m;
50 m.triangulate = opt.triangulate;
51 m.generateNormalsIfMissing = opt.generateNormalsIfMissing;
52 m.joinIdenticalVertices = opt.joinIdenticalVertices;
53 m.flipUVs = opt.flipUVs;
54 m.improveCacheLocality = opt.improveCacheLocality;
58int queryInt(
const std::string &key,
const std::string &
name,
int fallback) {
59 const auto q = key.find(
'?');
60 if (q == std::string::npos)
return fallback;
62 std::string rest = key.substr(q + 1);
64 while (
pos < rest.size()) {
65 const size_t amp = rest.find(
'&',
pos);
66 const std::string pair =
67 rest.substr(
pos, amp == std::string::npos ? std::string::npos : amp -
pos);
68 const auto eq = pair.find(
'=');
69 if (eq != std::string::npos && pair.substr(0, eq) ==
name)
70 return std::atoi(pair.c_str() + eq + 1);
71 if (amp == std::string::npos)
break;
77bool queryBool(
const std::string &key,
const std::string &
name,
bool fallback) {
78 return queryInt(key,
name, fallback ? 1 : 0) != 0;
81ModelLoadOptions parseOptions(
const std::string &key) {
83 o.triangulate = queryBool(key,
"triangulate", o.triangulate);
84 o.generateNormalsIfMissing = queryBool(key,
"normals", o.generateNormalsIfMissing);
85 o.joinIdenticalVertices = queryBool(key,
"join", o.joinIdenticalVertices);
86 o.flipUVs = queryBool(key,
"flipuv", o.flipUVs);
87 o.improveCacheLocality = queryBool(key,
"cache", o.improveCacheLocality);
93 const char *reloadKind()
const override {
return "model"; }
95 bool handlesPath(
const std::string &normPath)
const override {
101 if (!isModelPath(path))
return nullptr;
102 const ModelLoadOptions options = parseOptions(key);
104 filesystem::Filesystem *fs =
105 ModuleManager::getInstance<filesystem::Filesystem>(
"Filesystem");
106 if (!fs) fs = filesystem::Filesystem::create();
107 if (!fs)
return nullptr;
109 EveFileSystem eveFs(fs);
110 medialoader::ModelLoader loader(&eveFs);
112 auto scene = loader.loadFromPath(path.c_str(), toMedialoader(options));
115 return new ModelData(std::move(scene),
"file://" + path);
116 }
catch (
const medialoader::Exception &e) {
124 static ModelLoader loader;
133 query +=
"triangulate=" + std::to_string(options.
triangulate ? 1 : 0);
136 query +=
"&flipuv=" + std::to_string(options.
flipUVs ? 1 : 0);
static std::string pathOfKey(const std::string &key)
The path part of a cache key (everything before the first '?').
static std::string makeKey(const std::string &path, const std::string &query="")
Build a cache key from a path and optional ?query parameters.
Resource is a game object that is managed by the ResourceManager. It can be loaded from a file or gen...
std::string modelCacheKey(const std::string &path, const ModelLoadOptions &options)
Build a deterministic ResourceManager cache key for path + options.
ModelLoadOptions modelOptionsFromKey(const std::string &key)
Parse the options back out of a model cache key (inverse of modelCacheKey).
Toggles for the Assimp post-processing steps applied by medialoader on decode. All default to on (mat...
bool improveCacheLocality
bool joinIdenticalVertices
bool generateNormalsIfMissing