/src/assimp/code/AssetLib/B3D/B3DImporter.cpp
Line | Count | Source |
1 | | /* |
2 | | --------------------------------------------------------------------------- |
3 | | Open Asset Import Library (assimp) |
4 | | --------------------------------------------------------------------------- |
5 | | |
6 | | Copyright (c) 2006-2026, assimp team |
7 | | |
8 | | All rights reserved. |
9 | | |
10 | | Redistribution and use of this software in source and binary forms, |
11 | | with or without modification, are permitted provided that the following |
12 | | conditions are met: |
13 | | |
14 | | * Redistributions of source code must retain the above |
15 | | copyright notice, this list of conditions and the |
16 | | following disclaimer. |
17 | | |
18 | | * Redistributions in binary form must reproduce the above |
19 | | copyright notice, this list of conditions and the |
20 | | following disclaimer in the documentation and/or other |
21 | | materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the assimp team, nor the names of its |
24 | | contributors may be used to endorse or promote products |
25 | | derived from this software without specific prior |
26 | | written permission of the assimp team. |
27 | | |
28 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
29 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
31 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
32 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
33 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
34 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
35 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
36 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
37 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
38 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
39 | | --------------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | /** @file B3DImporter.cpp |
43 | | * @brief Implementation of the b3d importer class |
44 | | */ |
45 | | |
46 | | #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER |
47 | | |
48 | | // internal headers |
49 | | #include "B3DImporter.h" |
50 | | #include "PostProcessing/ConvertToLHProcess.h" |
51 | | #include "PostProcessing/TextureTransform.h" |
52 | | |
53 | | #include <assimp/StringUtils.h> |
54 | | #include <assimp/anim.h> |
55 | | #include <assimp/importerdesc.h> |
56 | | #include <assimp/scene.h> |
57 | | #include <assimp/DefaultLogger.hpp> |
58 | | #include <assimp/IOSystem.hpp> |
59 | | |
60 | | #include <memory> |
61 | | |
62 | | namespace Assimp { |
63 | | using namespace std; |
64 | | |
65 | | static constexpr aiImporterDesc desc = { |
66 | | "BlitzBasic 3D Importer", |
67 | | "", |
68 | | "", |
69 | | "http://www.blitzbasic.com/", |
70 | | aiImporterFlags_SupportBinaryFlavour, |
71 | | 0, |
72 | | 0, |
73 | | 0, |
74 | | 0, |
75 | | "b3d" |
76 | | }; |
77 | | |
78 | | #ifdef _MSC_VER |
79 | | #pragma warning(disable : 4018) |
80 | | #endif |
81 | | |
82 | | // #define DEBUG_B3D |
83 | | |
84 | | template <typename T> |
85 | 0 | void DeleteAllBarePointers(std::vector<T> &x) { |
86 | 0 | for (auto p : x) { |
87 | 0 | delete p; |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | 40.6k | B3DImporter::~B3DImporter() = default; |
92 | | |
93 | | // ------------------------------------------------------------------------------------------------ |
94 | 0 | bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const { |
95 | 0 | size_t pos = pFile.find_last_of('.'); |
96 | 0 | if (pos == string::npos) { |
97 | 0 | return false; |
98 | 0 | } |
99 | | |
100 | 0 | string ext = pFile.substr(pos + 1); |
101 | 0 | if (ext.size() != 3) { |
102 | 0 | return false; |
103 | 0 | } |
104 | | |
105 | 0 | return (ext[0] == 'b' || ext[0] == 'B') && (ext[1] == '3') && (ext[2] == 'd' || ext[2] == 'D'); |
106 | 0 | } |
107 | | |
108 | | // ------------------------------------------------------------------------------------------------ |
109 | | // Loader meta information |
110 | 40.6k | const aiImporterDesc *B3DImporter::GetInfo() const { |
111 | 40.6k | return &desc; |
112 | 40.6k | } |
113 | | |
114 | | // ------------------------------------------------------------------------------------------------ |
115 | 0 | void B3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { |
116 | 0 | std::unique_ptr<IOStream> file(pIOHandler->Open(pFile)); |
117 | | |
118 | | // Check whether we can read from the file |
119 | 0 | if (file == nullptr) { |
120 | 0 | throw DeadlyImportError("Failed to open B3D file ", pFile, "."); |
121 | 0 | } |
122 | | |
123 | | // check whether the .b3d file is large enough to contain |
124 | | // at least one chunk. |
125 | 0 | size_t fileSize = file->FileSize(); |
126 | 0 | if (fileSize < 8) { |
127 | 0 | throw DeadlyImportError("B3D File is too small."); |
128 | 0 | } |
129 | | |
130 | 0 | _pos = 0; |
131 | 0 | _buf.resize(fileSize); |
132 | 0 | file->Read(&_buf[0], 1, fileSize); |
133 | 0 | _stack.clear(); |
134 | |
|
135 | 0 | ReadBB3D(pScene); |
136 | 0 | } |
137 | | |
138 | | // ------------------------------------------------------------------------------------------------ |
139 | 0 | AI_WONT_RETURN void B3DImporter::Oops() { |
140 | 0 | throw DeadlyImportError("B3D Importer - INTERNAL ERROR"); |
141 | 0 | } |
142 | | |
143 | | // ------------------------------------------------------------------------------------------------ |
144 | 0 | AI_WONT_RETURN void B3DImporter::Fail(const string &str) { |
145 | | #ifdef DEBUG_B3D |
146 | | ASSIMP_LOG_ERROR("Error in B3D file data: ", str); |
147 | | #endif |
148 | 0 | throw DeadlyImportError("B3D Importer - error in B3D file data: ", str); |
149 | 0 | } |
150 | | |
151 | | // ------------------------------------------------------------------------------------------------ |
152 | 0 | int B3DImporter::ReadByte() { |
153 | 0 | if (_pos >= _buf.size()) { |
154 | 0 | Fail("EOF"); |
155 | 0 | } |
156 | |
|
157 | 0 | return _buf[_pos++]; |
158 | 0 | } |
159 | | |
160 | | // ------------------------------------------------------------------------------------------------ |
161 | 0 | int B3DImporter::ReadInt() { |
162 | 0 | if (_pos + 4 > _buf.size()) { |
163 | 0 | Fail("EOF"); |
164 | 0 | } |
165 | |
|
166 | 0 | int n; |
167 | 0 | memcpy(&n, &_buf[_pos], 4); |
168 | 0 | _pos += 4; |
169 | |
|
170 | 0 | return n; |
171 | 0 | } |
172 | | |
173 | | // ------------------------------------------------------------------------------------------------ |
174 | 0 | float B3DImporter::ReadFloat() { |
175 | 0 | if (_pos + 4 > _buf.size()) { |
176 | 0 | Fail("EOF"); |
177 | 0 | } |
178 | |
|
179 | 0 | float n; |
180 | 0 | memcpy(&n, &_buf[_pos], 4); |
181 | 0 | _pos += 4; |
182 | |
|
183 | 0 | return n; |
184 | 0 | } |
185 | | |
186 | | // ------------------------------------------------------------------------------------------------ |
187 | 0 | aiVector2D B3DImporter::ReadVec2() { |
188 | 0 | float x = ReadFloat(); |
189 | 0 | float y = ReadFloat(); |
190 | 0 | return aiVector2D(x, y); |
191 | 0 | } |
192 | | |
193 | | // ------------------------------------------------------------------------------------------------ |
194 | 0 | aiVector3D B3DImporter::ReadVec3() { |
195 | 0 | float x = ReadFloat(); |
196 | 0 | float y = ReadFloat(); |
197 | 0 | float z = ReadFloat(); |
198 | 0 | return aiVector3D(x, y, z); |
199 | 0 | } |
200 | | |
201 | | // ------------------------------------------------------------------------------------------------ |
202 | 0 | aiQuaternion B3DImporter::ReadQuat() { |
203 | | // (aramis_acg) Fix to adapt the loader to changed quat orientation |
204 | 0 | float w = -ReadFloat(); |
205 | 0 | float x = ReadFloat(); |
206 | 0 | float y = ReadFloat(); |
207 | 0 | float z = ReadFloat(); |
208 | 0 | return aiQuaternion(w, x, y, z); |
209 | 0 | } |
210 | | |
211 | | // ------------------------------------------------------------------------------------------------ |
212 | 0 | string B3DImporter::ReadString() { |
213 | 0 | if (_pos > _buf.size()) { |
214 | 0 | Fail("EOF"); |
215 | 0 | } |
216 | 0 | string str; |
217 | 0 | while (_pos < _buf.size()) { |
218 | 0 | char c = (char)ReadByte(); |
219 | 0 | if (!c) { |
220 | 0 | return str; |
221 | 0 | } |
222 | 0 | str += c; |
223 | 0 | } |
224 | 0 | return string(); |
225 | 0 | } |
226 | | |
227 | | // ------------------------------------------------------------------------------------------------ |
228 | 0 | string B3DImporter::ReadChunk() { |
229 | 0 | string tag; |
230 | 0 | for (int i = 0; i < 4; ++i) { |
231 | 0 | tag += char(ReadByte()); |
232 | 0 | } |
233 | | #ifdef DEBUG_B3D |
234 | | ASSIMP_LOG_DEBUG("ReadChunk: ", tag); |
235 | | #endif |
236 | 0 | unsigned sz = (unsigned)ReadInt(); |
237 | 0 | _stack.push_back(_pos + sz); |
238 | 0 | return tag; |
239 | 0 | } |
240 | | |
241 | | // ------------------------------------------------------------------------------------------------ |
242 | 0 | void B3DImporter::ExitChunk() { |
243 | 0 | _pos = _stack.back(); |
244 | 0 | _stack.pop_back(); |
245 | 0 | } |
246 | | |
247 | | // ------------------------------------------------------------------------------------------------ |
248 | 0 | size_t B3DImporter::ChunkSize() { |
249 | 0 | return _stack.back() - _pos; |
250 | 0 | } |
251 | | // ------------------------------------------------------------------------------------------------ |
252 | | |
253 | | template <class T> |
254 | 0 | T *B3DImporter::to_array(const vector<T> &v) { |
255 | 0 | if (v.empty()) { |
256 | 0 | return nullptr; |
257 | 0 | } |
258 | 0 | T *p = new T[v.size()]; |
259 | 0 | for (size_t i = 0; i < v.size(); ++i) { |
260 | 0 | p[i] = v[i]; |
261 | 0 | } |
262 | 0 | return p; |
263 | 0 | } Unexecuted instantiation: aiVectorKey* Assimp::B3DImporter::to_array<aiVectorKey>(std::__1::vector<aiVectorKey, std::__1::allocator<aiVectorKey> > const&) Unexecuted instantiation: aiQuatKey* Assimp::B3DImporter::to_array<aiQuatKey>(std::__1::vector<aiQuatKey, std::__1::allocator<aiQuatKey> > const&) Unexecuted instantiation: unsigned int* Assimp::B3DImporter::to_array<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&) Unexecuted instantiation: aiNode** Assimp::B3DImporter::to_array<aiNode*>(std::__1::vector<aiNode*, std::__1::allocator<aiNode*> > const&) Unexecuted instantiation: aiVertexWeight* Assimp::B3DImporter::to_array<aiVertexWeight>(std::__1::vector<aiVertexWeight, std::__1::allocator<aiVertexWeight> > const&) Unexecuted instantiation: aiBone** Assimp::B3DImporter::to_array<aiBone*>(std::__1::vector<aiBone*, std::__1::allocator<aiBone*> > const&) |
264 | | |
265 | | // ------------------------------------------------------------------------------------------------ |
266 | | template <class T> |
267 | 0 | T **unique_to_array(vector<std::unique_ptr<T>> &v) { |
268 | 0 | if (v.empty()) { |
269 | 0 | return nullptr; |
270 | 0 | } |
271 | 0 | T **p = new T *[v.size()]; |
272 | 0 | for (size_t i = 0; i < v.size(); ++i) { |
273 | 0 | p[i] = v[i].release(); |
274 | 0 | } |
275 | 0 | return p; |
276 | 0 | } Unexecuted instantiation: aiMaterial** Assimp::unique_to_array<aiMaterial>(std::__1::vector<std::__1::unique_ptr<aiMaterial, std::__1::default_delete<aiMaterial> >, std::__1::allocator<std::__1::unique_ptr<aiMaterial, std::__1::default_delete<aiMaterial> > > >&) Unexecuted instantiation: aiMesh** Assimp::unique_to_array<aiMesh>(std::__1::vector<std::__1::unique_ptr<aiMesh, std::__1::default_delete<aiMesh> >, std::__1::allocator<std::__1::unique_ptr<aiMesh, std::__1::default_delete<aiMesh> > > >&) Unexecuted instantiation: aiNodeAnim** Assimp::unique_to_array<aiNodeAnim>(std::__1::vector<std::__1::unique_ptr<aiNodeAnim, std::__1::default_delete<aiNodeAnim> >, std::__1::allocator<std::__1::unique_ptr<aiNodeAnim, std::__1::default_delete<aiNodeAnim> > > >&) Unexecuted instantiation: aiAnimation** Assimp::unique_to_array<aiAnimation>(std::__1::vector<std::__1::unique_ptr<aiAnimation, std::__1::default_delete<aiAnimation> >, std::__1::allocator<std::__1::unique_ptr<aiAnimation, std::__1::default_delete<aiAnimation> > > >&) |
277 | | |
278 | | // ------------------------------------------------------------------------------------------------ |
279 | 0 | void B3DImporter::ReadTEXS() { |
280 | 0 | while (ChunkSize()) { |
281 | 0 | string name = ReadString(); |
282 | 0 | /*int flags=*/ReadInt(); |
283 | 0 | /*int blend=*/ReadInt(); |
284 | 0 | /*aiVector2D pos=*/ReadVec2(); |
285 | 0 | /*aiVector2D scale=*/ReadVec2(); |
286 | 0 | /*float rot=*/ReadFloat(); |
287 | |
|
288 | 0 | _textures.push_back(name); |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | | // ------------------------------------------------------------------------------------------------ |
293 | 0 | void B3DImporter::ReadBRUS() { |
294 | 0 | int n_texs = ReadInt(); |
295 | 0 | if (n_texs < 0 || n_texs > 8) { |
296 | 0 | Fail("Bad texture count"); |
297 | 0 | } |
298 | 0 | while (ChunkSize()) { |
299 | 0 | string name = ReadString(); |
300 | 0 | aiVector3D color = ReadVec3(); |
301 | 0 | float alpha = ReadFloat(); |
302 | 0 | float shiny = ReadFloat(); |
303 | 0 | /*int blend=**/ ReadInt(); |
304 | 0 | int fx = ReadInt(); |
305 | |
|
306 | 0 | std::unique_ptr<aiMaterial> mat(new aiMaterial); |
307 | | |
308 | | // Name |
309 | 0 | aiString ainame(name); |
310 | 0 | mat->AddProperty(&ainame, AI_MATKEY_NAME); |
311 | | |
312 | | // Diffuse color |
313 | 0 | mat->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE); |
314 | | |
315 | | // Opacity |
316 | 0 | mat->AddProperty(&alpha, 1, AI_MATKEY_OPACITY); |
317 | | |
318 | | // Specular color |
319 | 0 | aiColor3D speccolor(shiny, shiny, shiny); |
320 | 0 | mat->AddProperty(&speccolor, 1, AI_MATKEY_COLOR_SPECULAR); |
321 | | |
322 | | // Specular power |
323 | 0 | float specpow = shiny * 128; |
324 | 0 | mat->AddProperty(&specpow, 1, AI_MATKEY_SHININESS); |
325 | | |
326 | | // Double sided |
327 | 0 | if (fx & 0x10) { |
328 | 0 | int i = 1; |
329 | 0 | mat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED); |
330 | 0 | } |
331 | | |
332 | | // Textures |
333 | 0 | for (int i = 0; i < n_texs; ++i) { |
334 | 0 | int texid = ReadInt(); |
335 | 0 | if (texid < -1 || (texid >= 0 && texid >= static_cast<int>(_textures.size()))) { |
336 | 0 | Fail("Bad texture id"); |
337 | 0 | } |
338 | 0 | if (i == 0 && texid >= 0) { |
339 | 0 | aiString texname(_textures[texid]); |
340 | 0 | mat->AddProperty(&texname, AI_MATKEY_TEXTURE_DIFFUSE(0)); |
341 | 0 | } |
342 | 0 | } |
343 | 0 | _materials.emplace_back(std::move(mat)); |
344 | 0 | } |
345 | 0 | } |
346 | | |
347 | | // ------------------------------------------------------------------------------------------------ |
348 | 0 | void B3DImporter::ReadVRTS() { |
349 | 0 | _vflags = ReadInt(); |
350 | 0 | _tcsets = ReadInt(); |
351 | 0 | _tcsize = ReadInt(); |
352 | 0 | if (_tcsets < 0 || _tcsets > 4 || _tcsize < 0 || _tcsize > 4) { |
353 | 0 | Fail("Bad texcoord data"); |
354 | 0 | } |
355 | |
|
356 | 0 | int sz = 12 + (_vflags & 1 ? 12 : 0) + (_vflags & 2 ? 16 : 0) + (_tcsets * _tcsize * 4); |
357 | 0 | size_t n_verts = ChunkSize() / sz; |
358 | |
|
359 | 0 | int v0 = static_cast<int>(_vertices.size()); |
360 | 0 | _vertices.resize(v0 + n_verts); |
361 | |
|
362 | 0 | for (unsigned int i = 0; i < n_verts; ++i) { |
363 | 0 | Vertex &v = _vertices[v0 + i]; |
364 | |
|
365 | 0 | memset(v.bones, 0, sizeof(v.bones)); |
366 | 0 | memset(v.weights, 0, sizeof(v.weights)); |
367 | |
|
368 | 0 | v.vertex = ReadVec3(); |
369 | |
|
370 | 0 | if (_vflags & 1) { |
371 | 0 | v.normal = ReadVec3(); |
372 | 0 | } |
373 | |
|
374 | 0 | if (_vflags & 2) { |
375 | 0 | ReadQuat(); // skip v 4bytes... |
376 | 0 | } |
377 | |
|
378 | 0 | for (int j = 0; j < _tcsets; ++j) { |
379 | 0 | float t[4] = { 0, 0, 0, 0 }; |
380 | 0 | for (int k = 0; k < _tcsize; ++k) { |
381 | 0 | t[k] = ReadFloat(); |
382 | 0 | } |
383 | 0 | t[1] = 1 - t[1]; |
384 | 0 | if (!j) { |
385 | 0 | v.texcoords = aiVector3D(t[0], t[1], t[2]); |
386 | 0 | } |
387 | 0 | } |
388 | 0 | } |
389 | 0 | } |
390 | | |
391 | | // ------------------------------------------------------------------------------------------------ |
392 | 0 | void B3DImporter::ReadTRIS(int v0) { |
393 | 0 | int matid = ReadInt(); |
394 | 0 | if (matid == -1) { |
395 | 0 | matid = 0; |
396 | 0 | } else if (matid < 0 || matid >= (int)_materials.size()) { |
397 | | #ifdef DEBUG_B3D |
398 | | ASSIMP_LOG_ERROR("material id=", matid); |
399 | | #endif |
400 | 0 | Fail("Bad material id"); |
401 | 0 | } |
402 | |
|
403 | 0 | std::unique_ptr<aiMesh> mesh(new aiMesh); |
404 | |
|
405 | 0 | mesh->mMaterialIndex = matid; |
406 | 0 | mesh->mNumFaces = 0; |
407 | 0 | mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; |
408 | |
|
409 | 0 | size_t n_tris = ChunkSize() / 12; |
410 | 0 | aiFace *face = mesh->mFaces = new aiFace[n_tris]; |
411 | |
|
412 | 0 | for (unsigned int i = 0; i < n_tris; ++i) { |
413 | 0 | int i0 = ReadInt() + v0; |
414 | 0 | int i1 = ReadInt() + v0; |
415 | 0 | int i2 = ReadInt() + v0; |
416 | 0 | if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) { |
417 | | #ifdef DEBUG_B3D |
418 | | ASSIMP_LOG_ERROR("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2); |
419 | | #endif |
420 | 0 | Fail("Bad triangle index"); |
421 | 0 | } |
422 | 0 | face->mNumIndices = 3; |
423 | 0 | face->mIndices = new unsigned[3]; |
424 | 0 | face->mIndices[0] = i0; |
425 | 0 | face->mIndices[1] = i1; |
426 | 0 | face->mIndices[2] = i2; |
427 | 0 | ++mesh->mNumFaces; |
428 | 0 | ++face; |
429 | 0 | } |
430 | |
|
431 | 0 | _meshes.emplace_back(std::move(mesh)); |
432 | 0 | } |
433 | | |
434 | | // ------------------------------------------------------------------------------------------------ |
435 | 0 | void B3DImporter::ReadMESH() { |
436 | 0 | /*int matid=*/ReadInt(); |
437 | |
|
438 | 0 | int v0 = static_cast<int>(_vertices.size()); |
439 | |
|
440 | 0 | while (ChunkSize()) { |
441 | 0 | string t = ReadChunk(); |
442 | 0 | if (t == "VRTS") { |
443 | 0 | ReadVRTS(); |
444 | 0 | } else if (t == "TRIS") { |
445 | 0 | ReadTRIS(v0); |
446 | 0 | } |
447 | 0 | ExitChunk(); |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | | // ------------------------------------------------------------------------------------------------ |
452 | 0 | void B3DImporter::ReadBONE(int id) { |
453 | 0 | while (ChunkSize()) { |
454 | 0 | int vertex = ReadInt(); |
455 | 0 | float weight = ReadFloat(); |
456 | 0 | if (vertex < 0 || vertex >= (int)_vertices.size()) { |
457 | 0 | Fail("Bad vertex index"); |
458 | 0 | } |
459 | |
|
460 | 0 | Vertex &v = _vertices[vertex]; |
461 | 0 | for (int i = 0; i < 4; ++i) { |
462 | 0 | if (!v.weights[i]) { |
463 | 0 | v.bones[i] = static_cast<unsigned char>(id); |
464 | 0 | v.weights[i] = weight; |
465 | 0 | break; |
466 | 0 | } |
467 | 0 | } |
468 | 0 | } |
469 | 0 | } |
470 | | |
471 | | // ------------------------------------------------------------------------------------------------ |
472 | 0 | void B3DImporter::ReadKEYS(AnimKeys& keys) { |
473 | 0 | vector<aiVectorKey>& trans = keys.positionKeys; |
474 | 0 | vector<aiVectorKey>& scale = keys.scalingKeys; |
475 | 0 | vector<aiQuatKey>& rot = keys.rotationKeys; |
476 | |
|
477 | 0 | int flags = ReadInt(); |
478 | 0 | while (ChunkSize()) { |
479 | 0 | int frame = ReadInt(); |
480 | 0 | if (flags & 1) { |
481 | 0 | trans.emplace_back(frame, ReadVec3()); |
482 | 0 | } |
483 | 0 | if (flags & 2) { |
484 | 0 | scale.emplace_back(frame, ReadVec3()); |
485 | 0 | } |
486 | 0 | if (flags & 4) { |
487 | 0 | rot.emplace_back(frame, ReadQuat()); |
488 | 0 | } |
489 | 0 | } |
490 | 0 | } |
491 | | |
492 | | // ------------------------------------------------------------------------------------------------ |
493 | 0 | void B3DImporter::ReadANIM() { |
494 | 0 | /*int flags=*/ReadInt(); |
495 | 0 | int frames = ReadInt(); |
496 | 0 | float fps = ReadFloat(); |
497 | |
|
498 | 0 | std::unique_ptr<aiAnimation> anim(new aiAnimation); |
499 | |
|
500 | 0 | anim->mDuration = frames; |
501 | 0 | anim->mTicksPerSecond = fps; |
502 | 0 | _animations.emplace_back(std::move(anim)); |
503 | 0 | } |
504 | | |
505 | | // ------------------------------------------------------------------------------------------------ |
506 | 0 | aiNode *B3DImporter::ReadNODE(aiNode *parent) { |
507 | |
|
508 | 0 | string name = ReadString(); |
509 | 0 | aiVector3D t = ReadVec3(); |
510 | 0 | aiVector3D s = ReadVec3(); |
511 | 0 | aiQuaternion r = ReadQuat(); |
512 | |
|
513 | 0 | aiMatrix4x4 trans, scale, rot; |
514 | |
|
515 | 0 | aiMatrix4x4::Translation(t, trans); |
516 | 0 | aiMatrix4x4::Scaling(s, scale); |
517 | 0 | rot = aiMatrix4x4(r.GetMatrix()); |
518 | |
|
519 | 0 | aiMatrix4x4 tform = trans * rot * scale; |
520 | |
|
521 | 0 | int nodeid = static_cast<int>(_nodes.size()); |
522 | |
|
523 | 0 | aiNode *node = new aiNode(name); |
524 | 0 | _nodes.push_back(node); |
525 | |
|
526 | 0 | node->mParent = parent; |
527 | 0 | node->mTransformation = tform; |
528 | |
|
529 | 0 | std::unique_ptr<aiNodeAnim> nodeAnim; |
530 | 0 | vector<unsigned> meshes; |
531 | 0 | vector<aiNode *> children; |
532 | 0 | AnimKeys keys; |
533 | |
|
534 | 0 | while (ChunkSize()) { |
535 | 0 | const string chunk = ReadChunk(); |
536 | 0 | if (chunk == "MESH") { |
537 | 0 | unsigned int n = static_cast<unsigned int>(_meshes.size()); |
538 | 0 | ReadMESH(); |
539 | 0 | for (unsigned int i = n; i < static_cast<unsigned int>(_meshes.size()); ++i) { |
540 | 0 | meshes.push_back(i); |
541 | 0 | } |
542 | 0 | } else if (chunk == "BONE") { |
543 | 0 | ReadBONE(nodeid); |
544 | 0 | } else if (chunk == "ANIM") { |
545 | 0 | ReadANIM(); |
546 | 0 | } else if (chunk == "KEYS") { |
547 | 0 | if (!nodeAnim) { |
548 | 0 | nodeAnim.reset(new aiNodeAnim); |
549 | 0 | nodeAnim->mNodeName = node->mName; |
550 | 0 | } |
551 | 0 | ReadKEYS(keys); |
552 | 0 | } else if (chunk == "NODE") { |
553 | 0 | aiNode *child = ReadNODE(node); |
554 | 0 | children.push_back(child); |
555 | 0 | } |
556 | 0 | ExitChunk(); |
557 | 0 | } |
558 | |
|
559 | 0 | if (nodeAnim) { |
560 | 0 | if (!keys.positionKeys.empty()) { |
561 | 0 | nodeAnim->mNumPositionKeys = static_cast<unsigned int>(keys.positionKeys.size()); |
562 | 0 | nodeAnim->mPositionKeys = to_array(keys.positionKeys); |
563 | 0 | } |
564 | |
|
565 | 0 | if (!keys.scalingKeys.empty()) { |
566 | 0 | nodeAnim->mNumScalingKeys = static_cast<unsigned int>(keys.scalingKeys.size()); |
567 | 0 | nodeAnim->mScalingKeys = to_array(keys.scalingKeys); |
568 | 0 | } |
569 | |
|
570 | 0 | if (!keys.rotationKeys.empty()) { |
571 | 0 | nodeAnim->mNumRotationKeys = static_cast<unsigned int>(keys.rotationKeys.size()); |
572 | 0 | nodeAnim->mRotationKeys = to_array(keys.rotationKeys); |
573 | 0 | } |
574 | |
|
575 | 0 | _nodeAnims.emplace_back(std::move(nodeAnim)); |
576 | 0 | } |
577 | |
|
578 | 0 | node->mNumMeshes = static_cast<unsigned int>(meshes.size()); |
579 | 0 | node->mMeshes = to_array(meshes); |
580 | |
|
581 | 0 | node->mNumChildren = static_cast<unsigned int>(children.size()); |
582 | 0 | node->mChildren = to_array(children); |
583 | |
|
584 | 0 | return node; |
585 | 0 | } |
586 | | |
587 | | // ------------------------------------------------------------------------------------------------ |
588 | 0 | void B3DImporter::ReadBB3D(aiScene *scene) { |
589 | |
|
590 | 0 | _textures.clear(); |
591 | |
|
592 | 0 | _materials.clear(); |
593 | |
|
594 | 0 | _vertices.clear(); |
595 | |
|
596 | 0 | _meshes.clear(); |
597 | |
|
598 | 0 | DeleteAllBarePointers(_nodes); |
599 | 0 | _nodes.clear(); |
600 | |
|
601 | 0 | _nodeAnims.clear(); |
602 | |
|
603 | 0 | _animations.clear(); |
604 | |
|
605 | 0 | string t = ReadChunk(); |
606 | 0 | if (t == "BB3D") { |
607 | 0 | int version = ReadInt(); |
608 | |
|
609 | 0 | if (!DefaultLogger::isNullLogger()) { |
610 | 0 | char dmp[128]; |
611 | 0 | ai_snprintf(dmp, 128, "B3D file format version: %i", version); |
612 | 0 | ASSIMP_LOG_INFO(dmp); |
613 | 0 | } |
614 | |
|
615 | 0 | while (ChunkSize()) { |
616 | 0 | const string chunk = ReadChunk(); |
617 | 0 | if (chunk == "TEXS") { |
618 | 0 | ReadTEXS(); |
619 | 0 | } else if (chunk == "BRUS") { |
620 | 0 | ReadBRUS(); |
621 | 0 | } else if (chunk == "NODE") { |
622 | 0 | ReadNODE(nullptr); |
623 | 0 | } |
624 | 0 | ExitChunk(); |
625 | 0 | } |
626 | 0 | } |
627 | 0 | ExitChunk(); |
628 | |
|
629 | 0 | if (!_nodes.size()) { |
630 | 0 | Fail("No nodes"); |
631 | 0 | } |
632 | |
|
633 | 0 | if (!_meshes.size()) { |
634 | 0 | Fail("No meshes"); |
635 | 0 | } |
636 | | |
637 | | // Fix nodes/meshes/bones |
638 | 0 | for (size_t i = 0; i < _nodes.size(); ++i) { |
639 | 0 | aiNode *node = _nodes[i]; |
640 | |
|
641 | 0 | for (size_t j = 0; j < node->mNumMeshes; ++j) { |
642 | 0 | aiMesh *mesh = _meshes[node->mMeshes[j]].get(); |
643 | |
|
644 | 0 | int n_tris = mesh->mNumFaces; |
645 | 0 | int n_verts = mesh->mNumVertices = n_tris * 3; |
646 | |
|
647 | 0 | aiVector3D *mv = mesh->mVertices = new aiVector3D[n_verts], *mn = nullptr, *mc = nullptr; |
648 | 0 | if (_vflags & 1) { |
649 | 0 | mn = mesh->mNormals = new aiVector3D[n_verts]; |
650 | 0 | } |
651 | 0 | if (_tcsets) { |
652 | 0 | mc = mesh->mTextureCoords[0] = new aiVector3D[n_verts]; |
653 | 0 | } |
654 | |
|
655 | 0 | aiFace *face = mesh->mFaces; |
656 | |
|
657 | 0 | vector<vector<aiVertexWeight>> vweights(_nodes.size()); |
658 | |
|
659 | 0 | for (int vertIdx = 0; vertIdx < n_verts; vertIdx += 3) { |
660 | 0 | for (int faceIndex = 0; faceIndex < 3; ++faceIndex) { |
661 | 0 | Vertex &v = _vertices[face->mIndices[faceIndex]]; |
662 | |
|
663 | 0 | *mv++ = v.vertex; |
664 | 0 | if (mn) *mn++ = v.normal; |
665 | 0 | if (mc) *mc++ = v.texcoords; |
666 | |
|
667 | 0 | face->mIndices[faceIndex] = vertIdx + faceIndex; |
668 | |
|
669 | 0 | for (int k = 0; k < 4; ++k) { |
670 | 0 | if (!v.weights[k]) |
671 | 0 | break; |
672 | | |
673 | 0 | int bone = v.bones[k]; |
674 | 0 | float weight = v.weights[k]; |
675 | |
|
676 | 0 | vweights[bone].emplace_back(vertIdx + faceIndex, weight); |
677 | 0 | } |
678 | 0 | } |
679 | 0 | ++face; |
680 | 0 | } |
681 | |
|
682 | 0 | vector<aiBone *> bones; |
683 | 0 | for (size_t weightIndx = 0; weightIndx < vweights.size(); ++weightIndx) { |
684 | 0 | vector<aiVertexWeight> &weights = vweights[weightIndx]; |
685 | 0 | if (!weights.size()) { |
686 | 0 | continue; |
687 | 0 | } |
688 | | |
689 | 0 | aiBone *bone = new aiBone; |
690 | 0 | bones.push_back(bone); |
691 | |
|
692 | 0 | aiNode *bnode = _nodes[weightIndx]; |
693 | |
|
694 | 0 | bone->mName = bnode->mName; |
695 | 0 | bone->mNumWeights = static_cast<unsigned int>(weights.size()); |
696 | 0 | bone->mWeights = to_array(weights); |
697 | |
|
698 | 0 | aiMatrix4x4 mat = bnode->mTransformation; |
699 | 0 | while (bnode->mParent) { |
700 | 0 | bnode = bnode->mParent; |
701 | 0 | mat = bnode->mTransformation * mat; |
702 | 0 | } |
703 | 0 | bone->mOffsetMatrix = mat.Inverse(); |
704 | 0 | } |
705 | 0 | mesh->mNumBones = static_cast<unsigned int>(bones.size()); |
706 | 0 | mesh->mBones = to_array(bones); |
707 | 0 | } |
708 | 0 | } |
709 | | |
710 | | // nodes |
711 | 0 | scene->mRootNode = _nodes[0]; |
712 | 0 | _nodes.clear(); // node ownership now belongs to scene |
713 | | |
714 | | // material |
715 | 0 | if (!_materials.size()) { |
716 | 0 | _materials.emplace_back(std::unique_ptr<aiMaterial>(new aiMaterial)); |
717 | 0 | } |
718 | 0 | scene->mNumMaterials = static_cast<unsigned int>(_materials.size()); |
719 | 0 | scene->mMaterials = unique_to_array(_materials); |
720 | | |
721 | | // meshes |
722 | 0 | scene->mNumMeshes = static_cast<unsigned int>(_meshes.size()); |
723 | 0 | scene->mMeshes = unique_to_array(_meshes); |
724 | | |
725 | | // animations |
726 | 0 | if (_animations.size() == 1 && _nodeAnims.size()) { |
727 | |
|
728 | 0 | aiAnimation *anim = _animations.back().get(); |
729 | 0 | anim->mNumChannels = static_cast<unsigned int>(_nodeAnims.size()); |
730 | 0 | anim->mChannels = unique_to_array(_nodeAnims); |
731 | |
|
732 | 0 | scene->mNumAnimations = static_cast<unsigned int>(_animations.size()); |
733 | 0 | scene->mAnimations = unique_to_array(_animations); |
734 | 0 | } |
735 | | |
736 | | // convert to RH |
737 | 0 | MakeLeftHandedProcess makeleft; |
738 | 0 | makeleft.Execute(scene); |
739 | |
|
740 | 0 | FlipWindingOrderProcess flip; |
741 | 0 | flip.Execute(scene); |
742 | 0 | } |
743 | | |
744 | | } // namespace Assimp |
745 | | |
746 | | #endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER |