vrshoot

annotate libs/assimp/ACLoader.cpp @ 0:b2f14e535253

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