Write one or more meshes to disk as a single scene.
115{
117
118 if (meshes.empty()) {
120 return false;
121 }
122
123 for (const auto& m : meshes) {
124 if (!m.is_valid()) {
126 return false;
127 }
128 if (m.layout.stride_bytes != sizeof(Kakshya::MeshVertex)) {
129 set_error(
"MeshData vertex stride is not the canonical MeshVertex layout");
130 return false;
131 }
132 }
133
134 const auto ext = extension_of(filepath);
135 std::string format_id = options.format_id;
136 if (format_id.empty()) {
137 format_id = default_format_id(ext);
138 }
139 if (format_id.empty()) {
140 set_error(
"No format_id resolved for extension '" + ext
141 + "', pass ModelWriteOptions::format_id explicitly");
142 return false;
143 }
144
145
146
147
148
149 aiScene scene;
150 scene.mRootNode = new aiNode();
151
152 scene.mNumMaterials = static_cast<unsigned int>(meshes.size());
153 scene.mMaterials = new aiMaterial*[scene.mNumMaterials];
154
155 scene.mNumMeshes = static_cast<unsigned int>(meshes.size());
156 scene.mMeshes = new aiMesh*[scene.mNumMeshes];
157
158 scene.mRootNode->mNumMeshes = scene.mNumMeshes;
159 scene.mRootNode->mMeshes = new unsigned int[scene.mNumMeshes];
160
161 for (unsigned int mi = 0; mi < scene.mNumMeshes; ++mi) {
162 const auto& mesh_data = meshes[mi];
163 const auto info = submesh_info_for(mesh_data);
164
165 auto* mat = new aiMaterial();
166 const std::string mat_name = !options.material_name_override.empty()
167 ? options.material_name_override
168 : (!info.material_name.empty() ? info.material_name : "material_" + std::to_string(mi));
169 aiString ai_mat_name(mat_name);
170 mat->AddProperty(&ai_mat_name, AI_MATKEY_NAME);
171 if (!info.diffuse_path.empty()) {
172 aiString tex_path(info.diffuse_path);
173 mat->AddProperty(&tex_path, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
174 }
175 scene.mMaterials[mi] = mat;
176
177 auto* mesh = new aiMesh();
178 mesh->mMaterialIndex = mi;
179 mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
180 mesh->mName = aiString(!info.name.empty() ? info.name :
"mesh_" +
std::
to_string(mi));
181
182 const auto* vb = std::get_if<std::vector<uint8_t>>(&mesh_data.vertex_variant);
183 const auto* ib = std::get_if<std::vector<uint32_t>>(&mesh_data.index_variant);
184
185 const auto* verts = reinterpret_cast<const Kakshya::MeshVertex*>(vb->data());
186 const size_t vertex_count = vb->size() / sizeof(Kakshya::MeshVertex);
187
188 mesh->mNumVertices = static_cast<unsigned int>(vertex_count);
189 mesh->mVertices = new aiVector3D[vertex_count];
190 mesh->mNormals = new aiVector3D[vertex_count];
191 mesh->mTangents = new aiVector3D[vertex_count];
192 mesh->mTextureCoords[0] = new aiVector3D[vertex_count];
193 mesh->mNumUVComponents[0] = 2;
194 mesh->mColors[0] = new aiColor4D[vertex_count];
195
196 for (size_t v = 0; v < vertex_count; ++v) {
197 const auto& mv = verts[v];
198 mesh->mVertices[v] = aiVector3D(mv.position.x, mv.position.y, mv.position.z);
199 mesh->mNormals[v] = aiVector3D(mv.normal.x, mv.normal.y, mv.normal.z);
200 mesh->mTangents[v] = aiVector3D(mv.tangent.x, mv.tangent.y, mv.tangent.z);
201 mesh->mTextureCoords[0][v] = aiVector3D(mv.uv.x, mv.uv.y, 0.0F);
202 mesh->mColors[0][v] = aiColor4D(mv.color.x, mv.color.y, mv.color.z, 1.0F);
203 }
204
205 const size_t face_count = ib->size() / 3;
206 mesh->mNumFaces = static_cast<unsigned int>(face_count);
207 mesh->mFaces = new aiFace[face_count];
208 for (size_t f = 0; f < face_count; ++f) {
209 auto& face = mesh->mFaces[f];
210 face.mNumIndices = 3;
211 face.mIndices = new unsigned int[3] {
212 (*ib)[(f * 3) + 0],
213 (*ib)[(f * 3) + 1],
214 (*ib)[(f * 3) + 2],
215 };
216 }
217
218 scene.mMeshes[mi] = mesh;
219 scene.mRootNode->mMeshes[mi] = mi;
220 }
221
222
224
225 Assimp::Exporter exporter;
226 const auto ret = exporter.Export(&scene, format_id, resolved);
227
228 if (ret != AI_SUCCESS) {
231 "AssimpModelWriter: export failed for '{}' (format '{}'): {}",
233 return false;
234 }
235
237 "AssimpModelWriter: wrote '{}', {} mesh(es), format '{}'",
238 resolved, meshes.size(), format_id);
239 return true;
240}
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
void set_error(std::string msg) const
std::string_view to_string(Keys key) noexcept
Converts a Keys enum value to its string representation.
std::string resolve_write_path(const std::string &filepath)
Anchor a relative output path to Config::SOURCE_DIR.
@ FileIO
Filesystem I/O operations.
@ IO
Networking, file handling, streaming.