vrshoot
view libs/assimp/ACLoader.cpp @ 1:e7ca128b8713
looks nice :)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 02 Feb 2014 00:35:22 +0200 |
parents | |
children |
line source
2 /*
3 ---------------------------------------------------------------------------
4 Open Asset Import Library (assimp)
5 ---------------------------------------------------------------------------
7 Copyright (c) 2006-2012, assimp team
9 All rights reserved.
11 Redistribution and use of this software in source and binary forms,
12 with or without modification, are permitted provided that the following
13 conditions are met:
15 * Redistributions of source code must retain the above
16 copyright notice, this list of conditions and the
17 following disclaimer.
19 * Redistributions in binary form must reproduce the above
20 copyright notice, this list of conditions and the
21 following disclaimer in the documentation and/or other
22 materials provided with the distribution.
24 * Neither the name of the assimp team, nor the names of its
25 contributors may be used to endorse or promote products
26 derived from this software without specific prior
27 written permission of the assimp team.
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 ---------------------------------------------------------------------------
41 */
43 /** @file Implementation of the AC3D importer class */
45 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_AC_IMPORTER
49 // internal headers
50 #include "ACLoader.h"
51 #include "ParsingUtils.h"
52 #include "fast_atof.h"
53 #include "Subdivision.h"
55 using namespace Assimp;
57 static const aiImporterDesc desc = {
58 "AC3D Importer",
59 "",
60 "",
61 "",
62 aiImporterFlags_SupportTextFlavour,
63 0,
64 0,
65 0,
66 0,
67 "ac acc ac3d"
68 };
70 // ------------------------------------------------------------------------------------------------
71 // skip to the next token
72 #define AI_AC_SKIP_TO_NEXT_TOKEN() \
73 if (!SkipSpaces(&buffer)) \
74 { \
75 DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \
76 continue; \
77 }
79 // ------------------------------------------------------------------------------------------------
80 // read a string (may be enclosed in double quotation marks). buffer must point to "
81 #define AI_AC_GET_STRING(out) \
82 ++buffer; \
83 const char* sz = buffer; \
84 while ('\"' != *buffer) \
85 { \
86 if (IsLineEnd( *buffer )) \
87 { \
88 DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \
89 out = "ERROR"; \
90 break; \
91 } \
92 ++buffer; \
93 } \
94 if (IsLineEnd( *buffer ))continue; \
95 out = std::string(sz,(unsigned int)(buffer-sz)); \
96 ++buffer;
99 // ------------------------------------------------------------------------------------------------
100 // read 1 to n floats prefixed with an optional predefined identifier
101 #define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \
102 AI_AC_SKIP_TO_NEXT_TOKEN(); \
103 if (name_length) \
104 { \
105 if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
106 { \
107 DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \
108 continue; \
109 } \
110 buffer += name_length+1; \
111 } \
112 for (unsigned int i = 0; i < num;++i) \
113 { \
114 AI_AC_SKIP_TO_NEXT_TOKEN(); \
115 buffer = fast_atoreal_move<float>(buffer,((float*)out)[i]); \
116 }
119 // ------------------------------------------------------------------------------------------------
120 // Constructor to be privately used by Importer
121 AC3DImporter::AC3DImporter()
122 {
123 // nothing to be done here
124 }
126 // ------------------------------------------------------------------------------------------------
127 // Destructor, private as well
128 AC3DImporter::~AC3DImporter()
129 {
130 // nothing to be done here
131 }
133 // ------------------------------------------------------------------------------------------------
134 // Returns whether the class can handle the format of the given file.
135 bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
136 {
137 std::string extension = GetExtension(pFile);
139 // fixme: are acc and ac3d *really* used? Some sources say they are
140 if(extension == "ac" || extension == "ac3d" || extension == "acc") {
141 return true;
142 }
143 if (!extension.length() || checkSig) {
144 uint32_t token = AI_MAKE_MAGIC("AC3D");
145 return CheckMagicToken(pIOHandler,pFile,&token,1,0);
146 }
147 return false;
148 }
150 // ------------------------------------------------------------------------------------------------
151 // Loader meta information
152 const aiImporterDesc* AC3DImporter::GetInfo () const
153 {
154 return &desc;
155 }
157 // ------------------------------------------------------------------------------------------------
158 // Get a pointer to the next line from the file
159 bool AC3DImporter::GetNextLine( )
160 {
161 SkipLine(&buffer);
162 return SkipSpaces(&buffer);
163 }
165 // ------------------------------------------------------------------------------------------------
166 // Parse an object section in an AC file
167 void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
168 {
169 if (!TokenMatch(buffer,"OBJECT",6))
170 return;
172 SkipSpaces(&buffer);
174 ++mNumMeshes;
176 objects.push_back(Object());
177 Object& obj = objects.back();
179 aiLight* light = NULL;
180 if (!ASSIMP_strincmp(buffer,"light",5))
181 {
182 // This is a light source. Add it to the list
183 mLights->push_back(light = new aiLight());
185 // Return a point light with no attenuation
186 light->mType = aiLightSource_POINT;
187 light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f);
188 light->mAttenuationConstant = 1.f;
190 // Generate a default name for both the light source and the node
191 // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
192 light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",static_cast<unsigned int>(mLights->size())-1);
193 obj.name = std::string( light->mName.data );
195 DefaultLogger::get()->debug("AC3D: Light source encountered");
196 obj.type = Object::Light;
197 }
198 else if (!ASSIMP_strincmp(buffer,"group",5))
199 {
200 obj.type = Object::Group;
201 }
202 else if (!ASSIMP_strincmp(buffer,"world",5))
203 {
204 obj.type = Object::World;
205 }
206 else obj.type = Object::Poly;
207 while (GetNextLine())
208 {
209 if (TokenMatch(buffer,"kids",4))
210 {
211 SkipSpaces(&buffer);
212 unsigned int num = strtoul10(buffer,&buffer);
213 GetNextLine();
214 if (num)
215 {
216 // load the children of this object recursively
217 obj.children.reserve(num);
218 for (unsigned int i = 0; i < num; ++i)
219 LoadObjectSection(obj.children);
220 }
221 return;
222 }
223 else if (TokenMatch(buffer,"name",4))
224 {
225 SkipSpaces(&buffer);
226 AI_AC_GET_STRING(obj.name);
228 // If this is a light source, we'll also need to store
229 // the name of the node in it.
230 if (light)
231 {
232 light->mName.Set(obj.name);
233 }
234 }
235 else if (TokenMatch(buffer,"texture",7))
236 {
237 SkipSpaces(&buffer);
238 AI_AC_GET_STRING(obj.texture);
239 }
240 else if (TokenMatch(buffer,"texrep",6))
241 {
242 SkipSpaces(&buffer);
243 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat);
244 if (!obj.texRepeat.x || !obj.texRepeat.y)
245 obj.texRepeat = aiVector2D (1.f,1.f);
246 }
247 else if (TokenMatch(buffer,"texoff",6))
248 {
249 SkipSpaces(&buffer);
250 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset);
251 }
252 else if (TokenMatch(buffer,"rot",3))
253 {
254 SkipSpaces(&buffer);
255 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation);
256 }
257 else if (TokenMatch(buffer,"loc",3))
258 {
259 SkipSpaces(&buffer);
260 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation);
261 }
262 else if (TokenMatch(buffer,"subdiv",6))
263 {
264 SkipSpaces(&buffer);
265 obj.subDiv = strtoul10(buffer,&buffer);
266 }
267 else if (TokenMatch(buffer,"crease",6))
268 {
269 SkipSpaces(&buffer);
270 obj.crease = fast_atof(buffer);
271 }
272 else if (TokenMatch(buffer,"numvert",7))
273 {
274 SkipSpaces(&buffer);
276 unsigned int t = strtoul10(buffer,&buffer);
277 obj.vertices.reserve(t);
278 for (unsigned int i = 0; i < t;++i)
279 {
280 if (!GetNextLine())
281 {
282 DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet");
283 break;
284 }
285 else if (!IsNumeric(*buffer))
286 {
287 DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet");
288 --buffer; // make sure the line is processed a second time
289 break;
290 }
291 obj.vertices.push_back(aiVector3D());
292 aiVector3D& v = obj.vertices.back();
293 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
294 }
295 }
296 else if (TokenMatch(buffer,"numsurf",7))
297 {
298 SkipSpaces(&buffer);
300 bool Q3DWorkAround = false;
302 const unsigned int t = strtoul10(buffer,&buffer);
303 obj.surfaces.reserve(t);
304 for (unsigned int i = 0; i < t;++i)
305 {
306 GetNextLine();
307 if (!TokenMatch(buffer,"SURF",4))
308 {
309 // FIX: this can occur for some files - Quick 3D for
310 // example writes no surf chunks
311 if (!Q3DWorkAround)
312 {
313 DefaultLogger::get()->warn("AC3D: SURF token was expected");
314 DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled");
315 }
316 --buffer; // make sure the line is processed a second time
317 // break; --- see fix notes above
319 Q3DWorkAround = true;
320 }
321 SkipSpaces(&buffer);
322 obj.surfaces.push_back(Surface());
323 Surface& surf = obj.surfaces.back();
324 surf.flags = strtoul_cppstyle(buffer);
326 while (1)
327 {
328 if(!GetNextLine())
329 {
330 DefaultLogger::get()->error("AC3D: Unexpected EOF: surface is incomplete");
331 break;
332 }
333 if (TokenMatch(buffer,"mat",3))
334 {
335 SkipSpaces(&buffer);
336 surf.mat = strtoul10(buffer);
337 }
338 else if (TokenMatch(buffer,"refs",4))
339 {
340 // --- see fix notes above
341 if (Q3DWorkAround)
342 {
343 if (!surf.entries.empty())
344 {
345 buffer -= 6;
346 break;
347 }
348 }
350 SkipSpaces(&buffer);
351 const unsigned int m = strtoul10(buffer);
352 surf.entries.reserve(m);
354 obj.numRefs += m;
356 for (unsigned int k = 0; k < m; ++k)
357 {
358 if(!GetNextLine())
359 {
360 DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete");
361 break;
362 }
363 surf.entries.push_back(Surface::SurfaceEntry());
364 Surface::SurfaceEntry& entry = surf.entries.back();
366 entry.first = strtoul10(buffer,&buffer);
367 SkipSpaces(&buffer);
368 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second);
369 }
370 }
371 else
372 {
374 --buffer; // make sure the line is processed a second time
375 break;
376 }
377 }
378 }
379 }
380 }
381 DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected");
382 }
384 // ------------------------------------------------------------------------------------------------
385 // Convert a material from AC3DImporter::Material to aiMaterial
386 void AC3DImporter::ConvertMaterial(const Object& object,
387 const Material& matSrc,
388 aiMaterial& matDest)
389 {
390 aiString s;
392 if (matSrc.name.length())
393 {
394 s.Set(matSrc.name);
395 matDest.AddProperty(&s,AI_MATKEY_NAME);
396 }
397 if (object.texture.length())
398 {
399 s.Set(object.texture);
400 matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
402 // UV transformation
403 if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
404 object.texOffset.x || object.texOffset.y)
405 {
406 aiUVTransform transform;
407 transform.mScaling = object.texRepeat;
408 transform.mTranslation = object.texOffset;
409 matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
410 }
411 }
413 matDest.AddProperty<aiColor3D>(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE);
414 matDest.AddProperty<aiColor3D>(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT);
415 matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE);
416 matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR);
418 int n;
419 if (matSrc.shin)
420 {
421 n = aiShadingMode_Phong;
422 matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS);
423 }
424 else n = aiShadingMode_Gouraud;
425 matDest.AddProperty<int>(&n,1,AI_MATKEY_SHADING_MODEL);
427 float f = 1.f - matSrc.trans;
428 matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
429 }
431 // ------------------------------------------------------------------------------------------------
432 // Converts the loaded data to the internal verbose representation
433 aiNode* AC3DImporter::ConvertObjectSection(Object& object,
434 std::vector<aiMesh*>& meshes,
435 std::vector<aiMaterial*>& outMaterials,
436 const std::vector<Material>& materials,
437 aiNode* parent)
438 {
439 aiNode* node = new aiNode();
440 node->mParent = parent;
441 if (object.vertices.size())
442 {
443 if (!object.surfaces.size() || !object.numRefs)
444 {
445 /* " An object with 7 vertices (no surfaces, no materials defined).
446 This is a good way of getting point data into AC3D.
447 The Vertex->create convex-surface/object can be used on these
448 vertices to 'wrap' a 3d shape around them "
449 (http://www.opencity.info/html/ac3dfileformat.html)
451 therefore: if no surfaces are defined return point data only
452 */
454 DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, "
455 "a point list is returned");
457 meshes.push_back(new aiMesh());
458 aiMesh* mesh = meshes.back();
460 mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size();
461 aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
462 aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
464 for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts)
465 {
466 *verts = object.vertices[i];
467 faces->mNumIndices = 1;
468 faces->mIndices = new unsigned int[1];
469 faces->mIndices[0] = i;
470 }
472 // use the primary material in this case. this should be the
473 // default material if all objects of the file contain points
474 // and no faces.
475 mesh->mMaterialIndex = 0;
476 outMaterials.push_back(new aiMaterial());
477 ConvertMaterial(object, materials[0], *outMaterials.back());
478 }
479 else
480 {
481 // need to generate one or more meshes for this object.
482 // find out how many different materials we have
483 typedef std::pair< unsigned int, unsigned int > IntPair;
484 typedef std::vector< IntPair > MatTable;
485 MatTable needMat(materials.size(),IntPair(0,0));
487 std::vector<Surface>::iterator it,end = object.surfaces.end();
488 std::vector<Surface::SurfaceEntry>::iterator it2,end2;
490 for (it = object.surfaces.begin(); it != end; ++it)
491 {
492 register unsigned int idx = (*it).mat;
493 if (idx >= needMat.size())
494 {
495 DefaultLogger::get()->error("AC3D: material index is out of range");
496 idx = 0;
497 }
498 if ((*it).entries.empty())
499 {
500 DefaultLogger::get()->warn("AC3D: surface her zero vertex references");
501 }
503 // validate all vertex indices to make sure we won't crash here
504 for (it2 = (*it).entries.begin(),
505 end2 = (*it).entries.end(); it2 != end2; ++it2)
506 {
507 if ((*it2).first >= object.vertices.size())
508 {
509 DefaultLogger::get()->warn("AC3D: Invalid vertex reference");
510 (*it2).first = 0;
511 }
512 }
514 if (!needMat[idx].first)++node->mNumMeshes;
516 switch ((*it).flags & 0xf)
517 {
518 // closed line
519 case 0x1:
521 needMat[idx].first += (unsigned int)(*it).entries.size();
522 needMat[idx].second += (unsigned int)(*it).entries.size()<<1u;
523 break;
525 // unclosed line
526 case 0x2:
528 needMat[idx].first += (unsigned int)(*it).entries.size()-1;
529 needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u;
530 break;
532 // 0 == polygon, else unknown
533 default:
535 if ((*it).flags & 0xf)
536 {
537 DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown");
538 (*it).flags &= ~(0xf);
539 }
541 // the number of faces increments by one, the number
542 // of vertices by surface.numref.
543 needMat[idx].first++;
544 needMat[idx].second += (unsigned int)(*it).entries.size();
545 };
546 }
547 unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes];
548 unsigned int mat = 0;
549 const size_t oldm = meshes.size();
550 for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
551 cit != cend; ++cit, ++mat)
552 {
553 if (!(*cit).first)continue;
555 // allocate a new aiMesh object
556 *pip++ = (unsigned int)meshes.size();
557 aiMesh* mesh = new aiMesh();
558 meshes.push_back(mesh);
560 mesh->mMaterialIndex = (unsigned int)outMaterials.size();
561 outMaterials.push_back(new aiMaterial());
562 ConvertMaterial(object, materials[mat], *outMaterials.back());
564 // allocate storage for vertices and normals
565 mesh->mNumFaces = (*cit).first;
566 aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
568 mesh->mNumVertices = (*cit).second;
569 aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
570 unsigned int cur = 0;
572 // allocate UV coordinates, but only if the texture name for the
573 // surface is not empty
574 aiVector3D* uv = NULL;
575 if(object.texture.length())
576 {
577 uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
578 mesh->mNumUVComponents[0] = 2;
579 }
581 for (it = object.surfaces.begin(); it != end; ++it)
582 {
583 if (mat == (*it).mat)
584 {
585 const Surface& src = *it;
587 // closed polygon
588 unsigned int type = (*it).flags & 0xf;
589 if (!type)
590 {
591 aiFace& face = *faces++;
592 if((face.mNumIndices = (unsigned int)src.entries.size()))
593 {
594 face.mIndices = new unsigned int[face.mNumIndices];
595 for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices)
596 {
597 const Surface::SurfaceEntry& entry = src.entries[i];
598 face.mIndices[i] = cur++;
600 // copy vertex positions
601 *vertices = object.vertices[entry.first] + object.translation;
604 // copy texture coordinates
605 if (uv)
606 {
607 uv->x = entry.second.x;
608 uv->y = entry.second.y;
609 ++uv;
610 }
611 }
612 }
613 }
614 else
615 {
617 it2 = (*it).entries.begin();
619 // either a closed or an unclosed line
620 register unsigned int tmp = (unsigned int)(*it).entries.size();
621 if (0x2 == type)--tmp;
622 for (unsigned int m = 0; m < tmp;++m)
623 {
624 aiFace& face = *faces++;
626 face.mNumIndices = 2;
627 face.mIndices = new unsigned int[2];
628 face.mIndices[0] = cur++;
629 face.mIndices[1] = cur++;
631 // copy vertex positions
632 *vertices++ = object.vertices[(*it2).first];
634 // copy texture coordinates
635 if (uv)
636 {
637 uv->x = (*it2).second.x;
638 uv->y = (*it2).second.y;
639 ++uv;
640 }
643 if (0x1 == type && tmp-1 == m)
644 {
645 // if this is a closed line repeat its beginning now
646 it2 = (*it).entries.begin();
647 }
648 else ++it2;
650 // second point
651 *vertices++ = object.vertices[(*it2).first];
653 if (uv)
654 {
655 uv->x = (*it2).second.x;
656 uv->y = (*it2).second.y;
657 ++uv;
658 }
659 }
660 }
661 }
662 }
663 }
665 // Now apply catmull clark subdivision if necessary. We split meshes into
666 // materials which is not done by AC3D during smoothing, so we need to
667 // collect all meshes using the same material group.
668 if (object.subDiv) {
669 if (configEvalSubdivision) {
670 boost::scoped_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
671 DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name);
673 std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
674 div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
675 std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm);
677 // previous meshes are deleted vy Subdivide().
678 }
679 else {
680 DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: "
681 +object.name);
682 }
683 }
684 }
685 }
687 if (object.name.length())
688 node->mName.Set(object.name);
689 else
690 {
691 // generate a name depending on the type of the node
692 switch (object.type)
693 {
694 case Object::Group:
695 node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++);
696 break;
697 case Object::Poly:
698 node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++);
699 break;
700 case Object::Light:
701 node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++);
702 break;
704 // there shouldn't be more than one world, but we don't care
705 case Object::World:
706 node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++);
707 break;
708 }
709 }
712 // setup the local transformation matrix of the object
713 // compute the transformation offset to the parent node
714 node->mTransformation = aiMatrix4x4 ( object.rotation );
716 if (object.type == Object::Group || !object.numRefs)
717 {
718 node->mTransformation.a4 = object.translation.x;
719 node->mTransformation.b4 = object.translation.y;
720 node->mTransformation.c4 = object.translation.z;
721 }
723 // add children to the object
724 if (object.children.size())
725 {
726 node->mNumChildren = (unsigned int)object.children.size();
727 node->mChildren = new aiNode*[node->mNumChildren];
728 for (unsigned int i = 0; i < node->mNumChildren;++i)
729 {
730 node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node);
731 }
732 }
734 return node;
735 }
737 // ------------------------------------------------------------------------------------------------
738 void AC3DImporter::SetupProperties(const Importer* pImp)
739 {
740 configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false;
741 configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false;
742 }
744 // ------------------------------------------------------------------------------------------------
745 // Imports the given file into the given scene structure.
746 void AC3DImporter::InternReadFile( const std::string& pFile,
747 aiScene* pScene, IOSystem* pIOHandler)
748 {
749 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
751 // Check whether we can read from the file
752 if( file.get() == NULL)
753 throw DeadlyImportError( "Failed to open AC3D file " + pFile + ".");
755 // allocate storage and copy the contents of the file to a memory buffer
756 std::vector<char> mBuffer2;
757 TextFileToBuffer(file.get(),mBuffer2);
759 buffer = &mBuffer2[0];
760 mNumMeshes = 0;
762 lights = polys = worlds = groups = 0;
764 if (::strncmp(buffer,"AC3D",4)) {
765 throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
766 }
768 // print the file format version to the console
769 unsigned int version = HexDigitToDecimal( buffer[4] );
770 char msg[3];
771 ASSIMP_itoa10(msg,3,version);
772 DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg);
774 std::vector<Material> materials;
775 materials.reserve(5);
777 std::vector<Object> rootObjects;
778 rootObjects.reserve(5);
780 std::vector<aiLight*> lights;
781 mLights = & lights;
783 while (GetNextLine())
784 {
785 if (TokenMatch(buffer,"MATERIAL",8))
786 {
787 materials.push_back(Material());
788 Material& mat = materials.back();
790 // manually parse the material ... sscanf would use the buldin atof ...
791 // Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
793 AI_AC_SKIP_TO_NEXT_TOKEN();
794 if ('\"' == *buffer)
795 {
796 AI_AC_GET_STRING(mat.name);
797 AI_AC_SKIP_TO_NEXT_TOKEN();
798 }
800 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
801 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb);
802 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis);
803 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec);
804 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin);
805 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
806 }
807 LoadObjectSection(rootObjects);
808 }
810 if (rootObjects.empty() || !mNumMeshes)
811 {
812 throw DeadlyImportError("AC3D: No meshes have been loaded");
813 }
814 if (materials.empty())
815 {
816 DefaultLogger::get()->warn("AC3D: No material has been found");
817 materials.push_back(Material());
818 }
820 mNumMeshes += (mNumMeshes>>2u) + 1;
821 std::vector<aiMesh*> meshes;
822 meshes.reserve(mNumMeshes);
824 std::vector<aiMaterial*> omaterials;
825 materials.reserve(mNumMeshes);
827 // generate a dummy root if there are multiple objects on the top layer
828 Object* root;
829 if (1 == rootObjects.size())
830 root = &rootObjects[0];
831 else
832 {
833 root = new Object();
834 }
836 // now convert the imported stuff to our output data structure
837 pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials);
838 if (1 != rootObjects.size())delete root;
840 if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
841 pScene->mRootNode->mName.Set("<AC3DWorld>");
843 // copy meshes
844 if (meshes.empty())
845 {
846 throw DeadlyImportError("An unknown error occured during converting");
847 }
848 pScene->mNumMeshes = (unsigned int)meshes.size();
849 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
850 ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
852 // copy materials
853 pScene->mNumMaterials = (unsigned int)omaterials.size();
854 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
855 ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
857 // copy lights
858 pScene->mNumLights = (unsigned int)lights.size();
859 if (lights.size())
860 {
861 pScene->mLights = new aiLight*[lights.size()];
862 ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*));
863 }
864 }
866 #endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER