diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index d08dc3dce..9f2b70b7f 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -23,7 +23,7 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT @@ -766,6 +766,7 @@ private: // find user defined properties (3ds Max) data->Set(index++, "UserProperties", aiString(PropertyGet(props, "UDP3DSMAX", ""))); + unparsedProperties.erase("UDP3DSMAX"); // preserve the info that a node was marked as Null node in the original file. data->Set(index++, "IsNull", model.IsNull() ? true : false); @@ -1439,6 +1440,7 @@ private: // texture assignments SetTextureProperties(out_mat,material.Textures()); + SetTextureProperties(out_mat,material.LayeredTextures()); return static_cast(materials.size() - 1); } @@ -1538,6 +1540,99 @@ private: out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0); } + // ------------------------------------------------------------------------------------------------ + void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, + const std::string& propName, + aiTextureType target) + { + LayeredTextureMap::const_iterator it = layeredTextures.find(propName); + if(it == layeredTextures.end()) { + return; + } + + const Texture* const tex = (*it).second->getTexture(); + + aiString path; + path.Set(tex->RelativeFilename()); + + out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0); + + aiUVTransform uvTrafo; + // XXX handle all kinds of UV transformations + uvTrafo.mScaling = tex->UVScaling(); + uvTrafo.mTranslation = tex->UVTranslation(); + out_mat->AddProperty(&uvTrafo,1,_AI_MATKEY_UVTRANSFORM_BASE,target,0); + + const PropertyTable& props = tex->Props(); + + int uvIndex = 0; + + bool ok; + const std::string& uvSet = PropertyGet(props,"UVSet",ok); + if(ok) { + // "default" is the name which usually appears in the FbxFileTexture template + if(uvSet != "default" && uvSet.length()) { + // this is a bit awkward - we need to find a mesh that uses this + // material and scan its UV channels for the given UV name because + // assimp references UV channels by index, not by name. + + // XXX: the case that UV channels may appear in different orders + // in meshes is unhandled. A possible solution would be to sort + // the UV channels alphabetically, but this would have the side + // effect that the primary (first) UV channel would sometimes + // be moved, causing trouble when users read only the first + // UV channel and ignore UV channel assignments altogether. + + const unsigned int matIndex = static_cast(std::distance(materials.begin(), + std::find(materials.begin(),materials.end(),out_mat) + )); + + uvIndex = -1; + BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) { + const MeshGeometry* const mesh = dynamic_cast (v.first); + if(!mesh) { + continue; + } + + const MatIndexArray& mats = mesh->GetMaterialIndices(); + if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { + continue; + } + + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if(mesh->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = mesh->GetTextureCoordChannelName(i); + if(name == uvSet) { + index = static_cast(i); + break; + } + } + if(index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + continue; + } + + if(uvIndex == -1) { + uvIndex = index; + } + else { + FBXImporter::LogWarn("the UV channel named " + uvSet + + " appears at different positions in meshes, results will be wrong"); + } + } + + if(uvIndex == -1) { + FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); + uvIndex = 0; + } + } + } + + out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0); + } // ------------------------------------------------------------------------------------------------ void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures) @@ -1554,6 +1649,20 @@ private: TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS); } + // ------------------------------------------------------------------------------------------------ + void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures) + { + TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE); + TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT); + TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE); + TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR); + TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY); + TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION); + TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT); + TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS); + TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT); + TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS); + } // ------------------------------------------------------------------------------------------------ diff --git a/code/FBXDocument.cpp b/code/FBXDocument.cpp index cff52e542..404a8d6e2 100644 --- a/code/FBXDocument.cpp +++ b/code/FBXDocument.cpp @@ -14,7 +14,7 @@ following conditions are met: following disclaimer. * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the + copyright notice, this list of conditions and the* following disclaimer in the documentation and/or other materials provided with the distribution. @@ -176,6 +176,9 @@ const Object* LazyObject::Get(bool dieOnError) else if (!strncmp(obtype,"Texture",length)) { object.reset(new Texture(id,element,doc,name)); } + else if (!strncmp(obtype,"LayeredTexture",length)) { + object.reset(new LayeredTexture(id,element,doc,name)); + } else if (!strncmp(obtype,"AnimationStack",length)) { object.reset(new AnimationStack(id,element,name,doc)); } diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 9b7d5e3ec..9dd5c79dd 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -516,8 +516,6 @@ private: boost::shared_ptr props; }; - - /** DOM class for generic FBX textures */ class Texture : public Object { @@ -576,8 +574,73 @@ private: unsigned int crop[4]; }; +/** DOM class for layered FBX textures */ +class LayeredTexture : public Object +{ +public: + + LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name); + ~LayeredTexture(); + + //Can only be called after construction of the layered texture object due to construction flag. + void fillTexture(const Document& doc); + + enum BlendMode + { + BlendMode_Translucent, + BlendMode_Additive, + BlendMode_Modulate, + BlendMode_Modulate2, + BlendMode_Over, + BlendMode_Normal, + BlendMode_Dissolve, + BlendMode_Darken, + BlendMode_ColorBurn, + BlendMode_LinearBurn, + BlendMode_DarkerColor, + BlendMode_Lighten, + BlendMode_Screen, + BlendMode_ColorDodge, + BlendMode_LinearDodge, + BlendMode_LighterColor, + BlendMode_SoftLight, + BlendMode_HardLight, + BlendMode_VividLight, + BlendMode_LinearLight, + BlendMode_PinLight, + BlendMode_HardMix, + BlendMode_Difference, + BlendMode_Exclusion, + BlendMode_Subtract, + BlendMode_Divide, + BlendMode_Hue, + BlendMode_Saturation, + BlendMode_Color, + BlendMode_Luminosity, + BlendMode_Overlay, + BlendMode_BlendModeCount + }; + + const Texture* getTexture() const + { + return texture; + } + BlendMode GetBlendMode() + { + return blendMode; + } + float Alpha() + { + return alpha; + } +private: + const Texture* texture; + BlendMode blendMode; + float alpha; +}; typedef std::fbx_unordered_map TextureMap; +typedef std::fbx_unordered_map LayeredTextureMap; /** DOM class for generic FBX materials */ @@ -607,6 +670,10 @@ public: return textures; } + const LayeredTextureMap& LayeredTextures() const { + return layeredTextures; + } + private: std::string shading; @@ -614,6 +681,7 @@ private: boost::shared_ptr props; TextureMap textures; + LayeredTextureMap layeredTextures; }; diff --git a/code/FBXMaterial.cpp b/code/FBXMaterial.cpp index 1a5d7d443..a5e2a1169 100644 --- a/code/FBXMaterial.cpp +++ b/code/FBXMaterial.cpp @@ -110,16 +110,29 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con const Texture* const tex = dynamic_cast(ob); if(!tex) { - DOMWarning("source object for texture link is not a texture, ignoring",&element); - continue; + const LayeredTexture* const layeredTexture = dynamic_cast(ob); + if(!layeredTexture) { + DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element); + continue; + } + const std::string& prop = con->PropertyName(); + if (layeredTextures.find(prop) != layeredTextures.end()) { + DOMWarning("duplicate layered texture link: " + prop,&element); + } + + layeredTextures[prop] = layeredTexture; + ((LayeredTexture*)layeredTexture)->fillTexture(doc); + } + else + { + const std::string& prop = con->PropertyName(); + if (textures.find(prop) != textures.end()) { + DOMWarning("duplicate texture link: " + prop,&element); + } + + textures[prop] = tex; } - const std::string& prop = con->PropertyName(); - if (textures.find(prop) != textures.end()) { - DOMWarning("duplicate texture link: " + prop,&element); - } - - textures[prop] = tex; } } @@ -194,6 +207,52 @@ Texture::~Texture() } +LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name) +: Object(id,element,name) +,texture(0) +,blendMode(BlendMode_Modulate) +,alpha(1) +{ + const Scope& sc = GetRequiredScope(element); + + const Element* const BlendModes = sc["BlendModes"]; + const Element* const Alphas = sc["Alphas"]; + + + if(BlendModes!=0) + { + blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0)); + } + if(Alphas!=0) + { + alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0)); + } +} + +LayeredTexture::~LayeredTexture() +{ + +} + +void LayeredTexture::fillTexture(const Document& doc) +{ + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); + for(size_t i = 0; i < conns.size();++i) + { + const Connection* con = conns.at(i); + + const Object* const ob = con->SourceObject(); + if(!ob) { + DOMWarning("failed to read source object for texture link, ignoring",&element); + continue; + } + + const Texture* const tex = dynamic_cast(ob); + + texture = tex; + } +} + } //!FBX } //!Assimp