From a677cdd1c0f54058a4658f45f349cada32537fd2 Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Tue, 5 May 2009 14:32:01 +0000 Subject: [PATCH] LWO: Improving handling of VMAD chunks to process multiple discontinous UV's correctly. LWO: Error messages include VMAP/VMAD name now. LWO: Subdivision weight maps are read; but not yet evaluated. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@415 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/LWOFileData.h | 8 +++ code/LWOLoader.cpp | 143 ++++++++++++++++++++++++++------------------- 2 files changed, 91 insertions(+), 60 deletions(-) diff --git a/code/LWOFileData.h b/code/LWOFileData.h index f1d6fb3ec..abc0e1843 100644 --- a/code/LWOFileData.h +++ b/code/LWOFileData.h @@ -243,6 +243,11 @@ namespace LWO { #define AI_LWO_RGBA AI_IFF_FOURCC('R','G','B','A') #define AI_LWO_WGHT AI_IFF_FOURCC('W','G','H','T') +#define AI_LWO_MNVW AI_IFF_FOURCC('M','N','V','W') +#define AI_LWO_MORF AI_IFF_FOURCC('M','O','R','F') +#define AI_LWO_SPOT AI_IFF_FOURCC('S','P','O','T') +#define AI_LWO_PICK AI_IFF_FOURCC('P','I','C','K') + // MODO extension - per-vertex normal vectors #define AI_LWO_MODO_NORM AI_IFF_FOURCC('N', 'O', 'R', 'M') @@ -646,6 +651,9 @@ struct Layer /** Weight channel list from the file */ WeightChannelList mWeightChannels; + /** Subdivision weight channel list from the file */ + WeightChannelList mSWeightChannels; + /** Vertex color list from the file */ VColorChannelList mVColorChannels; diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index f899b080c..8150d92d2 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -344,11 +344,13 @@ void LWOImporter::InternReadFile( const std::string& pFile, } #if 0 - // process vertex weights - not yet supported + // process vertex weights. We can't properly reconstruct the whole skeleton for now, + // but we can create dummy bones for all weight channels which we have. for (unsigned int w = 0; w < layer.mWeightChannels.size();++w) { } #endif + face.mIndices[q] = vert; } pf->mIndices = face.mIndices; @@ -607,14 +609,14 @@ void LWOImporter::ResolveTags() { // --- this function is used for both LWO2 and LWOB mMapping->resize(mTags->size(),0xffffffff); - for (unsigned int a = 0; a < mTags->size();++a) - { + for (unsigned int a = 0; a < mTags->size();++a) { + const std::string& c = (*mTags)[a]; - for (unsigned int i = 0; i < mSurfaces->size();++i) - { + for (unsigned int i = 0; i < mSurfaces->size();++i) { + const std::string& d = (*mSurfaces)[i].mName; - if (!ASSIMP_stricmp(c,d)) - { + if (!ASSIMP_stricmp(c,d)) { + (*mMapping)[a] = i; break; } @@ -625,24 +627,23 @@ void LWOImporter::ResolveTags() // ------------------------------------------------------------------------------------------------ void LWOImporter::ResolveClips() { - for( unsigned int i = 0; i < mClips.size();++i) - { + for( unsigned int i = 0; i < mClips.size();++i) { + Clip& clip = mClips[i]; - if (Clip::REF == clip.type) - { - if (clip.clipRef >= mClips.size()) - { + if (Clip::REF == clip.type) { + + if (clip.clipRef >= mClips.size()) { DefaultLogger::get()->error("LWO2: Clip referrer index is out of range"); clip.clipRef = 0; } + Clip& dest = mClips[clip.clipRef]; - if (Clip::REF == dest.type) - { + if (Clip::REF == dest.type) { DefaultLogger::get()->error("LWO2: Clip references another clip reference"); clip.type = Clip::UNSUPPORTED; } - else - { + + else { clip.path = dest.path; clip.type = dest.type; } @@ -654,17 +655,16 @@ void LWOImporter::ResolveClips() void LWOImporter::AdjustTexturePath(std::string& out) { // --- this function is used for both LWO2 and LWOB - if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)")) - { + if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)")) { + // remove the (sequence) and append 000 DefaultLogger::get()->info("LWOB: Sequence of animated texture found. It will be ignored"); out = out.substr(0,out.length()-10) + "000"; } - // format: drive:path/file - we need to insert a slash after the drive + // format: drive:path/file - we just need to insert a slash after the drive std::string::size_type n = out.find_first_of(':'); - if (std::string::npos != n) - { + if (std::string::npos != n) { out.insert(n+1,"/"); } } @@ -744,7 +744,7 @@ void LWOImporter::LoadLWO2Polygons(unsigned int length) default: // hm!? wtf is this? ok ... - DefaultLogger::get()->error("LWO2: Encountered unknown polygon type"); + DefaultLogger::get()->error("LWO2: Ignoring unknown polygon type."); break; } @@ -785,23 +785,22 @@ void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator& it, uint16_t*& cursor, const uint16_t* const end) { - while (cursor < end) - { - LWO::Face& face = *it;++it; - if((face.mNumIndices = (*cursor++) & 0x03FF)) // swapping has already been done - { + while (cursor < end) { + + LWO::Face& face = *it++;; + if((face.mNumIndices = (*cursor++) & 0x03FF)) /* byte swapping has already been done */ { face.mIndices = new unsigned int[face.mNumIndices]; for(unsigned int i = 0; i < face.mNumIndices; i++) { face.mIndices[i] = ReadVSizedIntLWO2((uint8_t*&)cursor) + mCurLayer->mPointIDXOfs; if(face.mIndices[i] > mCurLayer->mTempPoints.size()) { - DefaultLogger::get()->warn("LWO2: face index is out of range"); + DefaultLogger::get()->warn("LWO2: Failure evaluating face record, index is out of range"); face.mIndices[i] = (unsigned int)mCurLayer->mTempPoints.size()-1; } } } - else throw new ImportErrorException("LWO2: face has 0 indices"); + else throw new ImportErrorException("LWO2: Encountered invalid face record with zero indices"); } } @@ -817,23 +816,22 @@ void LWOImporter::LoadLWO2PolygonTags(unsigned int length) if (type != AI_LWO_SURF && type != AI_LWO_SMGP) return; - while (mFileBuffer < end) - { + while (mFileBuffer < end) { + unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs; unsigned int j = GetU2(); - if (i >= mCurLayer->mFaces.size()) - { + if (i >= mCurLayer->mFaces.size()) { DefaultLogger::get()->warn("LWO2: face index in PTAG is out of range"); continue; } - switch (type) - { + switch (type) { + case AI_LWO_SURF: mCurLayer->mFaces[i].surfaceIndex = j; break; - case AI_LWO_SMGP: + case AI_LWO_SMGP: /* is that really used? */ mCurLayer->mFaces[i].smoothGroup = j; break; }; @@ -845,10 +843,8 @@ template VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPoly) { for (typename std::vector< T >::iterator it = list.begin(), end = list.end();it != end; ++it) { - if ((*it).name == name) - { - if (!perPoly) - { + if ((*it).name == name) { + if (!perPoly) { DefaultLogger::get()->warn("LWO2: Found two VMAP sections with equal names"); } return &(*it); @@ -864,7 +860,8 @@ VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPol template inline void CreateNewEntry(T& chan, unsigned int srcIdx) { - if (!chan.name.length())return; + if (!chan.name.length()) + return; chan.abAssigned[srcIdx] = true; chan.abAssigned.resize(chan.abAssigned.size()+1,false); @@ -891,11 +888,13 @@ inline void LWOImporter::DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int unsigned int i; base->abAssigned[idx] = true; - for (i = 0; i < numRead;++i) + for (i = 0; i < numRead;++i) { base->rawData[idx*base->dims+i]= data[i]; + } - if (0xffffffff != (i = refList[idx])) + if (0xffffffff != (i = refList[idx])) { DoRecursiveVMAPAssignment(base,numRead,i,data); + } } // ------------------------------------------------------------------------------------------------ @@ -928,29 +927,33 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) { case AI_LWO_TXUV: if (dims != 2) { - DefaultLogger::get()->warn("LWO2: Found UV channel with != 2 components"); + DefaultLogger::get()->warn("LWO2: Skipping UV channel \'" + + name + "\' with !2 components"); return; } base = FindEntry(mCurLayer->mUVChannels,name,perPoly); break; case AI_LWO_WGHT: + case AI_LWO_MNVW: if (dims != 1) { - DefaultLogger::get()->warn("LWO2: found vertex weight map with != 1 components"); + DefaultLogger::get()->warn("LWO2: Skipping Weight Channel \'" + + name + "\' with !1 components"); return; } - base = FindEntry(mCurLayer->mWeightChannels,name,perPoly); + base = FindEntry((type == AI_LWO_WGHT ? mCurLayer->mWeightChannels + : mCurLayer->mSWeightChannels),name,perPoly); break; case AI_LWO_RGB: case AI_LWO_RGBA: if (dims != 3 && dims != 4) { - DefaultLogger::get()->warn("LWO2: found vertex color map with != 3&4 components"); + DefaultLogger::get()->warn("LWO2: Skipping Color Map \'" + + name + "\' with a dimension > 4 or < 3"); return; } base = FindEntry(mCurLayer->mVColorChannels,name,perPoly); break; case AI_LWO_MODO_NORM: - /* This is a non-standard extension chunk used by Luxology's MODO. * It stores per-vertex normals. This VMAP exists just once, has * 3 dimensions and is btw extremely beautiful. @@ -958,20 +961,26 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) if (name != "vert_normals" || dims != 3 || mCurLayer->mNormals.name.length()) return; - DefaultLogger::get()->info("Non-standard extension: MODO VMAP.NORM.vert_normals"); + DefaultLogger::get()->info("Processing non-standard extension: MODO VMAP.NORM.vert_normals"); mCurLayer->mNormals.name = name; base = & mCurLayer->mNormals; break; + case AI_LWO_PICK: /* these VMAPs are just silently dropped */ + case AI_LWO_MORF: + case AI_LWO_SPOT: + return; + default: + DefaultLogger::get()->warn("LWO2: Skipping unknown VMAP/VMAD channel \'" + name + "\'"); return; }; base->Allocate((unsigned int)mCurLayer->mTempPoints.size()); // now read all entries in the map type = std::min(dims,base->dims); - const unsigned int diff = (dims - type)<<2; + const unsigned int diff = (dims - type)<<2u; LWO::FaceList& list = mCurLayer->mFaces; LWO::PointList& pointList = mCurLayer->mTempPoints; @@ -982,12 +991,13 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) const unsigned int numPoints = (unsigned int)pointList.size(); const unsigned int numFaces = (unsigned int)list.size(); - while (mFileBuffer < end) - { + while (mFileBuffer < end) { + unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs; if (idx >= numPoints) { - DefaultLogger::get()->warn("LWO2: vertex index in vmap/vmad is out of range"); - mFileBuffer += base->dims*4;continue; + DefaultLogger::get()->warn("LWO2: Failure evaluating VMAP/VMAD entry \'" + name + "\', vertex index is out of range"); + mFileBuffer += base->dims<<2u; + continue; } if (perPoly) { unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs; @@ -995,8 +1005,8 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) // we have already a VMAP entry for this vertex - thus // we need to duplicate the corresponding polygon. if (polyIdx >= numFaces) { - DefaultLogger::get()->warn("LWO2: VMAD polygon index is out of range"); - mFileBuffer += base->dims*4; + DefaultLogger::get()->warn("LWO2: Failure evaluating VMAD entry \'" + name + "\', polygon index is out of range"); + mFileBuffer += base->dims<<2u; continue; } @@ -1004,11 +1014,19 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) // generate a new unique vertex for the corresponding index - but only // if we can find the index in the face + bool had = false; for (unsigned int i = 0; i < src.mNumIndices;++i) { - register unsigned int srcIdx = src.mIndices[i]; - if (idx != srcIdx) + + unsigned int srcIdx = src.mIndices[i], tmp = idx; + do { + if (tmp == srcIdx) + break; + } + while ((tmp = refList[tmp]) != 0xffffffff); + if (tmp == 0xffffffff) continue; + had = true; refList.resize(refList.size()+1, 0xffffffff); idx = (unsigned int)pointList.size(); @@ -1023,7 +1041,12 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) CreateNewEntry(mCurLayer->mVColorChannels, srcIdx ); CreateNewEntry(mCurLayer->mUVChannels, srcIdx ); CreateNewEntry(mCurLayer->mWeightChannels, srcIdx ); - CreateNewEntry(mCurLayer->mNormals, srcIdx ); + CreateNewEntry(mCurLayer->mSWeightChannels, srcIdx ); + CreateNewEntry(mCurLayer->mNormals, srcIdx ); + } + if (!had) { + DefaultLogger::get()->warn("LWO2: Failure evaluating VMAD entry \'" + name + "\', vertex index wasn't found in that polygon"); + ai_assert(had); } } }