diff --git a/code/ColladaExporter.cpp b/code/ColladaExporter.cpp index f5658bb1d..1d8b04d42 100644 --- a/code/ColladaExporter.cpp +++ b/code/ColladaExporter.cpp @@ -94,6 +94,7 @@ void ColladaExporter::WriteFile() WriteHeader(); + WriteMaterials(); WriteGeometryLibrary(); WriteSceneLibrary(); @@ -127,6 +128,155 @@ void ColladaExporter::WriteHeader() mOutput << startstr << "" << endstr; } +// ------------------------------------------------------------------------------------------------ +// Reads a single surface entry from the given material keys +void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex) +{ + if( pSrcMat->GetTextureCount( pTexture) > 0 ) + { + aiString texfile; + unsigned int uvChannel = 0; + pSrcMat->GetTexture( pTexture, 0, &texfile, nullptr, &uvChannel); + poSurface.texture = texfile.C_Str(); + poSurface.channel = uvChannel; + } else + { + if( pKey ) + pSrcMat->Get( pKey, pType, pIndex, poSurface.color); + } +} + +// ------------------------------------------------------------------------------------------------ +// Writes an image entry for the given surface +void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) +{ + if( !pSurface.texture.empty() ) + { + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << pSurface.texture << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + } +} + +// ------------------------------------------------------------------------------------------------ +// Writes a color-or-texture entry into an effect definition +void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName) +{ + mOutput << startstr << "<" << pTypeName << ">" << endstr; + PushTag(); + if( pSurface.texture.empty() ) + { + mOutput << startstr << "" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "" << endstr; + } else + { + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; +} + +// ------------------------------------------------------------------------------------------------ +// Writes the material setup +void ColladaExporter::WriteMaterials() +{ + materials.resize( mScene->mNumMaterials); + + /// collect all materials from the scene + for( size_t a = 0; a < mScene->mNumMaterials; ++a ) + { + const aiMaterial* mat = mScene->mMaterials[a]; + + aiString name; + if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS ) + name = "mat"; + materials[a].name = boost::lexical_cast (a) + name.C_Str(); + + ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); + ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE); + ReadMaterialSurface( materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); + ReadMaterialSurface( materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE); + ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE); + ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, nullptr, 0, 0); + + mat->Get( AI_MATKEY_SHININESS, materials[a].shininess); + } + + // output textures if present + mOutput << startstr << "" << endstr; + PushTag(); + for( auto it = materials.cbegin(); it != materials.cend(); ++it ) + { + const Material& mat = *it; + WriteImageEntry( mat.ambient, mat.name + "_ambient_image"); + WriteImageEntry( mat.diffuse, mat.name + "_diffuse_image"); + WriteImageEntry( mat.specular, mat.name + "_specular_image"); + WriteImageEntry( mat.emissive, mat.name + "_emissive_image"); + WriteImageEntry( mat.reflective, mat.name + "_reflective_image"); + WriteImageEntry( mat.normal, mat.name + "_normal_image"); + } + PopTag(); + mOutput << startstr << "" << endstr; + + // output effects - those are the actual carriers of information + mOutput << startstr << "" << endstr; + PushTag(); + for( auto it = materials.cbegin(); it != materials.cend(); ++it ) + { + const Material& mat = *it; + // this is so ridiculous it must be right + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); + + WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "_ambient_image"); + WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "_diffuse_image"); + WriteTextureColorEntry( mat.specular, "specular", mat.name + "_specular_image"); + WriteTextureColorEntry( mat.emissive, "emission", mat.name + "_emissive_image"); + WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "_reflective_image"); + if( !mat.normal.texture.empty() ) + WriteTextureColorEntry( mat.normal, "bump", mat.name + "_normal_image"); + + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << mat.shininess << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; + + // write materials - they're just effect references + mOutput << startstr << "" << endstr; + PushTag(); + for( auto it = materials.cbegin(); it != materials.cend(); ++it ) + { + const Material& mat = *it; + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; +} + // ------------------------------------------------------------------------------------------------ // Writes the geometry library void ColladaExporter::WriteGeometryLibrary() @@ -199,7 +349,7 @@ void ColladaExporter::WriteGeometry( size_t pIndex) mOutput << startstr << "" << endstr; // write face setup - mOutput << startstr << "mNumFaces << "\" material=\"tellme\">" << endstr; + mOutput << startstr << "mNumFaces << "\" material=\"theresonlyone\">" << endstr; PushTag(); mOutput << startstr << "" << endstr; @@ -356,8 +506,16 @@ void ColladaExporter::WriteNode( const aiNode* pNode) // const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]]; mOutput << startstr << "mMeshes[a]) << "\">" << endstr; PushTag(); - + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "mMeshes[pNode->mMeshes[a]]->mMaterialIndex].name << "\" />" << endstr; PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); mOutput << startstr << "" << endstr; } diff --git a/code/ColladaExporter.h b/code/ColladaExporter.h index c4fd2f6f2..cfe5a8db7 100644 --- a/code/ColladaExporter.h +++ b/code/ColladaExporter.h @@ -68,6 +68,9 @@ protected: /// Writes the asset header void WriteHeader(); + /// Writes the material setup + void WriteMaterials(); + /// Writes the geometry library void WriteGeometryLibrary(); @@ -105,6 +108,36 @@ protected: std::string startstr; /// current line end string for simple stream insertion std::string endstr; + + // pair of color and texture - texture precedences color + struct Surface + { + aiColor4D color; + std::string texture; + size_t channel; + Surface() { channel = 0; } + }; + + // summarize a material in an convinient way. + struct Material + { + std::string name; + Surface ambient, diffuse, specular, emissive, reflective, normal; + float shininess; /// specular exponent + + Material() { shininess = 16.0f; } + }; + + std::vector materials; + +protected: + /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions + /// Reads a single surface entry from the given material keys + void ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex); + /// Writes an image entry for the given surface + void WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd); + /// Writes a color-or-texture entry into an effect definition + void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName); }; }