16#include "medialoader/Exception.h"
17#include "medialoader/model/ModelLoader.h"
29std::string extensionOf(
const std::string &
path) {
30 const auto pos =
path.find_last_of(
'.');
31 if (
pos == std::string::npos)
return {};
32 std::string ext =
path.substr(
pos);
33 for (
char &
c : ext)
c = static_cast<char>(
std::tolower(static_cast<unsigned char>(
c)));
37bool isModelPath(
const std::string &
path) {
38 const std::string ext = extensionOf(
path);
39 return ext ==
".obj" || ext ==
".fbx" || ext ==
".gltf" || ext ==
".glb" || ext ==
".vrm" || ext ==
".dae" ||
40 ext ==
".3ds" || ext ==
".blend" || ext ==
".stl" || ext ==
".ply" || ext ==
".x" || ext ==
".lwo" ||
41 ext ==
".lws" || ext ==
".md5mesh" || ext ==
".md5anim" || ext ==
".b3d" || ext ==
".csm" || ext ==
".irr" ||
42 ext ==
".irrmesh" || ext ==
".md2" || ext ==
".md3" || ext ==
".ms3d" || ext ==
".smd" || ext ==
".vta" ||
43 ext ==
".bvh" || ext ==
".ac" || ext ==
".off" || ext ==
".raw" || ext ==
".ter" || ext ==
".nff" ||
44 ext ==
".ndo" || ext ==
".evmodel";
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 {
108 if (!isModelPath(
path))
return nullptr;
109 const ModelLoadOptions
options = parseOptions(
key);
111 filesystem::Filesystem *fs =
112 ModuleManager::getInstance<filesystem::Filesystem>(
"Filesystem");
113 if (!fs) fs = filesystem::Filesystem::create();
114 if (!fs)
return nullptr;
116 if (extensionOf(
path) ==
".evmodel" || extensionOf(
path) ==
".vrm") {
117 filesystem::FileData *packedRaw = fs->read(
path);
118 if (!packedRaw)
return nullptr;
120 Model3D *
module = ModuleManager::getInstance<Model3D>("Model3D");
121 if (!module)
module = Model3D::create();
122 return module->newModelData(packed.get(), extensionOf(path), options);
125 EveFileSystem eveFs(fs);
126 medialoader::ModelLoader loader(&eveFs);
131 return new ModelData(std::move(scene),
"file://" +
path,
options.flipUVs);
132 }
catch (
const medialoader::Exception &e) {
140 static ModelLoader loader;
149 query +=
"triangulate=" + std::to_string(
options.triangulate ? 1 : 0);
150 query +=
"&normals=" + std::to_string(
options.generateNormalsIfMissing ? 1 : 0);
151 query +=
"&join=" + std::to_string(
options.joinIdenticalVertices ? 1 : 0);
152 query +=
"&flipuv=" + std::to_string(
options.flipUVs ? 1 : 0);
153 query +=
"&cache=" + std::to_string(
options.improveCacheLocality ? 1 : 0);
std::array< double, 10 > q
std::weak_ptr< PrimitiveScene > scene
const SquirrelValueOptions & options
EVENGINE_API_FOUNDATION public API.
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...
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
EVENGINE_API_FOUNDATION public API.
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).
std::unique_ptr< T > Owned
C++ owning storage used by an object factory.
Toggles for the Assimp post-processing steps applied by medialoader on decode. All default to on (mat...