1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
#include "assimp.h"
#include "assetFactory.h"
#include "collections.hpp"
#include "ptr.hpp"
#include "resource.h"
#include <assimp/cimport.h>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <future>
#include <stb/stb_image.h>
template<typename T>
glm::vec<3, T>
operator*(const aiVector3t<T> & v)
{
return {v.x, v.y, v.z};
}
template<typename T>
glm::vec<2, T>
operator!(const aiVector3t<T> & v)
{
return {v.x, v.y};
}
#define AIRANGE(parent, member) \
std::span \
{ \
(parent)->m##member, (parent)->mNum##member \
}
using SceneCPtr = std::shared_ptr<const aiScene>;
class AssImpNode : public Shape {
public:
AssImpNode(SceneCPtr scene, const aiNode * node) : scene(std::move(scene)), node(node) { }
SceneCPtr scene;
const aiNode * node;
CreatedFaces
createMesh(ModelFactoryMesh & mesh, float) const
{
CreatedFaces faces;
addMesh(faces, mesh, node);
return faces;
}
void
addMesh(CreatedFaces & faces, ModelFactoryMesh & mesh, const aiNode * node) const
{
for (const auto & m : AIRANGE(node, Meshes)) {
addMesh(faces, mesh, scene->mMeshes[m]);
}
for (const auto & n : AIRANGE(node, Children)) {
addMesh(faces, mesh, n);
}
}
void
addMesh(CreatedFaces & faces, ModelFactoryMesh & mesh, const aiMesh * amesh) const
{
const auto vhs = AIRANGE(amesh, Vertices) * [&mesh](auto && v) {
return mesh.add_vertex(*v);
};
const auto & m = *scene->mMaterials[amesh->mMaterialIndex];
GLuint material {};
if (auto mf = Persistence::ParseBase::getShared<AssetFactory>("assetFactory")) {
aiString path;
m.Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path);
material = mf->getMaterialIndex(path.C_Str());
}
for (const auto & f : AIRANGE(amesh, Faces)) {
const auto fvhs = AIRANGE(&f, Indices) * [&vhs](auto && i) {
return vhs[i];
};
const auto fh = faces.emplace(mesh.add_namedFace(amesh->mName.C_Str(), fvhs))->second;
if (amesh->HasTextureCoords(0)) {
for (auto idx = f.mIndices; const auto fheh : mesh.fh_range(fh)) {
const auto ouv = !amesh->mTextureCoords[0][*idx++];
mesh.set_texcoord2D(fheh, ouv);
mesh.property(mesh.materialFaceProperty, fh) = material;
}
}
}
}
};
void
AssImp::postLoad()
{
SceneCPtr scene {
aiImportFile(Resource::mapPath(path).c_str(), aiProcess_RemoveRedundantMaterials), &aiReleaseImport};
if (!scene) {
throw std::runtime_error("Failed to load asset library: " + path);
}
if (auto mf = Persistence::ParseBase::getShared<AssetFactory>("assetFactory")) {
const auto root = AIRANGE(scene->mRootNode, Children);
std::transform(
root.begin(), root.end(), std::inserter(mf->shapes, mf->shapes.end()), [&scene](const aiNode * m) {
return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared<AssImpNode>(scene, m)};
});
const auto textures = AIRANGE(scene, Textures);
auto textureFutures = textures * [](const aiTexture * t) {
return std::async(std::launch::async, [t]() {
auto texture = std::make_shared<TextureFragment>();
texture->id = texture->path = t->mFilename.C_Str();
texture->image = std::make_unique<Image>(
std::span {reinterpret_cast<unsigned char *>(t->pcData), t->mWidth}, STBI_rgb_alpha);
return texture;
});
};
std::transform(textureFutures.begin(), textureFutures.end(),
std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && textureFuture) {
auto texture = textureFuture.get();
return AssetFactory::TextureFragments::value_type {texture->id, texture};
});
}
}
bool
AssImp::persist(Persistence::PersistenceStore & store)
{
return STORE_TYPE && STORE_MEMBER(path);
}
|