1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41/** @file AssbinExporter.cpp
42 * ASSBIN exporter main code
43 */
44#include "assbin_chunks.h"
45#include <assimp/version.h>
46#include <assimp/IOStream.hpp>
47#include <assimp/IOSystem.hpp>
48#include <assimp/Exporter.hpp>
49#include "ProcessHelper.h"
50#include "Exceptional.h"
51
52#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
53# include <zlib.h>
54#else
55# include "../contrib/zlib/zlib.h"
56#endif
57
58#include <time.h>
59
60
61#ifndef ASSIMP_BUILD_NO_EXPORT
62#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
63
64using namespace Assimp;
65
66namespace Assimp {
67
68template <typename T>
69size_t Write(IOStream * stream, const T& v)
70{
71 return stream->Write( &v, sizeof(T), 1 );
72}
73
74
75// -----------------------------------------------------------------------------------
76// Serialize an aiString
77template <>
78inline size_t Write<aiString>(IOStream * stream, const aiString& s)
79{
80 const size_t s2 = (uint32_t)s.length;
81 stream->Write(&s,4,1);
82 stream->Write(s.data,s2,1);
83 return s2+4;
84}
85
86// -----------------------------------------------------------------------------------
87// Serialize an unsigned int as uint32_t
88template <>
89inline size_t Write<unsigned int>(IOStream * stream, const unsigned int& w)
90{
91 const uint32_t t = (uint32_t)w;
92 if (w > t) {
93 // this shouldn't happen, integers in Assimp data structures never exceed 2^32
94 throw new DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
95 }
96
97 stream->Write(&t,4,1);
98 return 4;
99}
100
101// -----------------------------------------------------------------------------------
102// Serialize an unsigned int as uint16_t
103template <>
104inline size_t Write<uint16_t>(IOStream * stream, const uint16_t& w)
105{
106 static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2");
107 stream->Write(&w,2,1);
108 return 2;
109}
110
111// -----------------------------------------------------------------------------------
112// Serialize a float
113template <>
114inline size_t Write<float>(IOStream * stream, const float& f)
115{
116 static_assert(sizeof(float)==4, "sizeof(float)==4");
117 stream->Write(&f,4,1);
118 return 4;
119}
120
121// -----------------------------------------------------------------------------------
122// Serialize a double
123template <>
124inline size_t Write<double>(IOStream * stream, const double& f)
125{
126 static_assert(sizeof(double)==8, "sizeof(double)==8");
127 stream->Write(&f,8,1);
128 return 8;
129}
130
131// -----------------------------------------------------------------------------------
132// Serialize a vec3
133template <>
134inline size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v)
135{
136 size_t t = Write<float>(stream,v.x);
137 t += Write<float>(stream,v.y);
138 t += Write<float>(stream,v.z);
139 return t;
140}
141
142// -----------------------------------------------------------------------------------
143// Serialize a color value
144template <>
145inline size_t Write<aiColor3D>(IOStream * stream, const aiColor3D& v)
146{
147 size_t t = Write<float>(stream,v.r);
148 t += Write<float>(stream,v.g);
149 t += Write<float>(stream,v.b);
150 return t;
151}
152
153// -----------------------------------------------------------------------------------
154// Serialize a color value
155template <>
156inline size_t Write<aiColor4D>(IOStream * stream, const aiColor4D& v)
157{
158 size_t t = Write<float>(stream,v.r);
159 t += Write<float>(stream,v.g);
160 t += Write<float>(stream,v.b);
161 t += Write<float>(stream,v.a);
162 return t;
163}
164
165// -----------------------------------------------------------------------------------
166// Serialize a quaternion
167template <>
168inline size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v)
169{
170 size_t t = Write<float>(stream,v.w);
171 t += Write<float>(stream,v.x);
172 t += Write<float>(stream,v.y);
173 t += Write<float>(stream,v.z);
174 ai_assert(t == 16);
175 return 16;
176}
177
178
179// -----------------------------------------------------------------------------------
180// Serialize a vertex weight
181template <>
182inline size_t Write<aiVertexWeight>(IOStream * stream, const aiVertexWeight& v)
183{
184 size_t t = Write<unsigned int>(stream,v.mVertexId);
185 return t+Write<float>(stream,v.mWeight);
186}
187
188// -----------------------------------------------------------------------------------
189// Serialize a mat4x4
190template <>
191inline size_t Write<aiMatrix4x4>(IOStream * stream, const aiMatrix4x4& m)
192{
193 for (unsigned int i = 0; i < 4;++i) {
194 for (unsigned int i2 = 0; i2 < 4;++i2) {
195 Write<float>(stream,m[i][i2]);
196 }
197 }
198 return 64;
199}
200
201// -----------------------------------------------------------------------------------
202// Serialize an aiVectorKey
203template <>
204inline size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v)
205{
206 const size_t t = Write<double>(stream,v.mTime);
207 return t + Write<aiVector3D>(stream,v.mValue);
208}
209
210// -----------------------------------------------------------------------------------
211// Serialize an aiQuatKey
212template <>
213inline size_t Write<aiQuatKey>(IOStream * stream, const aiQuatKey& v)
214{
215 const size_t t = Write<double>(stream,v.mTime);
216 return t + Write<aiQuaternion>(stream,v.mValue);
217}
218
219template <typename T>
220inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size)
221{
222 T minc,maxc;
223 ArrayBounds(in,size,minc,maxc);
224
225 const size_t t = Write<T>(stream,minc);
226 return t + Write<T>(stream,maxc);
227}
228
229// We use this to write out non-byte arrays so that we write using the specializations.
230// This way we avoid writing out extra bytes that potentially come from struct alignment.
231template <typename T>
232inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
233{
234 size_t n = 0;
235 for (unsigned int i=0; i<size; i++) n += Write<T>(stream,in[i]);
236 return n;
237}
238
239 // ----------------------------------------------------------------------------------
240 /** @class AssbinChunkWriter
241 * @brief Chunk writer mechanism for the .assbin file structure
242 *
243 * This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
244 * the difference being that this takes another IOStream as a "container" in the
245 * constructor, and when it is destroyed, it appends the magic number, the chunk size,
246 * and the chunk contents to the container stream. This allows relatively easy chunk
247 * chunk construction, even recursively.
248 */
249 class AssbinChunkWriter : public IOStream
250 {
251 private:
252
253 uint8_t* buffer;
254 uint32_t magic;
255 IOStream * container;
256 size_t cur_size, cursor, initial;
257
258 private:
259 // -------------------------------------------------------------------
260 void Grow(size_t need = 0)
261 {
262 size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
263
264 const uint8_t* const old = buffer;
265 buffer = new uint8_t[new_size];
266
267 if (old) {
268 memcpy(buffer,old,cur_size);
269 delete[] old;
270 }
271
272 cur_size = new_size;
273 }
274
275 public:
276
277 AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096)
278 : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
279 {
280 }
281
282 virtual ~AssbinChunkWriter()
283 {
284 if (container) {
285 container->Write( &magic, sizeof(uint32_t), 1 );
286 container->Write( &cursor, sizeof(uint32_t), 1 );
287 container->Write( buffer, 1, cursor );
288 }
289 if (buffer) delete[] buffer;
290 }
291
292 void * GetBufferPointer() { return buffer; }
293
294 // -------------------------------------------------------------------
295 virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; }
296 virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; }
297 virtual size_t Tell() const { return cursor; }
298 virtual void Flush() { }
299
300 virtual size_t FileSize() const
301 {
302 return cursor;
303 }
304
305 // -------------------------------------------------------------------
306 virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount)
307 {
308 pSize *= pCount;
309 if (cursor + pSize > cur_size) {
310 Grow(cursor + pSize);
311 }
312
313 memcpy(buffer+cursor, pvBuffer, pSize);
314 cursor += pSize;
315
316 return pCount;
317 }
318
319 };
320
321 // ----------------------------------------------------------------------------------
322 /** @class AssbinExport
323 * @brief Assbin exporter class
324 *
325 * This class performs the .assbin exporting, and is responsible for the file layout.
326 */
327 class AssbinExport
328 {
329 private:
330 bool shortened;
331 bool compressed;
332
333 protected:
334
335 // -----------------------------------------------------------------------------------
336 void WriteBinaryNode( IOStream * container, const aiNode* node)
337 {
338 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
339
340 unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
341
342 Write<aiString>(&chunk,node->mName);
343 Write<aiMatrix4x4>(&chunk,node->mTransformation);
344 Write<unsigned int>(&chunk,node->mNumChildren);
345 Write<unsigned int>(&chunk,node->mNumMeshes);
346 Write<unsigned int>(&chunk,nb_metadata);
347
348 for (unsigned int i = 0; i < node->mNumMeshes;++i) {
349 Write<unsigned int>(&chunk,node->mMeshes[i]);
350 }
351
352 for (unsigned int i = 0; i < node->mNumChildren;++i) {
353 WriteBinaryNode( &chunk, node->mChildren[i] );
354 }
355
356 for (unsigned int i = 0; i < nb_metadata; ++i) {
357 const aiString& key = node->mMetaData->mKeys[i];
358 aiMetadataType type = node->mMetaData->mValues[i].mType;
359 void* value = node->mMetaData->mValues[i].mData;
360
361 Write<aiString>(&chunk, key);
362 Write<uint16_t>(&chunk, type);
363
364 switch (type) {
365 case AI_BOOL:
366 Write<bool>(&chunk, *((bool*) value));
367 break;
368 case AI_INT32:
369 Write<int32_t>(&chunk, *((int32_t*) value));
370 break;
371 case AI_UINT64:
372 Write<uint64_t>(&chunk, *((uint64_t*) value));
373 break;
374 case AI_FLOAT:
375 Write<float>(&chunk, *((float*) value));
376 break;
377 case AI_DOUBLE:
378 Write<double>(&chunk, *((double*) value));
379 break;
380 case AI_AISTRING:
381 Write<aiString>(&chunk, *((aiString*) value));
382 break;
383 case AI_AIVECTOR3D:
384 Write<aiVector3D>(&chunk, *((aiVector3D*) value));
385 break;
386#ifdef SWIG
387 case FORCE_32BIT:
388#endif // SWIG
389 default:
390 break;
391 }
392 }
393 }
394
395 // -----------------------------------------------------------------------------------
396 void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
397 {
398 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
399
400 Write<unsigned int>(&chunk,tex->mWidth);
401 Write<unsigned int>(&chunk,tex->mHeight);
402 chunk.Write( tex->achFormatHint, sizeof(char), 4 );
403
404 if(!shortened) {
405 if (!tex->mHeight) {
406 chunk.Write(tex->pcData,1,tex->mWidth);
407 }
408 else {
409 chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4);
410 }
411 }
412
413 }
414
415 // -----------------------------------------------------------------------------------
416 void WriteBinaryBone(IOStream * container, const aiBone* b)
417 {
418 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE );
419
420 Write<aiString>(&chunk,b->mName);
421 Write<unsigned int>(&chunk,b->mNumWeights);
422 Write<aiMatrix4x4>(&chunk,b->mOffsetMatrix);
423
424 // for the moment we write dumb min/max values for the bones, too.
425 // maybe I'll add a better, hash-like solution later
426 if (shortened) {
427 WriteBounds(&chunk,b->mWeights,b->mNumWeights);
428 } // else write as usual
429 else WriteArray<aiVertexWeight>(&chunk,b->mWeights,b->mNumWeights);
430 }
431
432 // -----------------------------------------------------------------------------------
433 void WriteBinaryMesh(IOStream * container, const aiMesh* mesh)
434 {
435 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH );
436
437 Write<unsigned int>(&chunk,mesh->mPrimitiveTypes);
438 Write<unsigned int>(&chunk,mesh->mNumVertices);
439 Write<unsigned int>(&chunk,mesh->mNumFaces);
440 Write<unsigned int>(&chunk,mesh->mNumBones);
441 Write<unsigned int>(&chunk,mesh->mMaterialIndex);
442
443 // first of all, write bits for all existent vertex components
444 unsigned int c = 0;
445 if (mesh->mVertices) {
446 c |= ASSBIN_MESH_HAS_POSITIONS;
447 }
448 if (mesh->mNormals) {
449 c |= ASSBIN_MESH_HAS_NORMALS;
450 }
451 if (mesh->mTangents && mesh->mBitangents) {
452 c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
453 }
454 for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
455 if (!mesh->mTextureCoords[n]) {
456 break;
457 }
458 c |= ASSBIN_MESH_HAS_TEXCOORD(n);
459 }
460 for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
461 if (!mesh->mColors[n]) {
462 break;
463 }
464 c |= ASSBIN_MESH_HAS_COLOR(n);
465 }
466 Write<unsigned int>(&chunk,c);
467
468 aiVector3D minVec, maxVec;
469 if (mesh->mVertices) {
470 if (shortened) {
471 WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices);
472 } // else write as usual
473 else WriteArray<aiVector3D>(&chunk,mesh->mVertices,mesh->mNumVertices);
474 }
475 if (mesh->mNormals) {
476 if (shortened) {
477 WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices);
478 } // else write as usual
479 else WriteArray<aiVector3D>(&chunk,mesh->mNormals,mesh->mNumVertices);
480 }
481 if (mesh->mTangents && mesh->mBitangents) {
482 if (shortened) {
483 WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices);
484 WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices);
485 } // else write as usual
486 else {
487 WriteArray<aiVector3D>(&chunk,mesh->mTangents,mesh->mNumVertices);
488 WriteArray<aiVector3D>(&chunk,mesh->mBitangents,mesh->mNumVertices);
489 }
490 }
491 for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
492 if (!mesh->mColors[n])
493 break;
494
495 if (shortened) {
496 WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
497 } // else write as usual
498 else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
499 }
500 for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
501 if (!mesh->mTextureCoords[n])
502 break;
503
504 // write number of UV components
505 Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
506
507 if (shortened) {
508 WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
509 } // else write as usual
510 else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
511 }
512
513 // write faces. There are no floating-point calculations involved
514 // in these, so we can write a simple hash over the face data
515 // to the dump file. We generate a single 32 Bit hash for 512 faces
516 // using Assimp's standard hashing function.
517 if (shortened) {
518 unsigned int processed = 0;
519 for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) {
520
521 uint32_t hash = 0;
522 for (unsigned int a = 0; a < job;++a) {
523
524 const aiFace& f = mesh->mFaces[processed+a];
525 uint32_t tmp = f.mNumIndices;
526 hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
527 for (unsigned int i = 0; i < f.mNumIndices; ++i) {
528 static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff");
529 tmp = static_cast<uint32_t>( f.mIndices[i] );
530 hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
531 }
532 }
533 Write<unsigned int>(&chunk,hash);
534 }
535 }
536 else // else write as usual
537 {
538 // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
539 for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
540 const aiFace& f = mesh->mFaces[i];
541
542 static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
543 Write<uint16_t>(&chunk,f.mNumIndices);
544
545 for (unsigned int a = 0; a < f.mNumIndices;++a) {
546 if (mesh->mNumVertices < (1u<<16)) {
547 Write<uint16_t>(&chunk,f.mIndices[a]);
548 }
549 else Write<unsigned int>(&chunk,f.mIndices[a]);
550 }
551 }
552 }
553
554 // write bones
555 if (mesh->mNumBones) {
556 for (unsigned int a = 0; a < mesh->mNumBones;++a) {
557 const aiBone* b = mesh->mBones[a];
558 WriteBinaryBone(&chunk,b);
559 }
560 }
561 }
562
563 // -----------------------------------------------------------------------------------
564 void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop)
565 {
566 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY );
567
568 Write<aiString>(&chunk,prop->mKey);
569 Write<unsigned int>(&chunk,prop->mSemantic);
570 Write<unsigned int>(&chunk,prop->mIndex);
571
572 Write<unsigned int>(&chunk,prop->mDataLength);
573 Write<unsigned int>(&chunk,(unsigned int)prop->mType);
574 chunk.Write(prop->mData,1,prop->mDataLength);
575 }
576
577 // -----------------------------------------------------------------------------------
578 void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat)
579 {
580 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL);
581
582 Write<unsigned int>(&chunk,mat->mNumProperties);
583 for (unsigned int i = 0; i < mat->mNumProperties;++i) {
584 WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]);
585 }
586 }
587
588 // -----------------------------------------------------------------------------------
589 void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd)
590 {
591 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM );
592
593 Write<aiString>(&chunk,nd->mNodeName);
594 Write<unsigned int>(&chunk,nd->mNumPositionKeys);
595 Write<unsigned int>(&chunk,nd->mNumRotationKeys);
596 Write<unsigned int>(&chunk,nd->mNumScalingKeys);
597 Write<unsigned int>(&chunk,nd->mPreState);
598 Write<unsigned int>(&chunk,nd->mPostState);
599
600 if (nd->mPositionKeys) {
601 if (shortened) {
602 WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
603
604 } // else write as usual
605 else WriteArray<aiVectorKey>(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
606 }
607 if (nd->mRotationKeys) {
608 if (shortened) {
609 WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
610
611 } // else write as usual
612 else WriteArray<aiQuatKey>(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
613 }
614 if (nd->mScalingKeys) {
615 if (shortened) {
616 WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
617
618 } // else write as usual
619 else WriteArray<aiVectorKey>(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
620 }
621 }
622
623
624 // -----------------------------------------------------------------------------------
625 void WriteBinaryAnim( IOStream * container, const aiAnimation* anim )
626 {
627 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION );
628
629 Write<aiString>(&chunk,anim->mName);
630 Write<double>(&chunk,anim->mDuration);
631 Write<double>(&chunk,anim->mTicksPerSecond);
632 Write<unsigned int>(&chunk,anim->mNumChannels);
633
634 for (unsigned int a = 0; a < anim->mNumChannels;++a) {
635 const aiNodeAnim* nd = anim->mChannels[a];
636 WriteBinaryNodeAnim(&chunk,nd);
637 }
638 }
639
640 // -----------------------------------------------------------------------------------
641 void WriteBinaryLight( IOStream * container, const aiLight* l )
642 {
643 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
644
645 Write<aiString>(&chunk,l->mName);
646 Write<unsigned int>(&chunk,l->mType);
647
648 if (l->mType != aiLightSource_DIRECTIONAL) {
649 Write<float>(&chunk,l->mAttenuationConstant);
650 Write<float>(&chunk,l->mAttenuationLinear);
651 Write<float>(&chunk,l->mAttenuationQuadratic);
652 }
653
654 Write<aiColor3D>(&chunk,l->mColorDiffuse);
655 Write<aiColor3D>(&chunk,l->mColorSpecular);
656 Write<aiColor3D>(&chunk,l->mColorAmbient);
657
658 if (l->mType == aiLightSource_SPOT) {
659 Write<float>(&chunk,l->mAngleInnerCone);
660 Write<float>(&chunk,l->mAngleOuterCone);
661 }
662
663 }
664
665 // -----------------------------------------------------------------------------------
666 void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
667 {
668 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
669
670 Write<aiString>(&chunk,cam->mName);
671 Write<aiVector3D>(&chunk,cam->mPosition);
672 Write<aiVector3D>(&chunk,cam->mLookAt);
673 Write<aiVector3D>(&chunk,cam->mUp);
674 Write<float>(&chunk,cam->mHorizontalFOV);
675 Write<float>(&chunk,cam->mClipPlaneNear);
676 Write<float>(&chunk,cam->mClipPlaneFar);
677 Write<float>(&chunk,cam->mAspect);
678 }
679
680 // -----------------------------------------------------------------------------------
681 void WriteBinaryScene( IOStream * container, const aiScene* scene)
682 {
683 AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
684
685 // basic scene information
686 Write<unsigned int>(&chunk,scene->mFlags);
687 Write<unsigned int>(&chunk,scene->mNumMeshes);
688 Write<unsigned int>(&chunk,scene->mNumMaterials);
689 Write<unsigned int>(&chunk,scene->mNumAnimations);
690 Write<unsigned int>(&chunk,scene->mNumTextures);
691 Write<unsigned int>(&chunk,scene->mNumLights);
692 Write<unsigned int>(&chunk,scene->mNumCameras);
693
694 // write node graph
695 WriteBinaryNode( &chunk, scene->mRootNode );
696
697 // write all meshes
698 for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
699 const aiMesh* mesh = scene->mMeshes[i];
700 WriteBinaryMesh( &chunk,mesh);
701 }
702
703 // write materials
704 for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
705 const aiMaterial* mat = scene->mMaterials[i];
706 WriteBinaryMaterial(&chunk,mat);
707 }
708
709 // write all animations
710 for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
711 const aiAnimation* anim = scene->mAnimations[i];
712 WriteBinaryAnim(&chunk,anim);
713 }
714
715
716 // write all textures
717 for (unsigned int i = 0; i < scene->mNumTextures;++i) {
718 const aiTexture* mesh = scene->mTextures[i];
719 WriteBinaryTexture(&chunk,mesh);
720 }
721
722 // write lights
723 for (unsigned int i = 0; i < scene->mNumLights;++i) {
724 const aiLight* l = scene->mLights[i];
725 WriteBinaryLight(&chunk,l);
726 }
727
728 // write cameras
729 for (unsigned int i = 0; i < scene->mNumCameras;++i) {
730 const aiCamera* cam = scene->mCameras[i];
731 WriteBinaryCamera(&chunk,cam);
732 }
733
734 }
735
736 public:
737 AssbinExport()
738 : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
739 {
740 }
741
742 // -----------------------------------------------------------------------------------
743 // Write a binary model dump
744 void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
745 {
746 IOStream * out = pIOSystem->Open( pFile, "wb" );
747 if (!out) return;
748
749 time_t tt = time(NULL);
750 tm* p = gmtime(&tt);
751
752 // header
753 char s[64];
754 memset( s, 0, 64 );
755#if _MSC_VER >= 1400
756 sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p));
757#else
758 ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p));
759#endif
760 out->Write( s, 44, 1 );
761 // == 44 bytes
762
763 Write<unsigned int>( out, ASSBIN_VERSION_MAJOR );
764 Write<unsigned int>( out, ASSBIN_VERSION_MINOR );
765 Write<unsigned int>( out, aiGetVersionRevision() );
766 Write<unsigned int>( out, aiGetCompileFlags() );
767 Write<uint16_t>( out, shortened );
768 Write<uint16_t>( out, compressed );
769 // == 20 bytes
770
771 char buff[256];
772 strncpy(buff,pFile,256);
773 out->Write(buff,sizeof(char),256);
774
775 char cmd[] = "\0";
776 strncpy(buff,cmd,128);
777 out->Write(buff,sizeof(char),128);
778
779 // leave 64 bytes free for future extensions
780 memset(buff,0xcd,64);
781 out->Write(buff,sizeof(char),64);
782 // == 435 bytes
783
784 // ==== total header size: 512 bytes
785 ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH );
786
787 // Up to here the data is uncompressed. For compressed files, the rest
788 // is compressed using standard DEFLATE from zlib.
789 if (compressed)
790 {
791 AssbinChunkWriter uncompressedStream( NULL, 0 );
792 WriteBinaryScene( &uncompressedStream, pScene );
793
794 uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
795 uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.);
796 uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
797
798 compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
799
800 out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
801 out->Write( compressedBuffer, sizeof(char), compressedSize );
802
803 delete[] compressedBuffer;
804 }
805 else
806 {
807 WriteBinaryScene( out, pScene );
808 }
809
810 pIOSystem->Close( out );
811 }
812 };
813
814void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
815{
816 AssbinExport exporter;
817 exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
818}
819} // end of namespace Assimp
820
821#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER
822#endif // ASSIMP_BUILD_NO_EXPORT
823