diff --git a/code/LWOFileData.h b/code/LWOFileData.h index f13e32f86..f1d6fb3ec 100644 --- a/code/LWOFileData.h +++ b/code/LWOFileData.h @@ -308,9 +308,10 @@ struct VMapEntry //! allocates memory for the vertex map virtual void Allocate(unsigned int num) { - if (!rawData.empty())return; // return if already allocated + if (!rawData.empty()) + return; // return if already allocated - register unsigned int m = num*dims; + const unsigned int m = num*dims; rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs rawData.resize(m,0.f); abAssigned.resize(num,false); @@ -318,8 +319,8 @@ struct VMapEntry std::string name; unsigned int dims; - std::vector rawData; + std::vector rawData; std::vector abAssigned; }; @@ -336,14 +337,15 @@ struct VColorChannel : public VMapEntry //! be initialized to 1.0 by default virtual void Allocate(unsigned int num) { - if (!rawData.empty())return; // return if already allocated + if (!rawData.empty()) + return; // return if already allocated register unsigned int m = num*dims; rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs rawData.resize(m); for (aiColor4D* p = (aiColor4D*)&rawData[0]; p < (aiColor4D*)&rawData[m-1]; ++p) - *p = aiColor4D(); + p->a = 1.f; abAssigned.resize(num,false); } @@ -618,6 +620,7 @@ typedef std::vector < VColorChannel > VColorChannelList; typedef std::vector < UVChannel > UVChannelList; typedef std::vector < Clip > ClipList; typedef std::vector < Envelope > EnvelopeList; +typedef std::vector < unsigned int > SortedRep; // --------------------------------------------------------------------------- /** \brief Represents a layer in the file diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index cc16bca3d..f899b080c 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -208,7 +208,6 @@ void LWOImporter::InternReadFile( const std::string& pFile, if (!layer.mFaces.empty() && !layer.mTempPoints.empty()) { // now sort all faces by the surfaces assigned to them - typedef std::vector SortedRep; std::vector pSorted(mSurfaces->size()+1); unsigned int i = 0; @@ -271,8 +270,8 @@ void LWOImporter::InternReadFile( const std::string& pFile, vVColorIndices[mui] = 0xffffffff; #endif - FindUVChannels(_mSurfaces[i],layer,vUVChannelIndices); - FindVCChannels(_mSurfaces[i],layer,vVColorIndices); + FindUVChannels(_mSurfaces[i],sorted,layer,vUVChannelIndices); + FindVCChannels(_mSurfaces[i],sorted,layer,vVColorIndices); // allocate storage for UV and CV channels aiVector3D* pvUV[AI_MAX_NUMBER_OF_TEXTURECOORDS]; diff --git a/code/LWOLoader.h b/code/LWOLoader.h index e88013ace..3c889c74c 100644 --- a/code/LWOLoader.h +++ b/code/LWOLoader.h @@ -289,15 +289,17 @@ private: * UV/VC channel lists of the layer */ void FindUVChannels(/*const*/ LWO::Surface& surf, + LWO::SortedRep& sorted, /*const*/ LWO::Layer& layer, unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]); // ------------------------------------------------------------------- - void FindUVChannels(LWO::TextureList& list, LWO::Layer& layer, - unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS], unsigned int& next); + char FindUVChannels(LWO::TextureList& list, + LWO::Layer& layer,LWO::UVChannel& uv, unsigned int next); // ------------------------------------------------------------------- void FindVCChannels(const LWO::Surface& surf, + LWO::SortedRep& sorted, const LWO::Layer& layer, unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]); diff --git a/code/LWOMaterial.cpp b/code/LWOMaterial.cpp index ab8dcadca..f025ad6a7 100644 --- a/code/LWOMaterial.cpp +++ b/code/LWOMaterial.cpp @@ -285,9 +285,12 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat } else { - if (16.0f >= surf.mGlossiness)fGloss = 6.0f; - else if (64.0f >= surf.mGlossiness)fGloss = 20.0f; - else if (256.0f >= surf.mGlossiness)fGloss = 50.0f; + if (16.0f >= surf.mGlossiness) + fGloss = 6.0f; + else if (64.0f >= surf.mGlossiness) + fGloss = 20.0f; + else if (256.0f >= surf.mGlossiness) + fGloss = 50.0f; else fGloss = 80.0f; } @@ -303,20 +306,19 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH); // emissive color - // (luminosity is not really the same but it affects the surface in - // a similar way. However, some scalings seems to be necessary) + // luminosity is not really the same but it affects the surface in a similar way. Some scaling looks good. clr.g = clr.b = clr.r = surf.mLuminosity*0.8f; pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE); // opacity ... either additive or default-blended, please - if (0.f != surf.mAdditiveTransparency) - { + if (0.f != surf.mAdditiveTransparency) { + const int add = aiBlendMode_Additive; pcMat->AddProperty(&surf.mAdditiveTransparency,1,AI_MATKEY_OPACITY); pcMat->AddProperty(&add,1,AI_MATKEY_BLEND_FUNC); } - else if (10e10f != surf.mTransparency) - { + + else if (10e10f != surf.mTransparency) { const int def = aiBlendMode_Default; const float f = 1.0f-surf.mTransparency; pcMat->AddProperty(&f,1,AI_MATKEY_OPACITY); @@ -334,23 +336,19 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat HandleTextures(pcMat,surf.mOpacityTextures,aiTextureType_OPACITY); HandleTextures(pcMat,surf.mReflectionTextures,aiTextureType_REFLECTION); - // Now we need to know which shader we must use - // iterate through the shader list of the surface and - // search for a name which we know ... - for (ShaderList::const_iterator it = surf.mShaders.begin(), end = surf.mShaders.end(); - it != end;++it) - { + // Now we need to know which shader to use .. iterate through the shader list of + // the surface and search for a name which we know ... + for (ShaderList::const_iterator it = surf.mShaders.begin(), end = surf.mShaders.end();it != end;++it) { //if (!(*it).enabled)continue; + if ((*it).functionName == "LW_SuperCelShader" || (*it).functionName == "AH_CelShader") { - DefaultLogger::get()->info("LWO2: Mapping LW_SuperCelShader/AH_CelShader " - "to aiShadingMode_Toon"); + DefaultLogger::get()->info("LWO2: Mapping LW_SuperCelShader/AH_CelShader to aiShadingMode_Toon"); m = aiShadingMode_Toon; break; } else if ((*it).functionName == "LW_RealFresnel" || (*it).functionName == "LW_FastFresnel") { - DefaultLogger::get()->info("LWO2: Mapping LW_RealFresnel/LW_FastFresnel " - "to aiShadingMode_Fresnel"); + DefaultLogger::get()->info("LWO2: Mapping LW_RealFresnel/LW_FastFresnel to aiShadingMode_Fresnel"); m = aiShadingMode_Fresnel; break; @@ -374,74 +372,148 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat } // ------------------------------------------------------------------------------------------------ -void LWOImporter::FindUVChannels(LWO::TextureList& list, LWO::Layer& layer, - unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS], - unsigned int& next) +char LWOImporter::FindUVChannels(LWO::TextureList& list, + LWO::Layer& layer,LWO::UVChannel& uv, unsigned int next) { + char ret = 0; for (TextureList::iterator it = list.begin(), end = list.end();it != end;++it) { // Ignore textures with non-UV mappings for the moment. if (!(*it).enabled || !(*it).bCanUse || (*it).mapMode != LWO::Texture::UV) { continue; } - for (unsigned int i = 0; i < layer.mUVChannels.size();++i) { + + if ((*it).mUVChannelIndex == uv.name) { + ret = 1; + + // got it. + if ((*it).mRealUVIndex == 0xffffffff || (*it).mRealUVIndex == next) + { + (*it).mRealUVIndex = next; + } + else { + // channel mismatch. need to duplicate the material. + DefaultLogger::get()->warn("LWO: Channel mismatch, would need to duplicate surface [design bug]"); - bool found = false; - if ((*it).mUVChannelIndex == layer.mUVChannels[i].name) { - // check whether we have this channel already - for (unsigned int m = 0; m < next;++m) { + // TODO + } + } + } + return ret; +} + +// ------------------------------------------------------------------------------------------------ +void LWOImporter::FindUVChannels(LWO::Surface& surf, + LWO::SortedRep& sorted,LWO::Layer& layer, + unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]) +{ + unsigned int next = 0, extra = 0, num_extra = 0; + + // Check whether we have an UV entry != 0 for one of the faces in 'sorted' + for (unsigned int i = 0; i < layer.mUVChannels.size();++i) { + LWO::UVChannel& uv = layer.mUVChannels[i]; + + for (LWO::SortedRep::const_iterator it = sorted.begin(); it != sorted.end(); ++it) { + + LWO::Face& face = layer.mFaces[*it]; + + for (unsigned int n = 0; n < face.mNumIndices; ++n) { + unsigned int idx = face.mIndices[n]; + + if (uv.abAssigned[idx] && ((aiVector2D*)&uv.rawData[0])[idx] != aiVector2D()) { + + if (next >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { + + DefaultLogger::get()->error("LWO: Maximum number of UV channels for " + "this mesh reached. Skipping channel \'" + uv.name + "\'"); - if (i == out[m]) { - (*it).mRealUVIndex = m; - found = true; - break; } - } + else { + // Search through all textures assigned to 'surf' and look for this UV channel + char had = 0; + had |= FindUVChannels(surf.mColorTextures,layer,uv,next); + had |= FindUVChannels(surf.mDiffuseTextures,layer,uv,next); + had |= FindUVChannels(surf.mSpecularTextures,layer,uv,next); + had |= FindUVChannels(surf.mGlossinessTextures,layer,uv,next); + had |= FindUVChannels(surf.mOpacityTextures,layer,uv,next); + had |= FindUVChannels(surf.mBumpTextures,layer,uv,next); + had |= FindUVChannels(surf.mReflectionTextures,layer,uv,next); - if (!found) { - (*it).mRealUVIndex = next; - out[next++] = i; - if (AI_MAX_NUMBER_OF_TEXTURECOORDS != next) - out[next] = 0xffffffff; + if (had != 0) { + + // We have a texture referencing this UV channel so we have to take special care of it + if (num_extra) { + + for (unsigned int a = next; a < std::min( extra, AI_MAX_NUMBER_OF_TEXTURECOORDS-1u ); ++a) { + out[a+1] = out[a]; + } + } + ++extra; + out[next++] = i; + } + else { + + // Bäh ... seems not to be used at all. Push to end if enough space is available. + out[extra++] = i; + ++num_extra; + } + } + it = sorted.end()-1; break; } } } - if (0xffffffff == (*it).mRealUVIndex) - DefaultLogger::get()->error("LWO2: Unable to find matching UV channel for texture"); + } + if (next != AI_MAX_NUMBER_OF_TEXTURECOORDS) { + out[extra] = 0xffffffff; } } // ------------------------------------------------------------------------------------------------ -void LWOImporter::FindUVChannels(LWO::Surface& surf, LWO::Layer& layer, - unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]) -{ - out[0] = 0xffffffff; - unsigned int next = 0; - - FindUVChannels(surf.mColorTextures,layer,out,next); - FindUVChannels(surf.mDiffuseTextures,layer,out,next); - FindUVChannels(surf.mSpecularTextures,layer,out,next); - FindUVChannels(surf.mGlossinessTextures,layer,out,next); - FindUVChannels(surf.mOpacityTextures,layer,out,next); - FindUVChannels(surf.mBumpTextures,layer,out,next); - FindUVChannels(surf.mReflectionTextures,layer,out,next); -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::FindVCChannels(const LWO::Surface& surf, const LWO::Layer& layer, +void LWOImporter::FindVCChannels(const LWO::Surface& surf, LWO::SortedRep& sorted, const LWO::Layer& layer, unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]) { - out[0] = 0xffffffff; - if (surf.mVCMap.length()) { - for (unsigned int i = 0; i < layer.mVColorChannels.size();++i) { - if (surf.mVCMap == layer.mVColorChannels[i].name) { - out[0] = i; - out[1] = 0xffffffff; - return; + unsigned int next = 0; + + // Check whether we have an vc entry != 0 for one of the faces in 'sorted' + for (unsigned int i = 0; i < layer.mVColorChannels.size();++i) { + const LWO::VColorChannel& vc = layer.mVColorChannels[i]; + + if (surf.mVCMap == vc.name) { + // The vertex color map is explicitely requested by the surface so we need to take special care of it + for (unsigned int a = 0; a < std::min(next,AI_MAX_NUMBER_OF_COLOR_SETS-1u); ++a) { + out[a+1] = out[a]; + } + out[0] = i; + ++next; + } + else { + + for (LWO::SortedRep::iterator it = sorted.begin(); it != sorted.end(); ++it) { + const LWO::Face& face = layer.mFaces[*it]; + + for (unsigned int n = 0; n < face.mNumIndices; ++n) { + unsigned int idx = face.mIndices[n]; + + if (vc.abAssigned[idx] && ((aiColor4D*)&vc.rawData[0])[idx] != aiColor4D(0.f,0.f,0.f,1.f)) { + if (next >= AI_MAX_NUMBER_OF_COLOR_SETS) { + + DefaultLogger::get()->error("LWO: Maximum number of vertex color channels for " + "this mesh reached. Skipping channel \'" + vc.name + "\'"); + + } + else { + out[next++] = i; + } + it = sorted.end()-1; + break; + } + } } } - DefaultLogger::get()->warn("LWO2: Unable to find vertex color channel: " + surf.mVCMap); + } + if (next != AI_MAX_NUMBER_OF_COLOR_SETS) { + out[next] = 0xffffffff; } } diff --git a/mkutil/revision.h b/mkutil/revision.h index 3152519a3..c019ccfc1 100644 --- a/mkutil/revision.h +++ b/mkutil/revision.h @@ -1 +1 @@ -#define SVNRevision 387 +#define SVNRevision 394 diff --git a/test/models/LWO/LWO2/box_2uv_1unused.lwo b/test/models/LWO/LWO2/box_2uv_1unused.lwo new file mode 100644 index 000000000..49bf9ad0b Binary files /dev/null and b/test/models/LWO/LWO2/box_2uv_1unused.lwo differ diff --git a/test/models/LWO/LWO2/box_2vc_1unused.lwo b/test/models/LWO/LWO2/box_2vc_1unused.lwo new file mode 100644 index 000000000..97ec3c9b4 Binary files /dev/null and b/test/models/LWO/LWO2/box_2vc_1unused.lwo differ diff --git a/test/models/LWO/LWO2/white.bmp b/test/models/LWO/LWO2/white.bmp new file mode 100644 index 000000000..021d5fa92 Binary files /dev/null and b/test/models/LWO/LWO2/white.bmp differ diff --git a/tools/assimp_cmd/WriteDumb.cpp b/tools/assimp_cmd/WriteDumb.cpp index 78b674efd..5e5a677c7 100644 --- a/tools/assimp_cmd/WriteDumb.cpp +++ b/tools/assimp_cmd/WriteDumb.cpp @@ -890,7 +890,7 @@ void WriteDump(const aiScene* scene, FILE* out, const char* src, const char* cmd if (!mesh->mTextureCoords[a]) break; - ::fprintf(out,"\t\t \n",mesh->mNumUVComponents[a]); + ::fprintf(out,"\t\t \n",a,mesh->mNumUVComponents[a]); if (!shortened) { for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { ::fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", @@ -908,7 +908,7 @@ void WriteDump(const aiScene* scene, FILE* out, const char* src, const char* cmd for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { if (!mesh->mColors[a]) break; - ::fprintf(out,"\t\t \n"); + //::fprintf(out,"\t\t \n",a); if (!shortened) { for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { ::fprintf(out,"\t\t%0 8f %0 8f %0 8f %0 8f\n",