vrshoot

annotate libs/assimp/LWOLoader.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 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file LWOLoader.cpp
nuclear@0 43 * @brief Implementation of the LWO importer class
nuclear@0 44 */
nuclear@0 45
nuclear@0 46 #include "AssimpPCH.h"
nuclear@0 47 #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
nuclear@0 48
nuclear@0 49 // internal headers
nuclear@0 50 #include "LWOLoader.h"
nuclear@0 51 #include "StringComparison.h"
nuclear@0 52 #include "SGSpatialSort.h"
nuclear@0 53 #include "ByteSwap.h"
nuclear@0 54 #include "ProcessHelper.h"
nuclear@0 55 #include "ConvertToLHProcess.h"
nuclear@0 56
nuclear@0 57 using namespace Assimp;
nuclear@0 58
nuclear@0 59 static const aiImporterDesc desc = {
nuclear@0 60 "LightWave/Modo Object Importer",
nuclear@0 61 "",
nuclear@0 62 "",
nuclear@0 63 "http://www.newtek.com/lightwave.html\nhttp://www.luxology.com/modo/",
nuclear@0 64 aiImporterFlags_SupportTextFlavour,
nuclear@0 65 0,
nuclear@0 66 0,
nuclear@0 67 0,
nuclear@0 68 0,
nuclear@0 69 "lwo lxo"
nuclear@0 70 };
nuclear@0 71
nuclear@0 72 // ------------------------------------------------------------------------------------------------
nuclear@0 73 // Constructor to be privately used by Importer
nuclear@0 74 LWOImporter::LWOImporter()
nuclear@0 75 {}
nuclear@0 76
nuclear@0 77 // ------------------------------------------------------------------------------------------------
nuclear@0 78 // Destructor, private as well
nuclear@0 79 LWOImporter::~LWOImporter()
nuclear@0 80 {}
nuclear@0 81
nuclear@0 82 // ------------------------------------------------------------------------------------------------
nuclear@0 83 // Returns whether the class can handle the format of the given file.
nuclear@0 84 bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
nuclear@0 85 {
nuclear@0 86 const std::string extension = GetExtension(pFile);
nuclear@0 87 if (extension == "lwo" || extension == "lxo") {
nuclear@0 88 return true;
nuclear@0 89 }
nuclear@0 90
nuclear@0 91 // if check for extension is not enough, check for the magic tokens
nuclear@0 92 if (!extension.length() || checkSig) {
nuclear@0 93 uint32_t tokens[3];
nuclear@0 94 tokens[0] = AI_LWO_FOURCC_LWOB;
nuclear@0 95 tokens[1] = AI_LWO_FOURCC_LWO2;
nuclear@0 96 tokens[2] = AI_LWO_FOURCC_LXOB;
nuclear@0 97 return CheckMagicToken(pIOHandler,pFile,tokens,3,8);
nuclear@0 98 }
nuclear@0 99 return false;
nuclear@0 100 }
nuclear@0 101
nuclear@0 102 // ------------------------------------------------------------------------------------------------
nuclear@0 103 // Setup configuration properties
nuclear@0 104 void LWOImporter::SetupProperties(const Importer* pImp)
nuclear@0 105 {
nuclear@0 106 configSpeedFlag = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0) ? true : false);
nuclear@0 107 configLayerIndex = pImp->GetPropertyInteger (AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,UINT_MAX);
nuclear@0 108 configLayerName = pImp->GetPropertyString (AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,"");
nuclear@0 109 }
nuclear@0 110
nuclear@0 111 // ------------------------------------------------------------------------------------------------
nuclear@0 112 // Get list of file extensions
nuclear@0 113 const aiImporterDesc* LWOImporter::GetInfo () const
nuclear@0 114 {
nuclear@0 115 return &desc;
nuclear@0 116 }
nuclear@0 117
nuclear@0 118 // ------------------------------------------------------------------------------------------------
nuclear@0 119 // Imports the given file into the given scene structure.
nuclear@0 120 void LWOImporter::InternReadFile( const std::string& pFile,
nuclear@0 121 aiScene* pScene,
nuclear@0 122 IOSystem* pIOHandler)
nuclear@0 123 {
nuclear@0 124 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
nuclear@0 125
nuclear@0 126 // Check whether we can read from the file
nuclear@0 127 if( file.get() == NULL)
nuclear@0 128 throw DeadlyImportError( "Failed to open LWO file " + pFile + ".");
nuclear@0 129
nuclear@0 130 if((this->fileSize = (unsigned int)file->FileSize()) < 12)
nuclear@0 131 throw DeadlyImportError("LWO: The file is too small to contain the IFF header");
nuclear@0 132
nuclear@0 133 // Allocate storage and copy the contents of the file to a memory buffer
nuclear@0 134 std::vector< uint8_t > mBuffer(fileSize);
nuclear@0 135 file->Read( &mBuffer[0], 1, fileSize);
nuclear@0 136 this->pScene = pScene;
nuclear@0 137
nuclear@0 138 // Determine the type of the file
nuclear@0 139 uint32_t fileType;
nuclear@0 140 const char* sz = IFF::ReadHeader(&mBuffer[0],fileType);
nuclear@0 141 if (sz)throw DeadlyImportError(sz);
nuclear@0 142
nuclear@0 143 mFileBuffer = &mBuffer[0] + 12;
nuclear@0 144 fileSize -= 12;
nuclear@0 145
nuclear@0 146 // Initialize some members with their default values
nuclear@0 147 hasNamedLayer = false;
nuclear@0 148
nuclear@0 149 // Create temporary storage on the stack but store pointers to it in the class
nuclear@0 150 // instance. Therefore everything will be destructed properly if an exception
nuclear@0 151 // is thrown and we needn't take care of that.
nuclear@0 152 LayerList _mLayers;
nuclear@0 153 SurfaceList _mSurfaces;
nuclear@0 154 TagList _mTags;
nuclear@0 155 TagMappingTable _mMapping;
nuclear@0 156
nuclear@0 157 mLayers = &_mLayers;
nuclear@0 158 mTags = &_mTags;
nuclear@0 159 mMapping = &_mMapping;
nuclear@0 160 mSurfaces = &_mSurfaces;
nuclear@0 161
nuclear@0 162 // Allocate a default layer (layer indices are 1-based from now)
nuclear@0 163 mLayers->push_back(Layer());
nuclear@0 164 mCurLayer = &mLayers->back();
nuclear@0 165 mCurLayer->mName = "<LWODefault>";
nuclear@0 166 mCurLayer->mIndex = -1;
nuclear@0 167
nuclear@0 168 // old lightwave file format (prior to v6)
nuclear@0 169 if (AI_LWO_FOURCC_LWOB == fileType) {
nuclear@0 170 DefaultLogger::get()->info("LWO file format: LWOB (<= LightWave 5.5)");
nuclear@0 171
nuclear@0 172 mIsLWO2 = false;
nuclear@0 173 mIsLXOB = false;
nuclear@0 174 LoadLWOBFile();
nuclear@0 175 }
nuclear@0 176 // New lightwave format
nuclear@0 177 else if (AI_LWO_FOURCC_LWO2 == fileType) {
nuclear@0 178 mIsLXOB = false;
nuclear@0 179 DefaultLogger::get()->info("LWO file format: LWO2 (>= LightWave 6)");
nuclear@0 180 }
nuclear@0 181 // MODO file format
nuclear@0 182 else if (AI_LWO_FOURCC_LXOB == fileType) {
nuclear@0 183 mIsLXOB = true;
nuclear@0 184 DefaultLogger::get()->info("LWO file format: LXOB (Modo)");
nuclear@0 185 }
nuclear@0 186 // we don't know this format
nuclear@0 187 else
nuclear@0 188 {
nuclear@0 189 char szBuff[5];
nuclear@0 190 szBuff[0] = (char)(fileType >> 24u);
nuclear@0 191 szBuff[1] = (char)(fileType >> 16u);
nuclear@0 192 szBuff[2] = (char)(fileType >> 8u);
nuclear@0 193 szBuff[3] = (char)(fileType);
nuclear@0 194 szBuff[4] = '\0';
nuclear@0 195 throw DeadlyImportError(std::string("Unknown LWO sub format: ") + szBuff);
nuclear@0 196 }
nuclear@0 197
nuclear@0 198 if (AI_LWO_FOURCC_LWOB != fileType) {
nuclear@0 199 mIsLWO2 = true;
nuclear@0 200 LoadLWO2File();
nuclear@0 201
nuclear@0 202 // The newer lightwave format allows the user to configure the
nuclear@0 203 // loader that just one layer is used. If this is the case
nuclear@0 204 // we need to check now whether the requested layer has been found.
nuclear@0 205 if (UINT_MAX != configLayerIndex) {
nuclear@0 206 unsigned int layerCount = 0;
nuclear@0 207 for(std::list<LWO::Layer>::iterator itLayers=mLayers->begin(); itLayers!=mLayers->end(); itLayers++)
nuclear@0 208 if (!itLayers->skip)
nuclear@0 209 layerCount++;
nuclear@0 210 if (layerCount!=2)
nuclear@0 211 throw DeadlyImportError("LWO2: The requested layer was not found");
nuclear@0 212 }
nuclear@0 213
nuclear@0 214 if (configLayerName.length() && !hasNamedLayer) {
nuclear@0 215 throw DeadlyImportError("LWO2: Unable to find the requested layer: "
nuclear@0 216 + configLayerName);
nuclear@0 217 }
nuclear@0 218 }
nuclear@0 219
nuclear@0 220 // now, as we have loaded all data, we can resolve cross-referenced tags and clips
nuclear@0 221 ResolveTags();
nuclear@0 222 ResolveClips();
nuclear@0 223
nuclear@0 224 // now process all layers and build meshes and nodes
nuclear@0 225 std::vector<aiMesh*> apcMeshes;
nuclear@0 226 std::map<uint16_t, aiNode*> apcNodes;
nuclear@0 227
nuclear@0 228 apcMeshes.reserve(mLayers->size()*std::min(((unsigned int)mSurfaces->size()/2u), 1u));
nuclear@0 229
nuclear@0 230 unsigned int iDefaultSurface = UINT_MAX; // index of the default surface
nuclear@0 231 for (LayerList::iterator lit = mLayers->begin(), lend = mLayers->end();lit != lend;++lit) {
nuclear@0 232 LWO::Layer& layer = *lit;
nuclear@0 233 if (layer.skip)
nuclear@0 234 continue;
nuclear@0 235
nuclear@0 236 // I don't know whether there could be dummy layers, but it would be possible
nuclear@0 237 const unsigned int meshStart = (unsigned int)apcMeshes.size();
nuclear@0 238 if (!layer.mFaces.empty() && !layer.mTempPoints.empty()) {
nuclear@0 239
nuclear@0 240 // now sort all faces by the surfaces assigned to them
nuclear@0 241 std::vector<SortedRep> pSorted(mSurfaces->size()+1);
nuclear@0 242
nuclear@0 243 unsigned int i = 0;
nuclear@0 244 for (FaceList::iterator it = layer.mFaces.begin(), end = layer.mFaces.end();it != end;++it,++i) {
nuclear@0 245 // Check whether we support this face's type
nuclear@0 246 if ((*it).type != AI_LWO_FACE && (*it).type != AI_LWO_PTCH &&
nuclear@0 247 (*it).type != AI_LWO_BONE && (*it).type != AI_LWO_SUBD) {
nuclear@0 248 continue;
nuclear@0 249 }
nuclear@0 250
nuclear@0 251 unsigned int idx = (*it).surfaceIndex;
nuclear@0 252 if (idx >= mTags->size())
nuclear@0 253 {
nuclear@0 254 DefaultLogger::get()->warn("LWO: Invalid face surface index");
nuclear@0 255 idx = UINT_MAX;
nuclear@0 256 }
nuclear@0 257 if(UINT_MAX == idx || UINT_MAX == (idx = _mMapping[idx])) {
nuclear@0 258 if (UINT_MAX == iDefaultSurface) {
nuclear@0 259 iDefaultSurface = (unsigned int)mSurfaces->size();
nuclear@0 260 mSurfaces->push_back(LWO::Surface());
nuclear@0 261 LWO::Surface& surf = mSurfaces->back();
nuclear@0 262 surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f;
nuclear@0 263 surf.mName = "LWODefaultSurface";
nuclear@0 264 }
nuclear@0 265 idx = iDefaultSurface;
nuclear@0 266 }
nuclear@0 267 pSorted[idx].push_back(i);
nuclear@0 268 }
nuclear@0 269 if (UINT_MAX == iDefaultSurface) {
nuclear@0 270 pSorted.erase(pSorted.end()-1);
nuclear@0 271 }
nuclear@0 272 for (unsigned int p = 0,i = 0;i < mSurfaces->size();++i) {
nuclear@0 273 SortedRep& sorted = pSorted[i];
nuclear@0 274 if (sorted.empty())
nuclear@0 275 continue;
nuclear@0 276
nuclear@0 277 // generate the mesh
nuclear@0 278 aiMesh* mesh = new aiMesh();
nuclear@0 279 apcMeshes.push_back(mesh);
nuclear@0 280 mesh->mNumFaces = (unsigned int)sorted.size();
nuclear@0 281
nuclear@0 282 // count the number of vertices
nuclear@0 283 SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
nuclear@0 284 for (;it != end;++it) {
nuclear@0 285 mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
nuclear@0 286 }
nuclear@0 287
nuclear@0 288 aiVector3D *nrm = NULL, * pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
nuclear@0 289 aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
nuclear@0 290 mesh->mMaterialIndex = i;
nuclear@0 291
nuclear@0 292 // find out which vertex color channels and which texture coordinate
nuclear@0 293 // channels are really required by the material attached to this mesh
nuclear@0 294 unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
nuclear@0 295 unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
nuclear@0 296
nuclear@0 297 #if _DEBUG
nuclear@0 298 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
nuclear@0 299 vUVChannelIndices[mui] = UINT_MAX;
nuclear@0 300 }
nuclear@0 301 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui ) {
nuclear@0 302 vVColorIndices[mui] = UINT_MAX;
nuclear@0 303 }
nuclear@0 304 #endif
nuclear@0 305
nuclear@0 306 FindUVChannels(_mSurfaces[i],sorted,layer,vUVChannelIndices);
nuclear@0 307 FindVCChannels(_mSurfaces[i],sorted,layer,vVColorIndices);
nuclear@0 308
nuclear@0 309 // allocate storage for UV and CV channels
nuclear@0 310 aiVector3D* pvUV[AI_MAX_NUMBER_OF_TEXTURECOORDS];
nuclear@0 311 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
nuclear@0 312 if (UINT_MAX == vUVChannelIndices[mui]) {
nuclear@0 313 break;
nuclear@0 314 }
nuclear@0 315
nuclear@0 316 pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices];
nuclear@0 317
nuclear@0 318 // LightWave doesn't support more than 2 UV components (?)
nuclear@0 319 mesh->mNumUVComponents[0] = 2;
nuclear@0 320 }
nuclear@0 321
nuclear@0 322 if (layer.mNormals.name.length())
nuclear@0 323 nrm = mesh->mNormals = new aiVector3D[mesh->mNumVertices];
nuclear@0 324
nuclear@0 325 aiColor4D* pvVC[AI_MAX_NUMBER_OF_COLOR_SETS];
nuclear@0 326 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui) {
nuclear@0 327 if (UINT_MAX == vVColorIndices[mui]) {
nuclear@0 328 break;
nuclear@0 329 }
nuclear@0 330 pvVC[mui] = mesh->mColors[mui] = new aiColor4D[mesh->mNumVertices];
nuclear@0 331 }
nuclear@0 332
nuclear@0 333 // we would not need this extra array, but the code is much cleaner if we use it
nuclear@0 334 std::vector<unsigned int>& smoothingGroups = layer.mPointReferrers;
nuclear@0 335 smoothingGroups.erase (smoothingGroups.begin(),smoothingGroups.end());
nuclear@0 336 smoothingGroups.resize(mesh->mNumFaces,0);
nuclear@0 337
nuclear@0 338 // now convert all faces
nuclear@0 339 unsigned int vert = 0;
nuclear@0 340 std::vector<unsigned int>::iterator outIt = smoothingGroups.begin();
nuclear@0 341 for (it = sorted.begin(); it != end;++it,++outIt) {
nuclear@0 342 const LWO::Face& face = layer.mFaces[*it];
nuclear@0 343 *outIt = face.smoothGroup;
nuclear@0 344
nuclear@0 345 // copy all vertices
nuclear@0 346 for (unsigned int q = 0; q < face.mNumIndices;++q,++vert) {
nuclear@0 347 register unsigned int idx = face.mIndices[q];
nuclear@0 348 *pv++ = layer.mTempPoints[idx] /*- layer.mPivot*/;
nuclear@0 349
nuclear@0 350 // process UV coordinates
nuclear@0 351 for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w) {
nuclear@0 352 if (UINT_MAX == vUVChannelIndices[w]) {
nuclear@0 353 break;
nuclear@0 354 }
nuclear@0 355 aiVector3D*& pp = pvUV[w];
nuclear@0 356 const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx];
nuclear@0 357 pp->x = src.x;
nuclear@0 358 pp->y = src.y;
nuclear@0 359 pp++;
nuclear@0 360 }
nuclear@0 361
nuclear@0 362 // process normals (MODO extension)
nuclear@0 363 if (nrm) {
nuclear@0 364 *nrm = ((aiVector3D*)&layer.mNormals.rawData[0])[idx];
nuclear@0 365 nrm->z *= -1.f;
nuclear@0 366 ++nrm;
nuclear@0 367 }
nuclear@0 368
nuclear@0 369 // process vertex colors
nuclear@0 370 for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) {
nuclear@0 371 if (UINT_MAX == vVColorIndices[w]) {
nuclear@0 372 break;
nuclear@0 373 }
nuclear@0 374 *pvVC[w] = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
nuclear@0 375
nuclear@0 376 // If a RGB color map is explicitly requested delete the
nuclear@0 377 // alpha channel - it could theoretically be != 1.
nuclear@0 378 if(_mSurfaces[i].mVCMapType == AI_LWO_RGB)
nuclear@0 379 pvVC[w]->a = 1.f;
nuclear@0 380
nuclear@0 381 pvVC[w]++;
nuclear@0 382 }
nuclear@0 383
nuclear@0 384 #if 0
nuclear@0 385 // process vertex weights. We can't properly reconstruct the whole skeleton for now,
nuclear@0 386 // but we can create dummy bones for all weight channels which we have.
nuclear@0 387 for (unsigned int w = 0; w < layer.mWeightChannels.size();++w)
nuclear@0 388 {
nuclear@0 389 }
nuclear@0 390 #endif
nuclear@0 391
nuclear@0 392 face.mIndices[q] = vert;
nuclear@0 393 }
nuclear@0 394 pf->mIndices = face.mIndices;
nuclear@0 395 pf->mNumIndices = face.mNumIndices;
nuclear@0 396 unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // HACK: make sure it won't be deleted
nuclear@0 397 pf++;
nuclear@0 398 }
nuclear@0 399
nuclear@0 400 if (!mesh->mNormals) {
nuclear@0 401 // Compute normal vectors for the mesh - we can't use our GenSmoothNormal-
nuclear@0 402 // Step here since it wouldn't handle smoothing groups correctly for LWO.
nuclear@0 403 // So we use a separate implementation.
nuclear@0 404 ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]);
nuclear@0 405 }
nuclear@0 406 else DefaultLogger::get()->debug("LWO2: No need to compute normals, they're already there");
nuclear@0 407 ++p;
nuclear@0 408 }
nuclear@0 409 }
nuclear@0 410
nuclear@0 411 // Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes
nuclear@0 412 unsigned int num = apcMeshes.size() - meshStart;
nuclear@0 413 if (layer.mName != "<LWODefault>" || num > 0) {
nuclear@0 414 aiNode* pcNode = new aiNode();
nuclear@0 415 apcNodes[layer.mIndex] = pcNode;
nuclear@0 416 pcNode->mName.Set(layer.mName);
nuclear@0 417 pcNode->mParent = (aiNode*)&layer;
nuclear@0 418 pcNode->mNumMeshes = num;
nuclear@0 419
nuclear@0 420 if (pcNode->mNumMeshes) {
nuclear@0 421 pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
nuclear@0 422 for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
nuclear@0 423 pcNode->mMeshes[p] = p + meshStart;
nuclear@0 424 }
nuclear@0 425 }
nuclear@0 426 }
nuclear@0 427
nuclear@0 428 if (apcNodes.empty() || apcMeshes.empty())
nuclear@0 429 throw DeadlyImportError("LWO: No meshes loaded");
nuclear@0 430
nuclear@0 431 // The RemoveRedundantMaterials step will clean this up later
nuclear@0 432 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
nuclear@0 433 for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat) {
nuclear@0 434 aiMaterial* pcMat = new aiMaterial();
nuclear@0 435 pScene->mMaterials[mat] = pcMat;
nuclear@0 436 ConvertMaterial((*mSurfaces)[mat],pcMat);
nuclear@0 437 }
nuclear@0 438
nuclear@0 439 // copy the meshes to the output structure
nuclear@0 440 pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = (unsigned int)apcMeshes.size() ];
nuclear@0 441 ::memcpy(pScene->mMeshes,&apcMeshes[0],pScene->mNumMeshes*sizeof(void*));
nuclear@0 442
nuclear@0 443 // generate the final node graph
nuclear@0 444 GenerateNodeGraph(apcNodes);
nuclear@0 445 }
nuclear@0 446
nuclear@0 447 // ------------------------------------------------------------------------------------------------
nuclear@0 448 void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>& smoothingGroups,
nuclear@0 449 const LWO::Surface& surface)
nuclear@0 450 {
nuclear@0 451 // Allocate output storage
nuclear@0 452 mesh->mNormals = new aiVector3D[mesh->mNumVertices];
nuclear@0 453
nuclear@0 454 // First generate per-face normals
nuclear@0 455 aiVector3D* out;
nuclear@0 456 std::vector<aiVector3D> faceNormals;
nuclear@0 457
nuclear@0 458 // ... in some cases that's already enough
nuclear@0 459 if (!surface.mMaximumSmoothAngle)
nuclear@0 460 out = mesh->mNormals;
nuclear@0 461 else {
nuclear@0 462 faceNormals.resize(mesh->mNumVertices);
nuclear@0 463 out = &faceNormals[0];
nuclear@0 464 }
nuclear@0 465
nuclear@0 466 aiFace* begin = mesh->mFaces, *const end = mesh->mFaces+mesh->mNumFaces;
nuclear@0 467 for (; begin != end; ++begin) {
nuclear@0 468 aiFace& face = *begin;
nuclear@0 469
nuclear@0 470 if(face.mNumIndices < 3) {
nuclear@0 471 continue;
nuclear@0 472 }
nuclear@0 473
nuclear@0 474 // LWO doc: "the normal is defined as the cross product of the first and last edges"
nuclear@0 475 aiVector3D* pV1 = mesh->mVertices + face.mIndices[0];
nuclear@0 476 aiVector3D* pV2 = mesh->mVertices + face.mIndices[1];
nuclear@0 477 aiVector3D* pV3 = mesh->mVertices + face.mIndices[face.mNumIndices-1];
nuclear@0 478
nuclear@0 479 aiVector3D vNor = ((*pV2 - *pV1) ^(*pV3 - *pV1)).Normalize();
nuclear@0 480 for (unsigned int i = 0; i < face.mNumIndices;++i)
nuclear@0 481 out[face.mIndices[i]] = vNor;
nuclear@0 482 }
nuclear@0 483 if (!surface.mMaximumSmoothAngle)return;
nuclear@0 484 const float posEpsilon = ComputePositionEpsilon(mesh);
nuclear@0 485
nuclear@0 486 // Now generate the spatial sort tree
nuclear@0 487 SGSpatialSort sSort;
nuclear@0 488 std::vector<unsigned int>::const_iterator it = smoothingGroups.begin();
nuclear@0 489 for( begin = mesh->mFaces; begin != end; ++begin, ++it)
nuclear@0 490 {
nuclear@0 491 aiFace& face = *begin;
nuclear@0 492 for (unsigned int i = 0; i < face.mNumIndices;++i)
nuclear@0 493 {
nuclear@0 494 register unsigned int tt = face.mIndices[i];
nuclear@0 495 sSort.Add(mesh->mVertices[tt],tt,*it);
nuclear@0 496 }
nuclear@0 497 }
nuclear@0 498 // Sort everything - this takes O(nlogn) time
nuclear@0 499 sSort.Prepare();
nuclear@0 500 std::vector<unsigned int> poResult;
nuclear@0 501 poResult.reserve(20);
nuclear@0 502
nuclear@0 503 // Generate vertex normals. We have O(logn) for the binary lookup, which we need
nuclear@0 504 // for n elements, thus the EXPECTED complexity is O(nlogn)
nuclear@0 505 if (surface.mMaximumSmoothAngle < 3.f && !configSpeedFlag) {
nuclear@0 506 const float fLimit = cos(surface.mMaximumSmoothAngle);
nuclear@0 507
nuclear@0 508 for( begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) {
nuclear@0 509 const aiFace& face = *begin;
nuclear@0 510 unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
nuclear@0 511 for (; beginIdx != endIdx; ++beginIdx)
nuclear@0 512 {
nuclear@0 513 register unsigned int idx = *beginIdx;
nuclear@0 514 sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true);
nuclear@0 515 std::vector<unsigned int>::const_iterator a, end = poResult.end();
nuclear@0 516
nuclear@0 517 aiVector3D vNormals;
nuclear@0 518 for (a = poResult.begin();a != end;++a) {
nuclear@0 519 const aiVector3D& v = faceNormals[*a];
nuclear@0 520 if (v * faceNormals[idx] < fLimit)
nuclear@0 521 continue;
nuclear@0 522 vNormals += v;
nuclear@0 523 }
nuclear@0 524 mesh->mNormals[idx] = vNormals.Normalize();
nuclear@0 525 }
nuclear@0 526 }
nuclear@0 527 }
nuclear@0 528 // faster code path in case there is no smooth angle
nuclear@0 529 else {
nuclear@0 530 std::vector<bool> vertexDone(mesh->mNumVertices,false);
nuclear@0 531 for( begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) {
nuclear@0 532 const aiFace& face = *begin;
nuclear@0 533 unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
nuclear@0 534 for (; beginIdx != endIdx; ++beginIdx)
nuclear@0 535 {
nuclear@0 536 register unsigned int idx = *beginIdx;
nuclear@0 537 if (vertexDone[idx])
nuclear@0 538 continue;
nuclear@0 539 sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true);
nuclear@0 540 std::vector<unsigned int>::const_iterator a, end = poResult.end();
nuclear@0 541
nuclear@0 542 aiVector3D vNormals;
nuclear@0 543 for (a = poResult.begin();a != end;++a) {
nuclear@0 544 const aiVector3D& v = faceNormals[*a];
nuclear@0 545 vNormals += v;
nuclear@0 546 }
nuclear@0 547 vNormals.Normalize();
nuclear@0 548 for (a = poResult.begin();a != end;++a) {
nuclear@0 549 mesh->mNormals[*a] = vNormals;
nuclear@0 550 vertexDone[*a] = true;
nuclear@0 551 }
nuclear@0 552 }
nuclear@0 553 }
nuclear@0 554 }
nuclear@0 555 }
nuclear@0 556
nuclear@0 557 // ------------------------------------------------------------------------------------------------
nuclear@0 558 void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
nuclear@0 559 {
nuclear@0 560 // now generate the final nodegraph - generate a root node and attach children
nuclear@0 561 aiNode* root = pScene->mRootNode = new aiNode();
nuclear@0 562 root->mName.Set("<LWORoot>");
nuclear@0 563
nuclear@0 564 //Set parent of all children, inserting pivots
nuclear@0 565 //std::cout << "Set parent of all children" << std::endl;
nuclear@0 566 std::map<uint16_t, aiNode*> mapPivot;
nuclear@0 567 for (std::map<uint16_t,aiNode*>::iterator itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
nuclear@0 568
nuclear@0 569 //Get the parent index
nuclear@0 570 LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent);
nuclear@0 571 uint16_t parentIndex = nodeLayer->mParent;
nuclear@0 572
nuclear@0 573 //Create pivot node, store it into the pivot map, and set the parent as the pivot
nuclear@0 574 aiNode* pivotNode = new aiNode();
nuclear@0 575 pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data));
nuclear@0 576 mapPivot[-(itapcNodes->first+2)] = pivotNode;
nuclear@0 577 itapcNodes->second->mParent = pivotNode;
nuclear@0 578
nuclear@0 579 //Look for the parent node to attach the pivot to
nuclear@0 580 if (apcNodes.find(parentIndex) != apcNodes.end()) {
nuclear@0 581 pivotNode->mParent = apcNodes[parentIndex];
nuclear@0 582 } else {
nuclear@0 583 //If not, attach to the root node
nuclear@0 584 pivotNode->mParent = root;
nuclear@0 585 }
nuclear@0 586
nuclear@0 587 //Set the node and the pivot node transformation
nuclear@0 588 itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
nuclear@0 589 itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
nuclear@0 590 itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
nuclear@0 591 pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
nuclear@0 592 pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
nuclear@0 593 pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
nuclear@0 594 }
nuclear@0 595
nuclear@0 596 //Merge pivot map into node map
nuclear@0 597 //std::cout << "Merge pivot map into node map" << std::endl;
nuclear@0 598 for (std::map<uint16_t, aiNode*>::iterator itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
nuclear@0 599 apcNodes[itMapPivot->first] = itMapPivot->second;
nuclear@0 600 }
nuclear@0 601
nuclear@0 602 //Set children of all parents
nuclear@0 603 apcNodes[-1] = root;
nuclear@0 604 for (std::map<uint16_t,aiNode*>::iterator itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
nuclear@0 605 for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
nuclear@0 606 if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
nuclear@0 607 ++(itMapParentNodes->second->mNumChildren);
nuclear@0 608 }
nuclear@0 609 }
nuclear@0 610 if (itMapParentNodes->second->mNumChildren) {
nuclear@0 611 itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ];
nuclear@0 612 uint16_t p = 0;
nuclear@0 613 for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
nuclear@0 614 if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
nuclear@0 615 itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
nuclear@0 616 }
nuclear@0 617 }
nuclear@0 618 }
nuclear@0 619 }
nuclear@0 620
nuclear@0 621 if (!pScene->mRootNode->mNumChildren)
nuclear@0 622 throw DeadlyImportError("LWO: Unable to build a valid node graph");
nuclear@0 623
nuclear@0 624 // Remove a single root node with no meshes assigned to it ...
nuclear@0 625 if (1 == pScene->mRootNode->mNumChildren) {
nuclear@0 626 aiNode* pc = pScene->mRootNode->mChildren[0];
nuclear@0 627 pc->mParent = pScene->mRootNode->mChildren[0] = NULL;
nuclear@0 628 delete pScene->mRootNode;
nuclear@0 629 pScene->mRootNode = pc;
nuclear@0 630 }
nuclear@0 631
nuclear@0 632 // convert the whole stuff to RH with CCW winding
nuclear@0 633 MakeLeftHandedProcess maker;
nuclear@0 634 maker.Execute(pScene);
nuclear@0 635
nuclear@0 636 FlipWindingOrderProcess flipper;
nuclear@0 637 flipper.Execute(pScene);
nuclear@0 638 }
nuclear@0 639
nuclear@0 640 // ------------------------------------------------------------------------------------------------
nuclear@0 641 void LWOImporter::ResolveTags()
nuclear@0 642 {
nuclear@0 643 // --- this function is used for both LWO2 and LWOB
nuclear@0 644 mMapping->resize(mTags->size(), UINT_MAX);
nuclear@0 645 for (unsigned int a = 0; a < mTags->size();++a) {
nuclear@0 646
nuclear@0 647 const std::string& c = (*mTags)[a];
nuclear@0 648 for (unsigned int i = 0; i < mSurfaces->size();++i) {
nuclear@0 649
nuclear@0 650 const std::string& d = (*mSurfaces)[i].mName;
nuclear@0 651 if (!ASSIMP_stricmp(c,d)) {
nuclear@0 652
nuclear@0 653 (*mMapping)[a] = i;
nuclear@0 654 break;
nuclear@0 655 }
nuclear@0 656 }
nuclear@0 657 }
nuclear@0 658 }
nuclear@0 659
nuclear@0 660 // ------------------------------------------------------------------------------------------------
nuclear@0 661 void LWOImporter::ResolveClips()
nuclear@0 662 {
nuclear@0 663 for( unsigned int i = 0; i < mClips.size();++i) {
nuclear@0 664
nuclear@0 665 Clip& clip = mClips[i];
nuclear@0 666 if (Clip::REF == clip.type) {
nuclear@0 667
nuclear@0 668 if (clip.clipRef >= mClips.size()) {
nuclear@0 669 DefaultLogger::get()->error("LWO2: Clip referrer index is out of range");
nuclear@0 670 clip.clipRef = 0;
nuclear@0 671 }
nuclear@0 672
nuclear@0 673 Clip& dest = mClips[clip.clipRef];
nuclear@0 674 if (Clip::REF == dest.type) {
nuclear@0 675 DefaultLogger::get()->error("LWO2: Clip references another clip reference");
nuclear@0 676 clip.type = Clip::UNSUPPORTED;
nuclear@0 677 }
nuclear@0 678
nuclear@0 679 else {
nuclear@0 680 clip.path = dest.path;
nuclear@0 681 clip.type = dest.type;
nuclear@0 682 }
nuclear@0 683 }
nuclear@0 684 }
nuclear@0 685 }
nuclear@0 686
nuclear@0 687 // ------------------------------------------------------------------------------------------------
nuclear@0 688 void LWOImporter::AdjustTexturePath(std::string& out)
nuclear@0 689 {
nuclear@0 690 // --- this function is used for both LWO2 and LWOB
nuclear@0 691 if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)")) {
nuclear@0 692
nuclear@0 693 // remove the (sequence) and append 000
nuclear@0 694 DefaultLogger::get()->info("LWOB: Sequence of animated texture found. It will be ignored");
nuclear@0 695 out = out.substr(0,out.length()-10) + "000";
nuclear@0 696 }
nuclear@0 697
nuclear@0 698 // format: drive:path/file - we just need to insert a slash after the drive
nuclear@0 699 std::string::size_type n = out.find_first_of(':');
nuclear@0 700 if (std::string::npos != n) {
nuclear@0 701 out.insert(n+1,"/");
nuclear@0 702 }
nuclear@0 703 }
nuclear@0 704
nuclear@0 705 // ------------------------------------------------------------------------------------------------
nuclear@0 706 void LWOImporter::LoadLWOTags(unsigned int size)
nuclear@0 707 {
nuclear@0 708 // --- this function is used for both LWO2 and LWOB
nuclear@0 709
nuclear@0 710 const char* szCur = (const char*)mFileBuffer, *szLast = szCur;
nuclear@0 711 const char* const szEnd = szLast+size;
nuclear@0 712 while (szCur < szEnd)
nuclear@0 713 {
nuclear@0 714 if (!(*szCur))
nuclear@0 715 {
nuclear@0 716 const size_t len = (size_t)(szCur-szLast);
nuclear@0 717 // FIX: skip empty-sized tags
nuclear@0 718 if (len)
nuclear@0 719 mTags->push_back(std::string(szLast,len));
nuclear@0 720 szCur += (len&0x1 ? 1 : 2);
nuclear@0 721 szLast = szCur;
nuclear@0 722 }
nuclear@0 723 szCur++;
nuclear@0 724 }
nuclear@0 725 }
nuclear@0 726
nuclear@0 727 // ------------------------------------------------------------------------------------------------
nuclear@0 728 void LWOImporter::LoadLWOPoints(unsigned int length)
nuclear@0 729 {
nuclear@0 730 // --- this function is used for both LWO2 and LWOB but for
nuclear@0 731 // LWO2 we need to allocate 25% more storage - it could be we'll
nuclear@0 732 // need to duplicate some points later.
nuclear@0 733 register unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
nuclear@0 734 if (mIsLWO2)
nuclear@0 735 {
nuclear@0 736 mCurLayer->mTempPoints.reserve ( regularSize + (regularSize>>2u) );
nuclear@0 737 mCurLayer->mTempPoints.resize ( regularSize );
nuclear@0 738
nuclear@0 739 // initialize all point referrers with the default values
nuclear@0 740 mCurLayer->mPointReferrers.reserve ( regularSize + (regularSize>>2u) );
nuclear@0 741 mCurLayer->mPointReferrers.resize ( regularSize, UINT_MAX );
nuclear@0 742 }
nuclear@0 743 else mCurLayer->mTempPoints.resize( regularSize );
nuclear@0 744
nuclear@0 745 // perform endianess conversions
nuclear@0 746 #ifndef AI_BUILD_BIG_ENDIAN
nuclear@0 747 for (unsigned int i = 0; i < length>>2;++i)
nuclear@0 748 ByteSwap::Swap4( mFileBuffer + (i << 2));
nuclear@0 749 #endif
nuclear@0 750 ::memcpy(&mCurLayer->mTempPoints[0],mFileBuffer,length);
nuclear@0 751 }
nuclear@0 752
nuclear@0 753 // ------------------------------------------------------------------------------------------------
nuclear@0 754 void LWOImporter::LoadLWO2Polygons(unsigned int length)
nuclear@0 755 {
nuclear@0 756 LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
nuclear@0 757 const uint32_t type = GetU4();
nuclear@0 758
nuclear@0 759 // Determine the type of the polygons
nuclear@0 760 switch (type)
nuclear@0 761 {
nuclear@0 762 // read unsupported stuff too (although we wont process it)
nuclear@0 763 case AI_LWO_MBAL:
nuclear@0 764 DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (METABALL)");
nuclear@0 765 break;
nuclear@0 766 case AI_LWO_CURV:
nuclear@0 767 DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (SPLINE)");;
nuclear@0 768 break;
nuclear@0 769
nuclear@0 770 // These are ok with no restrictions
nuclear@0 771 case AI_LWO_PTCH:
nuclear@0 772 case AI_LWO_FACE:
nuclear@0 773 case AI_LWO_BONE:
nuclear@0 774 case AI_LWO_SUBD:
nuclear@0 775 break;
nuclear@0 776 default:
nuclear@0 777
nuclear@0 778 // hm!? wtf is this? ok ...
nuclear@0 779 DefaultLogger::get()->error("LWO2: Ignoring unknown polygon type.");
nuclear@0 780 break;
nuclear@0 781 }
nuclear@0 782
nuclear@0 783 // first find out how many faces and vertices we'll finally need
nuclear@0 784 uint16_t* cursor= (uint16_t*)mFileBuffer;
nuclear@0 785
nuclear@0 786 unsigned int iNumFaces = 0,iNumVertices = 0;
nuclear@0 787 CountVertsAndFacesLWO2(iNumVertices,iNumFaces,cursor,end);
nuclear@0 788
nuclear@0 789 // allocate the output array and copy face indices
nuclear@0 790 if (iNumFaces) {
nuclear@0 791 cursor = (uint16_t*)mFileBuffer;
nuclear@0 792
nuclear@0 793 mCurLayer->mFaces.resize(iNumFaces,LWO::Face(type));
nuclear@0 794 FaceList::iterator it = mCurLayer->mFaces.begin();
nuclear@0 795 CopyFaceIndicesLWO2(it,cursor,end);
nuclear@0 796 }
nuclear@0 797 }
nuclear@0 798
nuclear@0 799 // ------------------------------------------------------------------------------------------------
nuclear@0 800 void LWOImporter::CountVertsAndFacesLWO2(unsigned int& verts, unsigned int& faces,
nuclear@0 801 uint16_t*& cursor, const uint16_t* const end, unsigned int max)
nuclear@0 802 {
nuclear@0 803 while (cursor < end && max--)
nuclear@0 804 {
nuclear@0 805 AI_LSWAP2P(cursor);
nuclear@0 806 uint16_t numIndices = *cursor++;
nuclear@0 807 numIndices &= 0x03FF;
nuclear@0 808 verts += numIndices;++faces;
nuclear@0 809
nuclear@0 810 for(uint16_t i = 0; i < numIndices; i++)
nuclear@0 811 ReadVSizedIntLWO2((uint8_t*&)cursor);
nuclear@0 812 }
nuclear@0 813 }
nuclear@0 814
nuclear@0 815 // ------------------------------------------------------------------------------------------------
nuclear@0 816 void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator& it,
nuclear@0 817 uint16_t*& cursor,
nuclear@0 818 const uint16_t* const end)
nuclear@0 819 {
nuclear@0 820 while (cursor < end) {
nuclear@0 821
nuclear@0 822 LWO::Face& face = *it++;;
nuclear@0 823 if((face.mNumIndices = (*cursor++) & 0x03FF)) /* byte swapping has already been done */ {
nuclear@0 824 face.mIndices = new unsigned int[face.mNumIndices];
nuclear@0 825 for(unsigned int i = 0; i < face.mNumIndices; i++)
nuclear@0 826 {
nuclear@0 827 face.mIndices[i] = ReadVSizedIntLWO2((uint8_t*&)cursor) + mCurLayer->mPointIDXOfs;
nuclear@0 828 if(face.mIndices[i] > mCurLayer->mTempPoints.size())
nuclear@0 829 {
nuclear@0 830 DefaultLogger::get()->warn("LWO2: Failure evaluating face record, index is out of range");
nuclear@0 831 face.mIndices[i] = (unsigned int)mCurLayer->mTempPoints.size()-1;
nuclear@0 832 }
nuclear@0 833 }
nuclear@0 834 }
nuclear@0 835 else throw DeadlyImportError("LWO2: Encountered invalid face record with zero indices");
nuclear@0 836 }
nuclear@0 837 }
nuclear@0 838
nuclear@0 839
nuclear@0 840 // ------------------------------------------------------------------------------------------------
nuclear@0 841 void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
nuclear@0 842 {
nuclear@0 843 LE_NCONST uint8_t* const end = mFileBuffer+length;
nuclear@0 844
nuclear@0 845 AI_LWO_VALIDATE_CHUNK_LENGTH(length,PTAG,4);
nuclear@0 846 uint32_t type = GetU4();
nuclear@0 847
nuclear@0 848 if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
nuclear@0 849 return;
nuclear@0 850
nuclear@0 851 while (mFileBuffer < end) {
nuclear@0 852
nuclear@0 853 unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
nuclear@0 854 unsigned int j = GetU2();
nuclear@0 855
nuclear@0 856 if (i >= mCurLayer->mFaces.size()) {
nuclear@0 857 DefaultLogger::get()->warn("LWO2: face index in PTAG is out of range");
nuclear@0 858 continue;
nuclear@0 859 }
nuclear@0 860
nuclear@0 861 switch (type) {
nuclear@0 862
nuclear@0 863 case AI_LWO_SURF:
nuclear@0 864 mCurLayer->mFaces[i].surfaceIndex = j;
nuclear@0 865 break;
nuclear@0 866 case AI_LWO_SMGP: /* is that really used? */
nuclear@0 867 mCurLayer->mFaces[i].smoothGroup = j;
nuclear@0 868 break;
nuclear@0 869 };
nuclear@0 870 }
nuclear@0 871 }
nuclear@0 872
nuclear@0 873 // ------------------------------------------------------------------------------------------------
nuclear@0 874 template <class T>
nuclear@0 875 VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPoly)
nuclear@0 876 {
nuclear@0 877 for (typename std::vector< T >::iterator it = list.begin(), end = list.end();it != end; ++it) {
nuclear@0 878 if ((*it).name == name) {
nuclear@0 879 if (!perPoly) {
nuclear@0 880 DefaultLogger::get()->warn("LWO2: Found two VMAP sections with equal names");
nuclear@0 881 }
nuclear@0 882 return &(*it);
nuclear@0 883 }
nuclear@0 884 }
nuclear@0 885 list.push_back( T() );
nuclear@0 886 VMapEntry* p = &list.back();
nuclear@0 887 p->name = name;
nuclear@0 888 return p;
nuclear@0 889 }
nuclear@0 890
nuclear@0 891 // ------------------------------------------------------------------------------------------------
nuclear@0 892 template <class T>
nuclear@0 893 inline void CreateNewEntry(T& chan, unsigned int srcIdx)
nuclear@0 894 {
nuclear@0 895 if (!chan.name.length())
nuclear@0 896 return;
nuclear@0 897
nuclear@0 898 chan.abAssigned[srcIdx] = true;
nuclear@0 899 chan.abAssigned.resize(chan.abAssigned.size()+1,false);
nuclear@0 900
nuclear@0 901 for (unsigned int a = 0; a < chan.dims;++a)
nuclear@0 902 chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]);
nuclear@0 903 }
nuclear@0 904
nuclear@0 905 // ------------------------------------------------------------------------------------------------
nuclear@0 906 template <class T>
nuclear@0 907 inline void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx)
nuclear@0 908 {
nuclear@0 909 for (typename std::vector< T >::iterator it = list.begin(), end = list.end();it != end;++it) {
nuclear@0 910 CreateNewEntry( *it, srcIdx );
nuclear@0 911 }
nuclear@0 912 }
nuclear@0 913
nuclear@0 914 // ------------------------------------------------------------------------------------------------
nuclear@0 915 inline void LWOImporter::DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int numRead,
nuclear@0 916 unsigned int idx, float* data)
nuclear@0 917 {
nuclear@0 918 ai_assert(NULL != data);
nuclear@0 919 LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
nuclear@0 920 unsigned int i;
nuclear@0 921
nuclear@0 922 base->abAssigned[idx] = true;
nuclear@0 923 for (i = 0; i < numRead;++i) {
nuclear@0 924 base->rawData[idx*base->dims+i]= data[i];
nuclear@0 925 }
nuclear@0 926
nuclear@0 927 if (UINT_MAX != (i = refList[idx])) {
nuclear@0 928 DoRecursiveVMAPAssignment(base,numRead,i,data);
nuclear@0 929 }
nuclear@0 930 }
nuclear@0 931
nuclear@0 932 // ------------------------------------------------------------------------------------------------
nuclear@0 933 inline void AddToSingleLinkedList(ReferrerList& refList, unsigned int srcIdx, unsigned int destIdx)
nuclear@0 934 {
nuclear@0 935 if(UINT_MAX == refList[srcIdx]) {
nuclear@0 936 refList[srcIdx] = destIdx;
nuclear@0 937 return;
nuclear@0 938 }
nuclear@0 939 AddToSingleLinkedList(refList,refList[srcIdx],destIdx);
nuclear@0 940 }
nuclear@0 941
nuclear@0 942 // ------------------------------------------------------------------------------------------------
nuclear@0 943 // Load LWO2 vertex map
nuclear@0 944 void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
nuclear@0 945 {
nuclear@0 946 LE_NCONST uint8_t* const end = mFileBuffer+length;
nuclear@0 947
nuclear@0 948 AI_LWO_VALIDATE_CHUNK_LENGTH(length,VMAP,6);
nuclear@0 949 unsigned int type = GetU4();
nuclear@0 950 unsigned int dims = GetU2();
nuclear@0 951
nuclear@0 952 VMapEntry* base;
nuclear@0 953
nuclear@0 954 // read the name of the vertex map
nuclear@0 955 std::string name;
nuclear@0 956 GetS0(name,length);
nuclear@0 957
nuclear@0 958 switch (type)
nuclear@0 959 {
nuclear@0 960 case AI_LWO_TXUV:
nuclear@0 961 if (dims != 2) {
nuclear@0 962 DefaultLogger::get()->warn("LWO2: Skipping UV channel \'"
nuclear@0 963 + name + "\' with !2 components");
nuclear@0 964 return;
nuclear@0 965 }
nuclear@0 966 base = FindEntry(mCurLayer->mUVChannels,name,perPoly);
nuclear@0 967 break;
nuclear@0 968 case AI_LWO_WGHT:
nuclear@0 969 case AI_LWO_MNVW:
nuclear@0 970 if (dims != 1) {
nuclear@0 971 DefaultLogger::get()->warn("LWO2: Skipping Weight Channel \'"
nuclear@0 972 + name + "\' with !1 components");
nuclear@0 973 return;
nuclear@0 974 }
nuclear@0 975 base = FindEntry((type == AI_LWO_WGHT ? mCurLayer->mWeightChannels
nuclear@0 976 : mCurLayer->mSWeightChannels),name,perPoly);
nuclear@0 977 break;
nuclear@0 978 case AI_LWO_RGB:
nuclear@0 979 case AI_LWO_RGBA:
nuclear@0 980 if (dims != 3 && dims != 4) {
nuclear@0 981 DefaultLogger::get()->warn("LWO2: Skipping Color Map \'"
nuclear@0 982 + name + "\' with a dimension > 4 or < 3");
nuclear@0 983 return;
nuclear@0 984 }
nuclear@0 985 base = FindEntry(mCurLayer->mVColorChannels,name,perPoly);
nuclear@0 986 break;
nuclear@0 987
nuclear@0 988 case AI_LWO_MODO_NORM:
nuclear@0 989 /* This is a non-standard extension chunk used by Luxology's MODO.
nuclear@0 990 * It stores per-vertex normals. This VMAP exists just once, has
nuclear@0 991 * 3 dimensions and is btw extremely beautiful.
nuclear@0 992 */
nuclear@0 993 if (name != "vert_normals" || dims != 3 || mCurLayer->mNormals.name.length())
nuclear@0 994 return;
nuclear@0 995
nuclear@0 996 DefaultLogger::get()->info("Processing non-standard extension: MODO VMAP.NORM.vert_normals");
nuclear@0 997
nuclear@0 998 mCurLayer->mNormals.name = name;
nuclear@0 999 base = & mCurLayer->mNormals;
nuclear@0 1000 break;
nuclear@0 1001
nuclear@0 1002 case AI_LWO_PICK: /* these VMAPs are just silently dropped */
nuclear@0 1003 case AI_LWO_MORF:
nuclear@0 1004 case AI_LWO_SPOT:
nuclear@0 1005 return;
nuclear@0 1006
nuclear@0 1007 default:
nuclear@0 1008 if (name == "APS.Level") {
nuclear@0 1009 // XXX handle this (seems to be subdivision-related).
nuclear@0 1010 }
nuclear@0 1011 DefaultLogger::get()->warn("LWO2: Skipping unknown VMAP/VMAD channel \'" + name + "\'");
nuclear@0 1012 return;
nuclear@0 1013 };
nuclear@0 1014 base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
nuclear@0 1015
nuclear@0 1016 // now read all entries in the map
nuclear@0 1017 type = std::min(dims,base->dims);
nuclear@0 1018 const unsigned int diff = (dims - type)<<2u;
nuclear@0 1019
nuclear@0 1020 LWO::FaceList& list = mCurLayer->mFaces;
nuclear@0 1021 LWO::PointList& pointList = mCurLayer->mTempPoints;
nuclear@0 1022 LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
nuclear@0 1023
nuclear@0 1024 float temp[4];
nuclear@0 1025
nuclear@0 1026 const unsigned int numPoints = (unsigned int)pointList.size();
nuclear@0 1027 const unsigned int numFaces = (unsigned int)list.size();
nuclear@0 1028
nuclear@0 1029 while (mFileBuffer < end) {
nuclear@0 1030
nuclear@0 1031 unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs;
nuclear@0 1032 if (idx >= numPoints) {
nuclear@0 1033 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAP/VMAD entry \'" + name + "\', vertex index is out of range");
nuclear@0 1034 mFileBuffer += base->dims<<2u;
nuclear@0 1035 continue;
nuclear@0 1036 }
nuclear@0 1037 if (perPoly) {
nuclear@0 1038 unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
nuclear@0 1039 if (base->abAssigned[idx]) {
nuclear@0 1040 // we have already a VMAP entry for this vertex - thus
nuclear@0 1041 // we need to duplicate the corresponding polygon.
nuclear@0 1042 if (polyIdx >= numFaces) {
nuclear@0 1043 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAD entry \'" + name + "\', polygon index is out of range");
nuclear@0 1044 mFileBuffer += base->dims<<2u;
nuclear@0 1045 continue;
nuclear@0 1046 }
nuclear@0 1047
nuclear@0 1048 LWO::Face& src = list[polyIdx];
nuclear@0 1049
nuclear@0 1050 // generate a new unique vertex for the corresponding index - but only
nuclear@0 1051 // if we can find the index in the face
nuclear@0 1052 bool had = false;
nuclear@0 1053 for (unsigned int i = 0; i < src.mNumIndices;++i) {
nuclear@0 1054
nuclear@0 1055 unsigned int srcIdx = src.mIndices[i], tmp = idx;
nuclear@0 1056 do {
nuclear@0 1057 if (tmp == srcIdx)
nuclear@0 1058 break;
nuclear@0 1059 }
nuclear@0 1060 while ((tmp = refList[tmp]) != UINT_MAX);
nuclear@0 1061 if (tmp == UINT_MAX) {
nuclear@0 1062 continue;
nuclear@0 1063 }
nuclear@0 1064
nuclear@0 1065 had = true;
nuclear@0 1066 refList.resize(refList.size()+1, UINT_MAX);
nuclear@0 1067
nuclear@0 1068 idx = (unsigned int)pointList.size();
nuclear@0 1069 src.mIndices[i] = (unsigned int)pointList.size();
nuclear@0 1070
nuclear@0 1071 // store the index of the new vertex in the old vertex
nuclear@0 1072 // so we get a single linked list we can traverse in
nuclear@0 1073 // only one direction
nuclear@0 1074 AddToSingleLinkedList(refList,srcIdx,src.mIndices[i]);
nuclear@0 1075 pointList.push_back(pointList[srcIdx]);
nuclear@0 1076
nuclear@0 1077 CreateNewEntry(mCurLayer->mVColorChannels, srcIdx );
nuclear@0 1078 CreateNewEntry(mCurLayer->mUVChannels, srcIdx );
nuclear@0 1079 CreateNewEntry(mCurLayer->mWeightChannels, srcIdx );
nuclear@0 1080 CreateNewEntry(mCurLayer->mSWeightChannels, srcIdx );
nuclear@0 1081 CreateNewEntry(mCurLayer->mNormals, srcIdx );
nuclear@0 1082 }
nuclear@0 1083 if (!had) {
nuclear@0 1084 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAD entry \'" + name + "\', vertex index wasn't found in that polygon");
nuclear@0 1085 ai_assert(had);
nuclear@0 1086 }
nuclear@0 1087 }
nuclear@0 1088 }
nuclear@0 1089 for (unsigned int l = 0; l < type;++l)
nuclear@0 1090 temp[l] = GetF4();
nuclear@0 1091
nuclear@0 1092 DoRecursiveVMAPAssignment(base,type,idx, temp);
nuclear@0 1093 mFileBuffer += diff;
nuclear@0 1094 }
nuclear@0 1095 }
nuclear@0 1096
nuclear@0 1097 // ------------------------------------------------------------------------------------------------
nuclear@0 1098 // Load LWO2 clip
nuclear@0 1099 void LWOImporter::LoadLWO2Clip(unsigned int length)
nuclear@0 1100 {
nuclear@0 1101 AI_LWO_VALIDATE_CHUNK_LENGTH(length,CLIP,10);
nuclear@0 1102
nuclear@0 1103 mClips.push_back(LWO::Clip());
nuclear@0 1104 LWO::Clip& clip = mClips.back();
nuclear@0 1105
nuclear@0 1106 // first - get the index of the clip
nuclear@0 1107 clip.idx = GetU4();
nuclear@0 1108
nuclear@0 1109 IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
nuclear@0 1110 switch (head->type)
nuclear@0 1111 {
nuclear@0 1112 case AI_LWO_STIL:
nuclear@0 1113 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,STIL,1);
nuclear@0 1114
nuclear@0 1115 // "Normal" texture
nuclear@0 1116 GetS0(clip.path,head->length);
nuclear@0 1117 clip.type = Clip::STILL;
nuclear@0 1118 break;
nuclear@0 1119
nuclear@0 1120 case AI_LWO_ISEQ:
nuclear@0 1121 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ISEQ,16);
nuclear@0 1122 // Image sequence. We'll later take the first.
nuclear@0 1123 {
nuclear@0 1124 uint8_t digits = GetU1(); mFileBuffer++;
nuclear@0 1125 int16_t offset = GetU2(); mFileBuffer+=4;
nuclear@0 1126 int16_t start = GetU2(); mFileBuffer+=4;
nuclear@0 1127
nuclear@0 1128 std::string s;
nuclear@0 1129 std::ostringstream ss;
nuclear@0 1130 GetS0(s,head->length);
nuclear@0 1131
nuclear@0 1132 head->length -= (unsigned int)s.length()+1;
nuclear@0 1133 ss << s;
nuclear@0 1134 ss << std::setw(digits) << offset + start;
nuclear@0 1135 GetS0(s,head->length);
nuclear@0 1136 ss << s;
nuclear@0 1137 clip.path = ss.str();
nuclear@0 1138 clip.type = Clip::SEQ;
nuclear@0 1139 }
nuclear@0 1140 break;
nuclear@0 1141
nuclear@0 1142 case AI_LWO_STCC:
nuclear@0 1143 DefaultLogger::get()->warn("LWO2: Color shifted images are not supported");
nuclear@0 1144 break;
nuclear@0 1145
nuclear@0 1146 case AI_LWO_ANIM:
nuclear@0 1147 DefaultLogger::get()->warn("LWO2: Animated textures are not supported");
nuclear@0 1148 break;
nuclear@0 1149
nuclear@0 1150 case AI_LWO_XREF:
nuclear@0 1151 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,XREF,4);
nuclear@0 1152
nuclear@0 1153 // Just a cross-reference to another CLIp
nuclear@0 1154 clip.type = Clip::REF;
nuclear@0 1155 clip.clipRef = GetU4();
nuclear@0 1156 break;
nuclear@0 1157
nuclear@0 1158 case AI_LWO_NEGA:
nuclear@0 1159 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,NEGA,2);
nuclear@0 1160 clip.negate = (0 != GetU2());
nuclear@0 1161 break;
nuclear@0 1162
nuclear@0 1163 default:
nuclear@0 1164 DefaultLogger::get()->warn("LWO2: Encountered unknown CLIP subchunk");
nuclear@0 1165 }
nuclear@0 1166 }
nuclear@0 1167
nuclear@0 1168 // ------------------------------------------------------------------------------------------------
nuclear@0 1169 // Load envelope description
nuclear@0 1170 void LWOImporter::LoadLWO2Envelope(unsigned int length)
nuclear@0 1171 {
nuclear@0 1172 LE_NCONST uint8_t* const end = mFileBuffer + length;
nuclear@0 1173 AI_LWO_VALIDATE_CHUNK_LENGTH(length,ENVL,4);
nuclear@0 1174
nuclear@0 1175 mEnvelopes.push_back(LWO::Envelope());
nuclear@0 1176 LWO::Envelope& envelope = mEnvelopes.back();
nuclear@0 1177
nuclear@0 1178 // Get the index of the envelope
nuclear@0 1179 envelope.index = ReadVSizedIntLWO2(mFileBuffer);
nuclear@0 1180
nuclear@0 1181 // It looks like there might be an extra U4 right after the index,
nuclear@0 1182 // at least in modo (LXOB) files: we'll ignore it if it's zero,
nuclear@0 1183 // otherwise it represents the start of a subchunk, so we backtrack.
nuclear@0 1184 if (mIsLXOB)
nuclear@0 1185 {
nuclear@0 1186 uint32_t extra = GetU4();
nuclear@0 1187 if (extra)
nuclear@0 1188 {
nuclear@0 1189 mFileBuffer -= 4;
nuclear@0 1190 }
nuclear@0 1191 }
nuclear@0 1192
nuclear@0 1193 // ... and read all subchunks
nuclear@0 1194 while (true)
nuclear@0 1195 {
nuclear@0 1196 if (mFileBuffer + 6 >= end)break;
nuclear@0 1197 LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
nuclear@0 1198
nuclear@0 1199 if (mFileBuffer + head->length > end)
nuclear@0 1200 throw DeadlyImportError("LWO2: Invalid envelope chunk length");
nuclear@0 1201
nuclear@0 1202 uint8_t* const next = mFileBuffer+head->length;
nuclear@0 1203 switch (head->type)
nuclear@0 1204 {
nuclear@0 1205 // Type & representation of the envelope
nuclear@0 1206 case AI_LWO_TYPE:
nuclear@0 1207 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TYPE,2);
nuclear@0 1208 mFileBuffer++; // skip user format
nuclear@0 1209
nuclear@0 1210 // Determine type of envelope
nuclear@0 1211 envelope.type = (LWO::EnvelopeType)*mFileBuffer;
nuclear@0 1212 ++mFileBuffer;
nuclear@0 1213 break;
nuclear@0 1214
nuclear@0 1215 // precondition
nuclear@0 1216 case AI_LWO_PRE:
nuclear@0 1217 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,PRE,2);
nuclear@0 1218 envelope.pre = (LWO::PrePostBehaviour)GetU2();
nuclear@0 1219 break;
nuclear@0 1220
nuclear@0 1221 // postcondition
nuclear@0 1222 case AI_LWO_POST:
nuclear@0 1223 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,POST,2);
nuclear@0 1224 envelope.post = (LWO::PrePostBehaviour)GetU2();
nuclear@0 1225 break;
nuclear@0 1226
nuclear@0 1227 // keyframe
nuclear@0 1228 case AI_LWO_KEY:
nuclear@0 1229 {
nuclear@0 1230 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,KEY,8);
nuclear@0 1231
nuclear@0 1232 envelope.keys.push_back(LWO::Key());
nuclear@0 1233 LWO::Key& key = envelope.keys.back();
nuclear@0 1234
nuclear@0 1235 key.time = GetF4();
nuclear@0 1236 key.value = GetF4();
nuclear@0 1237 break;
nuclear@0 1238 }
nuclear@0 1239
nuclear@0 1240 // interval interpolation
nuclear@0 1241 case AI_LWO_SPAN:
nuclear@0 1242 {
nuclear@0 1243 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPAN,4);
nuclear@0 1244 if (envelope.keys.size()<2)
nuclear@0 1245 DefaultLogger::get()->warn("LWO2: Unexpected SPAN chunk");
nuclear@0 1246 else {
nuclear@0 1247 LWO::Key& key = envelope.keys.back();
nuclear@0 1248 switch (GetU4())
nuclear@0 1249 {
nuclear@0 1250 case AI_LWO_STEP:
nuclear@0 1251 key.inter = LWO::IT_STEP;break;
nuclear@0 1252 case AI_LWO_LINE:
nuclear@0 1253 key.inter = LWO::IT_LINE;break;
nuclear@0 1254 case AI_LWO_TCB:
nuclear@0 1255 key.inter = LWO::IT_TCB;break;
nuclear@0 1256 case AI_LWO_HERM:
nuclear@0 1257 key.inter = LWO::IT_HERM;break;
nuclear@0 1258 case AI_LWO_BEZI:
nuclear@0 1259 key.inter = LWO::IT_BEZI;break;
nuclear@0 1260 case AI_LWO_BEZ2:
nuclear@0 1261 key.inter = LWO::IT_BEZ2;break;
nuclear@0 1262 default:
nuclear@0 1263 DefaultLogger::get()->warn("LWO2: Unknown interval interpolation mode");
nuclear@0 1264 };
nuclear@0 1265
nuclear@0 1266 // todo ... read params
nuclear@0 1267 }
nuclear@0 1268 break;
nuclear@0 1269 }
nuclear@0 1270
nuclear@0 1271 default:
nuclear@0 1272 DefaultLogger::get()->warn("LWO2: Encountered unknown ENVL subchunk");
nuclear@0 1273 }
nuclear@0 1274 // regardless how much we did actually read, go to the next chunk
nuclear@0 1275 mFileBuffer = next;
nuclear@0 1276 }
nuclear@0 1277 }
nuclear@0 1278
nuclear@0 1279 // ------------------------------------------------------------------------------------------------
nuclear@0 1280 // Load file - master function
nuclear@0 1281 void LWOImporter::LoadLWO2File()
nuclear@0 1282 {
nuclear@0 1283 bool skip = false;
nuclear@0 1284
nuclear@0 1285 LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
nuclear@0 1286 while (true)
nuclear@0 1287 {
nuclear@0 1288 if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
nuclear@0 1289 IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
nuclear@0 1290
nuclear@0 1291 if (mFileBuffer + head->length > end)
nuclear@0 1292 {
nuclear@0 1293 throw DeadlyImportError("LWO2: Chunk length points behind the file");
nuclear@0 1294 break;
nuclear@0 1295 }
nuclear@0 1296 uint8_t* const next = mFileBuffer+head->length;
nuclear@0 1297 unsigned int iUnnamed = 0;
nuclear@0 1298
nuclear@0 1299 switch (head->type)
nuclear@0 1300 {
nuclear@0 1301 // new layer
nuclear@0 1302 case AI_LWO_LAYR:
nuclear@0 1303 {
nuclear@0 1304 // add a new layer to the list ....
nuclear@0 1305 mLayers->push_back ( LWO::Layer() );
nuclear@0 1306 LWO::Layer& layer = mLayers->back();
nuclear@0 1307 mCurLayer = &layer;
nuclear@0 1308
nuclear@0 1309 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
nuclear@0 1310
nuclear@0 1311 // layer index.
nuclear@0 1312 layer.mIndex = GetU2();
nuclear@0 1313
nuclear@0 1314 // Continue loading this layer or ignore it? Check the layer index property
nuclear@0 1315 if (UINT_MAX != configLayerIndex && (configLayerIndex-1) != layer.mIndex) {
nuclear@0 1316 skip = true;
nuclear@0 1317 }
nuclear@0 1318 else skip = false;
nuclear@0 1319
nuclear@0 1320 // pivot point
nuclear@0 1321 mFileBuffer += 2; /* unknown */
nuclear@0 1322 mCurLayer->mPivot.x = GetF4();
nuclear@0 1323 mCurLayer->mPivot.y = GetF4();
nuclear@0 1324 mCurLayer->mPivot.z = GetF4();
nuclear@0 1325 GetS0(layer.mName,head->length-16);
nuclear@0 1326
nuclear@0 1327 // if the name is empty, generate a default name
nuclear@0 1328 if (layer.mName.empty()) {
nuclear@0 1329 char buffer[128]; // should be sufficiently large
nuclear@0 1330 ::sprintf(buffer,"Layer_%i", iUnnamed++);
nuclear@0 1331 layer.mName = buffer;
nuclear@0 1332 }
nuclear@0 1333
nuclear@0 1334 // load this layer or ignore it? Check the layer name property
nuclear@0 1335 if (configLayerName.length() && configLayerName != layer.mName) {
nuclear@0 1336 skip = true;
nuclear@0 1337 }
nuclear@0 1338 else hasNamedLayer = true;
nuclear@0 1339
nuclear@0 1340 // optional: parent of this layer
nuclear@0 1341 if (mFileBuffer + 2 <= next)
nuclear@0 1342 layer.mParent = GetU2();
nuclear@0 1343 else layer.mParent = -1;
nuclear@0 1344
nuclear@0 1345 // Set layer skip parameter
nuclear@0 1346 layer.skip = skip;
nuclear@0 1347
nuclear@0 1348 break;
nuclear@0 1349 }
nuclear@0 1350
nuclear@0 1351 // vertex list
nuclear@0 1352 case AI_LWO_PNTS:
nuclear@0 1353 {
nuclear@0 1354 if (skip)
nuclear@0 1355 break;
nuclear@0 1356
nuclear@0 1357 unsigned int old = (unsigned int)mCurLayer->mTempPoints.size();
nuclear@0 1358 LoadLWOPoints(head->length);
nuclear@0 1359 mCurLayer->mPointIDXOfs = old;
nuclear@0 1360 break;
nuclear@0 1361 }
nuclear@0 1362 // vertex tags
nuclear@0 1363 case AI_LWO_VMAD:
nuclear@0 1364 if (mCurLayer->mFaces.empty())
nuclear@0 1365 {
nuclear@0 1366 DefaultLogger::get()->warn("LWO2: Unexpected VMAD chunk");
nuclear@0 1367 break;
nuclear@0 1368 }
nuclear@0 1369 // --- intentionally no break here
nuclear@0 1370 case AI_LWO_VMAP:
nuclear@0 1371 {
nuclear@0 1372 if (skip)
nuclear@0 1373 break;
nuclear@0 1374
nuclear@0 1375 if (mCurLayer->mTempPoints.empty())
nuclear@0 1376 DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk");
nuclear@0 1377 else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
nuclear@0 1378 break;
nuclear@0 1379 }
nuclear@0 1380 // face list
nuclear@0 1381 case AI_LWO_POLS:
nuclear@0 1382 {
nuclear@0 1383 if (skip)
nuclear@0 1384 break;
nuclear@0 1385
nuclear@0 1386 unsigned int old = (unsigned int)mCurLayer->mFaces.size();
nuclear@0 1387 LoadLWO2Polygons(head->length);
nuclear@0 1388 mCurLayer->mFaceIDXOfs = old;
nuclear@0 1389 break;
nuclear@0 1390 }
nuclear@0 1391 // polygon tags
nuclear@0 1392 case AI_LWO_PTAG:
nuclear@0 1393 {
nuclear@0 1394 if (skip)
nuclear@0 1395 break;
nuclear@0 1396
nuclear@0 1397 if (mCurLayer->mFaces.empty())
nuclear@0 1398 DefaultLogger::get()->warn("LWO2: Unexpected PTAG");
nuclear@0 1399 else LoadLWO2PolygonTags(head->length);
nuclear@0 1400 break;
nuclear@0 1401 }
nuclear@0 1402 // list of tags
nuclear@0 1403 case AI_LWO_TAGS:
nuclear@0 1404 {
nuclear@0 1405 if (!mTags->empty())
nuclear@0 1406 DefaultLogger::get()->warn("LWO2: SRFS chunk encountered twice");
nuclear@0 1407 else LoadLWOTags(head->length);
nuclear@0 1408 break;
nuclear@0 1409 }
nuclear@0 1410
nuclear@0 1411 // surface chunk
nuclear@0 1412 case AI_LWO_SURF:
nuclear@0 1413 {
nuclear@0 1414 LoadLWO2Surface(head->length);
nuclear@0 1415 break;
nuclear@0 1416 }
nuclear@0 1417
nuclear@0 1418 // clip chunk
nuclear@0 1419 case AI_LWO_CLIP:
nuclear@0 1420 {
nuclear@0 1421 LoadLWO2Clip(head->length);
nuclear@0 1422 break;
nuclear@0 1423 }
nuclear@0 1424
nuclear@0 1425 // envelope chunk
nuclear@0 1426 case AI_LWO_ENVL:
nuclear@0 1427 {
nuclear@0 1428 LoadLWO2Envelope(head->length);
nuclear@0 1429 break;
nuclear@0 1430 }
nuclear@0 1431 }
nuclear@0 1432 mFileBuffer = next;
nuclear@0 1433 }
nuclear@0 1434 }
nuclear@0 1435
nuclear@0 1436 #endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER