1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2021, 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  AssbinLoader.cpp
43  *  @brief Implementation of the .assbin importer class
44  *
45  *  see assbin_chunks.h
46  */
47 
48 #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
49 
50 // internal headers
51 #include "AssetLib/Assbin/AssbinLoader.h"
52 #include "Common/assbin_chunks.h"
53 #include <assimp/MemoryIOWrapper.h>
54 #include <assimp/anim.h>
55 #include <assimp/importerdesc.h>
56 #include <assimp/mesh.h>
57 #include <assimp/scene.h>
58 #include <memory>
59 
60 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
61 #include <zlib.h>
62 #else
63 #include <contrib/zlib/zlib.h>
64 #endif
65 
66 using namespace Assimp;
67 
68 static const aiImporterDesc desc = {
69     "Assimp Binary Importer",
70     "Gargaj / Conspiracy",
71     "",
72     "",
73     aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
74     0,
75     0,
76     0,
77     0,
78     "assbin"
79 };
80 
81 // -----------------------------------------------------------------------------------
GetInfo() const82 const aiImporterDesc *AssbinImporter::GetInfo() const {
83     return &desc;
84 }
85 
86 // -----------------------------------------------------------------------------------
CanRead(const std::string & pFile,IOSystem * pIOHandler,bool) const87 bool AssbinImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
88     IOStream *in = pIOHandler->Open(pFile);
89     if (nullptr == in) {
90         return false;
91     }
92 
93     char s[32];
94     in->Read(s, sizeof(char), 32);
95 
96     pIOHandler->Close(in);
97 
98     return strncmp(s, "ASSIMP.binary-dump.", 19) == 0;
99 }
100 
101 // -----------------------------------------------------------------------------------
102 template <typename T>
Read(IOStream * stream)103 T Read(IOStream *stream) {
104     T t;
105     size_t res = stream->Read(&t, sizeof(T), 1);
106     if (res != 1) {
107         throw DeadlyImportError("Unexpected EOF");
108     }
109     return t;
110 }
111 
112 // -----------------------------------------------------------------------------------
113 template <>
Read(IOStream * stream)114 aiVector3D Read<aiVector3D>(IOStream *stream) {
115     aiVector3D v;
116     v.x = Read<ai_real>(stream);
117     v.y = Read<ai_real>(stream);
118     v.z = Read<ai_real>(stream);
119     return v;
120 }
121 
122 // -----------------------------------------------------------------------------------
123 template <>
Read(IOStream * stream)124 aiColor4D Read<aiColor4D>(IOStream *stream) {
125     aiColor4D c;
126     c.r = Read<ai_real>(stream);
127     c.g = Read<ai_real>(stream);
128     c.b = Read<ai_real>(stream);
129     c.a = Read<ai_real>(stream);
130     return c;
131 }
132 
133 // -----------------------------------------------------------------------------------
134 template <>
Read(IOStream * stream)135 aiQuaternion Read<aiQuaternion>(IOStream *stream) {
136     aiQuaternion v;
137     v.w = Read<ai_real>(stream);
138     v.x = Read<ai_real>(stream);
139     v.y = Read<ai_real>(stream);
140     v.z = Read<ai_real>(stream);
141     return v;
142 }
143 
144 // -----------------------------------------------------------------------------------
145 template <>
Read(IOStream * stream)146 aiString Read<aiString>(IOStream *stream) {
147     aiString s;
148     stream->Read(&s.length, 4, 1);
149     if (s.length) {
150         stream->Read(s.data, s.length, 1);
151     }
152     s.data[s.length] = 0;
153 
154     return s;
155 }
156 
157 // -----------------------------------------------------------------------------------
158 template <>
Read(IOStream * stream)159 aiVertexWeight Read<aiVertexWeight>(IOStream *stream) {
160     aiVertexWeight w;
161     w.mVertexId = Read<unsigned int>(stream);
162     w.mWeight = Read<ai_real>(stream);
163     return w;
164 }
165 
166 // -----------------------------------------------------------------------------------
167 template <>
Read(IOStream * stream)168 aiMatrix4x4 Read<aiMatrix4x4>(IOStream *stream) {
169     aiMatrix4x4 m;
170     for (unsigned int i = 0; i < 4; ++i) {
171         for (unsigned int i2 = 0; i2 < 4; ++i2) {
172             m[i][i2] = Read<ai_real>(stream);
173         }
174     }
175     return m;
176 }
177 
178 // -----------------------------------------------------------------------------------
179 template <>
Read(IOStream * stream)180 aiVectorKey Read<aiVectorKey>(IOStream *stream) {
181     aiVectorKey v;
182     v.mTime = Read<double>(stream);
183     v.mValue = Read<aiVector3D>(stream);
184     return v;
185 }
186 
187 // -----------------------------------------------------------------------------------
188 template <>
Read(IOStream * stream)189 aiQuatKey Read<aiQuatKey>(IOStream *stream) {
190     aiQuatKey v;
191     v.mTime = Read<double>(stream);
192     v.mValue = Read<aiQuaternion>(stream);
193     return v;
194 }
195 
196 // -----------------------------------------------------------------------------------
197 template <typename T>
ReadArray(IOStream * stream,T * out,unsigned int size)198 void ReadArray(IOStream *stream, T *out, unsigned int size) {
199     ai_assert(nullptr != stream);
200     ai_assert(nullptr != out);
201 
202     for (unsigned int i = 0; i < size; i++) {
203         out[i] = Read<T>(stream);
204     }
205 }
206 
207 // -----------------------------------------------------------------------------------
208 template <typename T>
ReadBounds(IOStream * stream,T *,unsigned int n)209 void ReadBounds(IOStream *stream, T * /*p*/, unsigned int n) {
210     // not sure what to do here, the data isn't really useful.
211     stream->Seek(sizeof(T) * n, aiOrigin_CUR);
212 }
213 
214 // -----------------------------------------------------------------------------------
ReadBinaryNode(IOStream * stream,aiNode ** onode,aiNode * parent)215 void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *parent) {
216     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODE)
217         throw DeadlyImportError("Magic chunk identifiers are wrong!");
218     /*uint32_t size =*/Read<uint32_t>(stream);
219 
220     std::unique_ptr<aiNode> node(new aiNode());
221 
222     node->mName = Read<aiString>(stream);
223     node->mTransformation = Read<aiMatrix4x4>(stream);
224     unsigned numChildren = Read<unsigned int>(stream);
225     unsigned numMeshes = Read<unsigned int>(stream);
226     unsigned int nb_metadata = Read<unsigned int>(stream);
227 
228     if (parent) {
229         node->mParent = parent;
230     }
231 
232     if (numMeshes) {
233         node->mMeshes = new unsigned int[numMeshes];
234         for (unsigned int i = 0; i < numMeshes; ++i) {
235             node->mMeshes[i] = Read<unsigned int>(stream);
236             node->mNumMeshes++;
237         }
238     }
239 
240     if (numChildren) {
241         node->mChildren = new aiNode *[numChildren];
242         for (unsigned int i = 0; i < numChildren; ++i) {
243             ReadBinaryNode(stream, &node->mChildren[i], node.get());
244             node->mNumChildren++;
245         }
246     }
247 
248     if (nb_metadata > 0) {
249         node->mMetaData = aiMetadata::Alloc(nb_metadata);
250         for (unsigned int i = 0; i < nb_metadata; ++i) {
251             node->mMetaData->mKeys[i] = Read<aiString>(stream);
252             node->mMetaData->mValues[i].mType = (aiMetadataType)Read<uint16_t>(stream);
253             void *data = nullptr;
254 
255             switch (node->mMetaData->mValues[i].mType) {
256             case AI_BOOL:
257                 data = new bool(Read<bool>(stream));
258                 break;
259             case AI_INT32:
260                 data = new int32_t(Read<int32_t>(stream));
261                 break;
262             case AI_UINT64:
263                 data = new uint64_t(Read<uint64_t>(stream));
264                 break;
265             case AI_FLOAT:
266                 data = new ai_real(Read<ai_real>(stream));
267                 break;
268             case AI_DOUBLE:
269                 data = new double(Read<double>(stream));
270                 break;
271             case AI_AISTRING:
272                 data = new aiString(Read<aiString>(stream));
273                 break;
274             case AI_AIVECTOR3D:
275                 data = new aiVector3D(Read<aiVector3D>(stream));
276                 break;
277 #ifndef SWIG
278             case FORCE_32BIT:
279 #endif // SWIG
280             default:
281                 break;
282             }
283 
284             node->mMetaData->mValues[i].mData = data;
285         }
286     }
287     *onode = node.release();
288 }
289 
290 // -----------------------------------------------------------------------------------
ReadBinaryBone(IOStream * stream,aiBone * b)291 void AssbinImporter::ReadBinaryBone(IOStream *stream, aiBone *b) {
292     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIBONE)
293         throw DeadlyImportError("Magic chunk identifiers are wrong!");
294     /*uint32_t size =*/Read<uint32_t>(stream);
295 
296     b->mName = Read<aiString>(stream);
297     b->mNumWeights = Read<unsigned int>(stream);
298     b->mOffsetMatrix = Read<aiMatrix4x4>(stream);
299 
300     // for the moment we write dumb min/max values for the bones, too.
301     // maybe I'll add a better, hash-like solution later
302     if (shortened) {
303         ReadBounds(stream, b->mWeights, b->mNumWeights);
304     } else {
305         // else write as usual
306         b->mWeights = new aiVertexWeight[b->mNumWeights];
307         ReadArray<aiVertexWeight>(stream, b->mWeights, b->mNumWeights);
308     }
309 }
310 
311 // -----------------------------------------------------------------------------------
fitsIntoUI16(unsigned int mNumVertices)312 static bool fitsIntoUI16(unsigned int mNumVertices) {
313     return (mNumVertices < (1u << 16));
314 }
315 
316 // -----------------------------------------------------------------------------------
ReadBinaryMesh(IOStream * stream,aiMesh * mesh)317 void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) {
318     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMESH)
319         throw DeadlyImportError("Magic chunk identifiers are wrong!");
320     /*uint32_t size =*/Read<uint32_t>(stream);
321 
322     mesh->mPrimitiveTypes = Read<unsigned int>(stream);
323     mesh->mNumVertices = Read<unsigned int>(stream);
324     mesh->mNumFaces = Read<unsigned int>(stream);
325     mesh->mNumBones = Read<unsigned int>(stream);
326     mesh->mMaterialIndex = Read<unsigned int>(stream);
327 
328     // first of all, write bits for all existent vertex components
329     unsigned int c = Read<unsigned int>(stream);
330 
331     if (c & ASSBIN_MESH_HAS_POSITIONS) {
332         if (shortened) {
333             ReadBounds(stream, mesh->mVertices, mesh->mNumVertices);
334         } else {
335             // else write as usual
336             mesh->mVertices = new aiVector3D[mesh->mNumVertices];
337             ReadArray<aiVector3D>(stream, mesh->mVertices, mesh->mNumVertices);
338         }
339     }
340     if (c & ASSBIN_MESH_HAS_NORMALS) {
341         if (shortened) {
342             ReadBounds(stream, mesh->mNormals, mesh->mNumVertices);
343         } else {
344             // else write as usual
345             mesh->mNormals = new aiVector3D[mesh->mNumVertices];
346             ReadArray<aiVector3D>(stream, mesh->mNormals, mesh->mNumVertices);
347         }
348     }
349     if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) {
350         if (shortened) {
351             ReadBounds(stream, mesh->mTangents, mesh->mNumVertices);
352             ReadBounds(stream, mesh->mBitangents, mesh->mNumVertices);
353         } else {
354             // else write as usual
355             mesh->mTangents = new aiVector3D[mesh->mNumVertices];
356             ReadArray<aiVector3D>(stream, mesh->mTangents, mesh->mNumVertices);
357             mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
358             ReadArray<aiVector3D>(stream, mesh->mBitangents, mesh->mNumVertices);
359         }
360     }
361     for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) {
362         if (!(c & ASSBIN_MESH_HAS_COLOR(n))) {
363             break;
364         }
365 
366         if (shortened) {
367             ReadBounds(stream, mesh->mColors[n], mesh->mNumVertices);
368         } else {
369             // else write as usual
370             mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
371             ReadArray<aiColor4D>(stream, mesh->mColors[n], mesh->mNumVertices);
372         }
373     }
374     for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) {
375         if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) {
376             break;
377         }
378 
379         // write number of UV components
380         mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
381 
382         if (shortened) {
383             ReadBounds(stream, mesh->mTextureCoords[n], mesh->mNumVertices);
384         } else {
385             // else write as usual
386             mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
387             ReadArray<aiVector3D>(stream, mesh->mTextureCoords[n], mesh->mNumVertices);
388         }
389     }
390 
391     // write faces. There are no floating-point calculations involved
392     // in these, so we can write a simple hash over the face data
393     // to the dump file. We generate a single 32 Bit hash for 512 faces
394     // using Assimp's standard hashing function.
395     if (shortened) {
396         Read<unsigned int>(stream);
397     } else {
398         // else write as usual
399         // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
400         mesh->mFaces = new aiFace[mesh->mNumFaces];
401         for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
402             aiFace &f = mesh->mFaces[i];
403 
404             static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
405             f.mNumIndices = Read<uint16_t>(stream);
406             f.mIndices = new unsigned int[f.mNumIndices];
407 
408             for (unsigned int a = 0; a < f.mNumIndices; ++a) {
409                 // Check if unsigned  short ( 16 bit  ) are big enough for the indices
410                 if (fitsIntoUI16(mesh->mNumVertices)) {
411                     f.mIndices[a] = Read<uint16_t>(stream);
412                 } else {
413                     f.mIndices[a] = Read<unsigned int>(stream);
414                 }
415             }
416         }
417     }
418 
419     // write bones
420     if (mesh->mNumBones) {
421         mesh->mBones = new C_STRUCT aiBone *[mesh->mNumBones];
422         for (unsigned int a = 0; a < mesh->mNumBones; ++a) {
423             mesh->mBones[a] = new aiBone();
424             ReadBinaryBone(stream, mesh->mBones[a]);
425         }
426     }
427 }
428 
429 // -----------------------------------------------------------------------------------
ReadBinaryMaterialProperty(IOStream * stream,aiMaterialProperty * prop)430 void AssbinImporter::ReadBinaryMaterialProperty(IOStream *stream, aiMaterialProperty *prop) {
431     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY)
432         throw DeadlyImportError("Magic chunk identifiers are wrong!");
433     /*uint32_t size =*/Read<uint32_t>(stream);
434 
435     prop->mKey = Read<aiString>(stream);
436     prop->mSemantic = Read<unsigned int>(stream);
437     prop->mIndex = Read<unsigned int>(stream);
438 
439     prop->mDataLength = Read<unsigned int>(stream);
440     prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
441     prop->mData = new char[prop->mDataLength];
442     stream->Read(prop->mData, 1, prop->mDataLength);
443 }
444 
445 // -----------------------------------------------------------------------------------
ReadBinaryMaterial(IOStream * stream,aiMaterial * mat)446 void AssbinImporter::ReadBinaryMaterial(IOStream *stream, aiMaterial *mat) {
447     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIAL)
448         throw DeadlyImportError("Magic chunk identifiers are wrong!");
449     /*uint32_t size =*/Read<uint32_t>(stream);
450 
451     mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
452     if (mat->mNumProperties) {
453         if (mat->mProperties) {
454             delete[] mat->mProperties;
455         }
456         mat->mProperties = new aiMaterialProperty *[mat->mNumProperties];
457         for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
458             mat->mProperties[i] = new aiMaterialProperty();
459             ReadBinaryMaterialProperty(stream, mat->mProperties[i]);
460         }
461     }
462 }
463 
464 // -----------------------------------------------------------------------------------
ReadBinaryNodeAnim(IOStream * stream,aiNodeAnim * nd)465 void AssbinImporter::ReadBinaryNodeAnim(IOStream *stream, aiNodeAnim *nd) {
466     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODEANIM)
467         throw DeadlyImportError("Magic chunk identifiers are wrong!");
468     /*uint32_t size =*/Read<uint32_t>(stream);
469 
470     nd->mNodeName = Read<aiString>(stream);
471     nd->mNumPositionKeys = Read<unsigned int>(stream);
472     nd->mNumRotationKeys = Read<unsigned int>(stream);
473     nd->mNumScalingKeys = Read<unsigned int>(stream);
474     nd->mPreState = (aiAnimBehaviour)Read<unsigned int>(stream);
475     nd->mPostState = (aiAnimBehaviour)Read<unsigned int>(stream);
476 
477     if (nd->mNumPositionKeys) {
478         if (shortened) {
479             ReadBounds(stream, nd->mPositionKeys, nd->mNumPositionKeys);
480 
481         } // else write as usual
482         else {
483             nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
484             ReadArray<aiVectorKey>(stream, nd->mPositionKeys, nd->mNumPositionKeys);
485         }
486     }
487     if (nd->mNumRotationKeys) {
488         if (shortened) {
489             ReadBounds(stream, nd->mRotationKeys, nd->mNumRotationKeys);
490 
491         } else {
492             // else write as usual
493             nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
494             ReadArray<aiQuatKey>(stream, nd->mRotationKeys, nd->mNumRotationKeys);
495         }
496     }
497     if (nd->mNumScalingKeys) {
498         if (shortened) {
499             ReadBounds(stream, nd->mScalingKeys, nd->mNumScalingKeys);
500 
501         } else {
502             // else write as usual
503             nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
504             ReadArray<aiVectorKey>(stream, nd->mScalingKeys, nd->mNumScalingKeys);
505         }
506     }
507 }
508 
509 // -----------------------------------------------------------------------------------
ReadBinaryAnim(IOStream * stream,aiAnimation * anim)510 void AssbinImporter::ReadBinaryAnim(IOStream *stream, aiAnimation *anim) {
511     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIANIMATION)
512         throw DeadlyImportError("Magic chunk identifiers are wrong!");
513     /*uint32_t size =*/Read<uint32_t>(stream);
514 
515     anim->mName = Read<aiString>(stream);
516     anim->mDuration = Read<double>(stream);
517     anim->mTicksPerSecond = Read<double>(stream);
518     anim->mNumChannels = Read<unsigned int>(stream);
519 
520     if (anim->mNumChannels) {
521         anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
522         for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
523             anim->mChannels[a] = new aiNodeAnim();
524             ReadBinaryNodeAnim(stream, anim->mChannels[a]);
525         }
526     }
527 }
528 
529 // -----------------------------------------------------------------------------------
ReadBinaryTexture(IOStream * stream,aiTexture * tex)530 void AssbinImporter::ReadBinaryTexture(IOStream *stream, aiTexture *tex) {
531     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AITEXTURE)
532         throw DeadlyImportError("Magic chunk identifiers are wrong!");
533     /*uint32_t size =*/Read<uint32_t>(stream);
534 
535     tex->mWidth = Read<unsigned int>(stream);
536     tex->mHeight = Read<unsigned int>(stream);
537     stream->Read(tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1);
538 
539     if (!shortened) {
540         if (!tex->mHeight) {
541             tex->pcData = new aiTexel[tex->mWidth];
542             stream->Read(tex->pcData, 1, tex->mWidth);
543         } else {
544             tex->pcData = new aiTexel[tex->mWidth * tex->mHeight];
545             stream->Read(tex->pcData, 1, tex->mWidth * tex->mHeight * 4);
546         }
547     }
548 }
549 
550 // -----------------------------------------------------------------------------------
ReadBinaryLight(IOStream * stream,aiLight * l)551 void AssbinImporter::ReadBinaryLight(IOStream *stream, aiLight *l) {
552     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AILIGHT)
553         throw DeadlyImportError("Magic chunk identifiers are wrong!");
554     /*uint32_t size =*/Read<uint32_t>(stream);
555 
556     l->mName = Read<aiString>(stream);
557     l->mType = (aiLightSourceType)Read<unsigned int>(stream);
558 
559     if (l->mType != aiLightSource_DIRECTIONAL) {
560         l->mAttenuationConstant = Read<float>(stream);
561         l->mAttenuationLinear = Read<float>(stream);
562         l->mAttenuationQuadratic = Read<float>(stream);
563     }
564 
565     l->mColorDiffuse = Read<aiColor3D>(stream);
566     l->mColorSpecular = Read<aiColor3D>(stream);
567     l->mColorAmbient = Read<aiColor3D>(stream);
568 
569     if (l->mType == aiLightSource_SPOT) {
570         l->mAngleInnerCone = Read<float>(stream);
571         l->mAngleOuterCone = Read<float>(stream);
572     }
573 }
574 
575 // -----------------------------------------------------------------------------------
ReadBinaryCamera(IOStream * stream,aiCamera * cam)576 void AssbinImporter::ReadBinaryCamera(IOStream *stream, aiCamera *cam) {
577     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AICAMERA)
578         throw DeadlyImportError("Magic chunk identifiers are wrong!");
579     /*uint32_t size =*/Read<uint32_t>(stream);
580 
581     cam->mName = Read<aiString>(stream);
582     cam->mPosition = Read<aiVector3D>(stream);
583     cam->mLookAt = Read<aiVector3D>(stream);
584     cam->mUp = Read<aiVector3D>(stream);
585     cam->mHorizontalFOV = Read<float>(stream);
586     cam->mClipPlaneNear = Read<float>(stream);
587     cam->mClipPlaneFar = Read<float>(stream);
588     cam->mAspect = Read<float>(stream);
589 }
590 
591 // -----------------------------------------------------------------------------------
ReadBinaryScene(IOStream * stream,aiScene * scene)592 void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
593     if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AISCENE)
594         throw DeadlyImportError("Magic chunk identifiers are wrong!");
595     /*uint32_t size =*/Read<uint32_t>(stream);
596 
597     scene->mFlags = Read<unsigned int>(stream);
598     scene->mNumMeshes = Read<unsigned int>(stream);
599     scene->mNumMaterials = Read<unsigned int>(stream);
600     scene->mNumAnimations = Read<unsigned int>(stream);
601     scene->mNumTextures = Read<unsigned int>(stream);
602     scene->mNumLights = Read<unsigned int>(stream);
603     scene->mNumCameras = Read<unsigned int>(stream);
604 
605     // Read node graph
606     //scene->mRootNode = new aiNode[1];
607     ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)nullptr);
608 
609     // Read all meshes
610     if (scene->mNumMeshes) {
611         scene->mMeshes = new aiMesh *[scene->mNumMeshes];
612         memset(scene->mMeshes, 0, scene->mNumMeshes * sizeof(aiMesh *));
613         for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
614             scene->mMeshes[i] = new aiMesh();
615             ReadBinaryMesh(stream, scene->mMeshes[i]);
616         }
617     }
618 
619     // Read materials
620     if (scene->mNumMaterials) {
621         scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
622         memset(scene->mMaterials, 0, scene->mNumMaterials * sizeof(aiMaterial *));
623         for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
624             scene->mMaterials[i] = new aiMaterial();
625             ReadBinaryMaterial(stream, scene->mMaterials[i]);
626         }
627     }
628 
629     // Read all animations
630     if (scene->mNumAnimations) {
631         scene->mAnimations = new aiAnimation *[scene->mNumAnimations];
632         memset(scene->mAnimations, 0, scene->mNumAnimations * sizeof(aiAnimation *));
633         for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
634             scene->mAnimations[i] = new aiAnimation();
635             ReadBinaryAnim(stream, scene->mAnimations[i]);
636         }
637     }
638 
639     // Read all textures
640     if (scene->mNumTextures) {
641         scene->mTextures = new aiTexture *[scene->mNumTextures];
642         memset(scene->mTextures, 0, scene->mNumTextures * sizeof(aiTexture *));
643         for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
644             scene->mTextures[i] = new aiTexture();
645             ReadBinaryTexture(stream, scene->mTextures[i]);
646         }
647     }
648 
649     // Read lights
650     if (scene->mNumLights) {
651         scene->mLights = new aiLight *[scene->mNumLights];
652         memset(scene->mLights, 0, scene->mNumLights * sizeof(aiLight *));
653         for (unsigned int i = 0; i < scene->mNumLights; ++i) {
654             scene->mLights[i] = new aiLight();
655             ReadBinaryLight(stream, scene->mLights[i]);
656         }
657     }
658 
659     // Read cameras
660     if (scene->mNumCameras) {
661         scene->mCameras = new aiCamera *[scene->mNumCameras];
662         memset(scene->mCameras, 0, scene->mNumCameras * sizeof(aiCamera *));
663         for (unsigned int i = 0; i < scene->mNumCameras; ++i) {
664             scene->mCameras[i] = new aiCamera();
665             ReadBinaryCamera(stream, scene->mCameras[i]);
666         }
667     }
668 }
669 
670 // -----------------------------------------------------------------------------------
InternReadFile(const std::string & pFile,aiScene * pScene,IOSystem * pIOHandler)671 void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
672     IOStream *stream = pIOHandler->Open(pFile, "rb");
673     if (nullptr == stream) {
674         throw DeadlyImportError("ASSBIN: Could not open ", pFile);
675     }
676 
677     // signature
678     stream->Seek(44, aiOrigin_CUR);
679 
680     unsigned int versionMajor = Read<unsigned int>(stream);
681     unsigned int versionMinor = Read<unsigned int>(stream);
682     if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) {
683         throw DeadlyImportError("Invalid version, data format not compatible!");
684     }
685 
686     /*unsigned int versionRevision =*/Read<unsigned int>(stream);
687     /*unsigned int compileFlags =*/Read<unsigned int>(stream);
688 
689     shortened = Read<uint16_t>(stream) > 0;
690     compressed = Read<uint16_t>(stream) > 0;
691 
692     if (shortened)
693         throw DeadlyImportError("Shortened binaries are not supported!");
694 
695     stream->Seek(256, aiOrigin_CUR); // original filename
696     stream->Seek(128, aiOrigin_CUR); // options
697     stream->Seek(64, aiOrigin_CUR); // padding
698 
699     if (compressed) {
700         uLongf uncompressedSize = Read<uint32_t>(stream);
701         uLongf compressedSize = static_cast<uLongf>(stream->FileSize() - stream->Tell());
702 
703         unsigned char *compressedData = new unsigned char[compressedSize];
704         size_t len = stream->Read(compressedData, 1, compressedSize);
705         ai_assert(len == compressedSize);
706 
707         unsigned char *uncompressedData = new unsigned char[uncompressedSize];
708 
709         int res = uncompress(uncompressedData, &uncompressedSize, compressedData, (uLong)len);
710         if (res != Z_OK) {
711             delete[] uncompressedData;
712             delete[] compressedData;
713             pIOHandler->Close(stream);
714             throw DeadlyImportError("Zlib decompression failed.");
715         }
716 
717         MemoryIOStream io(uncompressedData, uncompressedSize);
718 
719         ReadBinaryScene(&io, pScene);
720 
721         delete[] uncompressedData;
722         delete[] compressedData;
723     } else {
724         ReadBinaryScene(stream, pScene);
725     }
726 
727     pIOHandler->Close(stream);
728 }
729 
730 #endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER
731