12#include <assimp/matrix4x4.h>
13#include <assimp/mesh.h>
14#include <assimp/scene.h>
18#include <unordered_map>
29Texture *textureFromImageData(IResourceFactory *gfx, image::ImageData *img) {
30 if (!img)
return nullptr;
32 return gfx->newTexture(img);
38Texture *loadEmbeddedTexture(IResourceFactory *gfx, ModelData *
model,
int idx) {
39 image::ImageData *img =
model->getEmbeddedTextureImageData(
idx);
40 Texture *tex = textureFromImageData(gfx, img);
45std::string basenameOf(
const std::string &path) {
46 const size_t slash = path.find_last_of(
"/\\");
47 return slash == std::string::npos ? path : path.substr(slash + 1);
50Texture *loadExternalTexture(IResourceFactory *gfx,
const std::string &path) {
51 auto *fs = filesystem::Filesystem::create();
52 std::unique_ptr<filesystem::FileData> fd;
54 fd.reset(fs->read(path));
57 if (!fd || fd->getSize() == 0) {
58 const std::string base = basenameOf(path);
60 fd.reset(fs->read(base));
63 if (!fd || fd->getSize() == 0) {
65 fd.reset(fs->read(
"Textures/" + base));
70 if (!fd || fd->getSize() == 0)
return nullptr;
72 image::ImageData *img = image::Image::create()->newImageData(fd.get());
73 Texture *tex = textureFromImageData(gfx, img);
81Texture *loadTextureSlot(IResourceFactory *gfx, ModelData *
model,
int matIndex,
const std::string &
type) {
82 if (
model->getMaterialTextureSlotCount(matIndex,
type) <= 0)
return nullptr;
83 const int embedded =
model->getMaterialTextureEmbeddedIndex(matIndex,
type, 0);
84 if (embedded >= 0)
return loadEmbeddedTexture(gfx,
model, embedded);
85 const std::string path =
model->getMaterialTexturePath(matIndex,
type, 0);
86 if (path.empty())
return nullptr;
87 return loadExternalTexture(gfx, path);
99TextureLook materialLook(IResourceFactory *gfx, ModelData *
model,
int matIndex,
const ModelRenderOptions &options,
100 std::unordered_map<int, TextureLook> &cache) {
101 auto it = cache.find(matIndex);
102 if (it != cache.end())
return it->second;
106 look.tr =
model->getMaterialBaseColorR(matIndex);
107 look.tg =
model->getMaterialBaseColorG(matIndex);
108 look.tb =
model->getMaterialBaseColorB(matIndex);
109 look.ta =
model->getMaterialBaseColorA(matIndex);
110 look.metallic =
model->getMaterialMetallicFactor(matIndex);
111 look.roughness =
model->getMaterialRoughnessFactor(matIndex);
112 if (options.importAlbedo) {
113 look.albedo = loadTextureSlot(gfx,
model, matIndex,
"base_color");
114 if (!look.albedo) look.albedo = loadTextureSlot(gfx,
model, matIndex,
"diffuse");
116 if (options.importNormalMaps)
117 look.normal = loadTextureSlot(gfx,
model, matIndex,
"normals");
118 if (options.importHeightMaps)
119 look.height = loadTextureSlot(gfx,
model, matIndex,
"height");
121 cache.emplace(matIndex, look);
125Renderable3D *makeRenderable(IResourceFactory *gfx, ModelData *
model,
int meshIndex,
const aiMatrix4x4 &world,
126 const ModelRenderOptions &options, std::unordered_map<int, TextureLook> &cache) {
127 const aiScene *scene =
model->getScene();
128 if (!scene || meshIndex < 0 ||
static_cast<unsigned>(meshIndex) >= scene->mNumMeshes)
130 const aiMesh *ai = scene->mMeshes[meshIndex];
131 if (!ai || ai->mNumVertices == 0 || ai->mNumFaces == 0)
return nullptr;
133 Mesh *
mesh = options.bakeWorldTransform ? gfx->newMeshFromAssimp(*ai, world)
134 : gfx->newMeshFromAssimp(*ai);
135 if (!
mesh)
return nullptr;
137 const int matIndex =
model->getMaterialIndex(meshIndex);
138 const TextureLook look = materialLook(gfx,
model, matIndex, options, cache);
140 Renderable3D *ent = Renderable3D::create();
141 ent->meshRenderer()->visible =
true;
143 if (look.albedo) ent->setTexture(look.albedo);
144 if (look.normal) ent->setNormalTexture(look.normal);
145 if (look.height) ent->setHeightTexture(look.height);
146 ent->setTint(look.tr, look.tg, look.tb, look.ta);
147 ent->setMetallic(look.metallic);
148 ent->setRoughness(look.roughness);
152void walkNodes(
const aiNode *node,
const aiMatrix4x4 &
parent, IResourceFactory *gfx, ModelData *
model,
153 const ModelRenderOptions &options, std::vector<Renderable3D *> &out,
154 std::unordered_map<int, TextureLook> &cache) {
156 const aiMatrix4x4 world =
parent *
node->mTransformation;
157 for (
unsigned i = 0; i <
node->mNumMeshes; ++i) {
159 makeRenderable(gfx,
model,
static_cast<int>(
node->mMeshes[i]), world, options, cache);
160 if (ent) out.push_back(ent);
162 for (
unsigned c = 0;
c <
node->mNumChildren; ++
c)
163 walkNodes(
node->mChildren[
c], world, gfx,
model, options, out, cache);
166bool findMeshTransform(
const aiNode *node,
const aiMatrix4x4 &
parent,
unsigned meshIndex,
168 if (!node)
return false;
169 const aiMatrix4x4 world =
parent *
node->mTransformation;
170 for (
unsigned i = 0; i <
node->mNumMeshes; ++i) {
171 if (
node->mMeshes[i] == meshIndex) {
176 for (
unsigned c = 0;
c <
node->mNumChildren; ++
c)
177 if (findMeshTransform(
node->mChildren[
c], world, meshIndex, out))
return true;
185 if (!
model)
return nullptr;
186 const aiScene *scene =
model->getScene();
187 if (!scene || !scene->mRootNode)
return nullptr;
190 if (!findMeshTransform(scene->mRootNode, aiMatrix4x4(),
static_cast<unsigned>(meshIndex),
192 world = aiMatrix4x4();
194 std::unordered_map<int, TextureLook> cache;
195 return makeRenderable(&gfx,
model, meshIndex, world, options, cache);
200 std::vector<Renderable3D *> out;
201 if (!
model)
return out;
202 const aiScene *scene =
model->getScene();
203 if (!scene || !scene->mRootNode)
return out;
204 std::unordered_map<int, TextureLook> cache;
205 walkNodes(scene->mRootNode, aiMatrix4x4(), &gfx,
model, options, out, cache);
Texture / mesh / shader / canvas creation and release.
GPU mesh handle (+ optional CPU morph targets).
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
CPU-side decoded 3D model (Assimp scene owned via medialoader::ModelScene). Does not upload to GPU — ...
Renderable3D * buildRenderable(IResourceFactory &gfx, ModelData *model, int meshIndex, const ModelRenderOptions &options)
std::vector< Renderable3D * > buildRenderables(IResourceFactory &gfx, ModelData *model, const ModelRenderOptions &options)
NodeDesc node(std::string id, std::vector< NodeDesc > children, std::string name)