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