vrshoot
diff libs/assimp/ObjExporter.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/ObjExporter.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,318 @@ 1.4 +/* 1.5 +Open Asset Import Library (assimp) 1.6 +---------------------------------------------------------------------- 1.7 + 1.8 +Copyright (c) 2006-2012, assimp team 1.9 +All rights reserved. 1.10 + 1.11 +Redistribution and use of this software in source and binary forms, 1.12 +with or without modification, are permitted provided that the 1.13 +following conditions are met: 1.14 + 1.15 +* Redistributions of source code must retain the above 1.16 + copyright notice, this list of conditions and the 1.17 + following disclaimer. 1.18 + 1.19 +* Redistributions in binary form must reproduce the above 1.20 + copyright notice, this list of conditions and the 1.21 + following disclaimer in the documentation and/or other 1.22 + materials provided with the distribution. 1.23 + 1.24 +* Neither the name of the assimp team, nor the names of its 1.25 + contributors may be used to endorse or promote products 1.26 + derived from this software without specific prior 1.27 + written permission of the assimp team. 1.28 + 1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.40 + 1.41 +---------------------------------------------------------------------- 1.42 +*/ 1.43 + 1.44 +#include "AssimpPCH.h" 1.45 + 1.46 +#ifndef ASSIMP_BUILD_NO_EXPORT 1.47 +#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER 1.48 + 1.49 +#include "ObjExporter.h" 1.50 +#include "assimp/version.h" 1.51 + 1.52 +using namespace Assimp; 1.53 +namespace Assimp { 1.54 + 1.55 +// ------------------------------------------------------------------------------------------------ 1.56 +// Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp 1.57 +void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene) 1.58 +{ 1.59 + // invoke the exporter 1.60 + ObjExporter exporter(pFile, pScene); 1.61 + 1.62 + // we're still here - export successfully completed. Write both the main OBJ file and the material script 1.63 + { 1.64 + boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt")); 1.65 + if(outfile == NULL) { 1.66 + throw DeadlyExportError("could not open output .obj file: " + std::string(pFile)); 1.67 + } 1.68 + outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1); 1.69 + } 1.70 + { 1.71 + boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(exporter.GetMaterialLibFileName(),"wt")); 1.72 + if(outfile == NULL) { 1.73 + throw DeadlyExportError("could not open output .mtl file: " + std::string(exporter.GetMaterialLibFileName())); 1.74 + } 1.75 + outfile->Write( exporter.mOutputMat.str().c_str(), static_cast<size_t>(exporter.mOutputMat.tellp()),1); 1.76 + } 1.77 +} 1.78 + 1.79 +} // end of namespace Assimp 1.80 + 1.81 + 1.82 +// ------------------------------------------------------------------------------------------------ 1.83 +ObjExporter :: ObjExporter(const char* _filename, const aiScene* pScene) 1.84 +: filename(_filename) 1.85 +, pScene(pScene) 1.86 +, endl("\n") 1.87 +{ 1.88 + // make sure that all formatting happens using the standard, C locale and not the user's current locale 1.89 + const std::locale& l = std::locale("C"); 1.90 + mOutput.imbue(l); 1.91 + mOutputMat.imbue(l); 1.92 + 1.93 + WriteGeometryFile(); 1.94 + WriteMaterialFile(); 1.95 +} 1.96 + 1.97 +// ------------------------------------------------------------------------------------------------ 1.98 +std::string ObjExporter :: GetMaterialLibName() 1.99 +{ 1.100 + // within the Obj file, we use just the relative file name with the path stripped 1.101 + const std::string& s = GetMaterialLibFileName(); 1.102 + std::string::size_type il = s.find_last_of("/\\"); 1.103 + if (il != std::string::npos) { 1.104 + return s.substr(il + 1); 1.105 + } 1.106 + 1.107 + return s; 1.108 +} 1.109 + 1.110 +// ------------------------------------------------------------------------------------------------ 1.111 +std::string ObjExporter :: GetMaterialLibFileName() 1.112 +{ 1.113 + return filename + ".mtl"; 1.114 +} 1.115 + 1.116 +// ------------------------------------------------------------------------------------------------ 1.117 +void ObjExporter :: WriteHeader(std::ostringstream& out) 1.118 +{ 1.119 + out << "# File produced by Open Asset Import Library (http://www.assimp.sf.net)" << endl; 1.120 + out << "# (assimp v" << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' << aiGetVersionRevision() << ")" << endl << endl; 1.121 +} 1.122 + 1.123 +// ------------------------------------------------------------------------------------------------ 1.124 +std::string ObjExporter :: GetMaterialName(unsigned int index) 1.125 +{ 1.126 + const aiMaterial* const mat = pScene->mMaterials[index]; 1.127 + aiString s; 1.128 + if(AI_SUCCESS == mat->Get(AI_MATKEY_NAME,s)) { 1.129 + return std::string(s.data,s.length); 1.130 + } 1.131 + 1.132 + char number[ sizeof(unsigned int) * 3 + 1 ]; 1.133 + ASSIMP_itoa10(number,index); 1.134 + return "$Material_" + std::string(number); 1.135 +} 1.136 + 1.137 +// ------------------------------------------------------------------------------------------------ 1.138 +void ObjExporter :: WriteMaterialFile() 1.139 +{ 1.140 + WriteHeader(mOutputMat); 1.141 + 1.142 + for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) { 1.143 + const aiMaterial* const mat = pScene->mMaterials[i]; 1.144 + 1.145 + int illum = 1; 1.146 + mOutputMat << "newmtl " << GetMaterialName(i) << endl; 1.147 + 1.148 + aiColor4D c; 1.149 + if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE,c)) { 1.150 + mOutputMat << "kd " << c.r << " " << c.g << " " << c.b << endl; 1.151 + } 1.152 + if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT,c)) { 1.153 + mOutputMat << "ka " << c.r << " " << c.g << " " << c.b << endl; 1.154 + } 1.155 + if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) { 1.156 + mOutputMat << "ks " << c.r << " " << c.g << " " << c.b << endl; 1.157 + } 1.158 + 1.159 + float o; 1.160 + if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) { 1.161 + mOutputMat << "d " << o << endl; 1.162 + } 1.163 + 1.164 + if(AI_SUCCESS == mat->Get(AI_MATKEY_SHININESS,o) && o) { 1.165 + mOutputMat << "Ns " << o << endl; 1.166 + illum = 2; 1.167 + } 1.168 + 1.169 + mOutputMat << "illum " << illum << endl; 1.170 + 1.171 + aiString s; 1.172 + if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_DIFFUSE(0),s)) { 1.173 + mOutputMat << "map_kd " << s.data << endl; 1.174 + } 1.175 + if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_AMBIENT(0),s)) { 1.176 + mOutputMat << "map_ka " << s.data << endl; 1.177 + } 1.178 + if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SPECULAR(0),s)) { 1.179 + mOutputMat << "map_ks " << s.data << endl; 1.180 + } 1.181 + if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SHININESS(0),s)) { 1.182 + mOutputMat << "map_ns " << s.data << endl; 1.183 + } 1.184 + if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_HEIGHT(0),s) || AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_NORMALS(0),s)) { 1.185 + // implementations seem to vary here, so write both variants 1.186 + mOutputMat << "bump " << s.data << endl; 1.187 + mOutputMat << "map_bump " << s.data << endl; 1.188 + } 1.189 + 1.190 + mOutputMat << endl; 1.191 + } 1.192 +} 1.193 + 1.194 +// ------------------------------------------------------------------------------------------------ 1.195 +void ObjExporter :: WriteGeometryFile() 1.196 +{ 1.197 + WriteHeader(mOutput); 1.198 + mOutput << "mtllib " << GetMaterialLibName() << endl << endl; 1.199 + 1.200 + // collect mesh geometry 1.201 + aiMatrix4x4 mBase; 1.202 + AddNode(pScene->mRootNode,mBase); 1.203 + 1.204 + // write vertex positions 1.205 + mOutput << "# " << vp.size() << " vertex positions" << endl; 1.206 + BOOST_FOREACH(const aiVector3D& v, vp) { 1.207 + mOutput << "v " << v.x << " " << v.y << " " << v.z << endl; 1.208 + } 1.209 + mOutput << endl; 1.210 + 1.211 + // write uv coordinates 1.212 + mOutput << "# " << vt.size() << " UV coordinates" << endl; 1.213 + BOOST_FOREACH(const aiVector3D& v, vt) { 1.214 + mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl; 1.215 + } 1.216 + mOutput << endl; 1.217 + 1.218 + // write vertex normals 1.219 + mOutput << "# " << vn.size() << " vertex normals" << endl; 1.220 + BOOST_FOREACH(const aiVector3D& v, vn) { 1.221 + mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl; 1.222 + } 1.223 + mOutput << endl; 1.224 + 1.225 + // now write all mesh instances 1.226 + BOOST_FOREACH(const MeshInstance& m, meshes) { 1.227 + mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl; 1.228 + mOutput << "g " << m.name << endl; 1.229 + mOutput << "usemtl " << m.matname << endl; 1.230 + 1.231 + BOOST_FOREACH(const Face& f, m.faces) { 1.232 + mOutput << f.kind << ' '; 1.233 + BOOST_FOREACH(const FaceVertex& fv, f.indices) { 1.234 + mOutput << ' ' << fv.vp; 1.235 + 1.236 + if (f.kind != 'p') { 1.237 + if (fv.vt || f.kind == 'f') { 1.238 + mOutput << '/'; 1.239 + } 1.240 + if (fv.vt) { 1.241 + mOutput << fv.vt; 1.242 + } 1.243 + if (f.kind == 'f') { 1.244 + mOutput << '/'; 1.245 + if (fv.vn) { 1.246 + mOutput << fv.vn; 1.247 + } 1.248 + } 1.249 + } 1.250 + } 1.251 + 1.252 + mOutput << endl; 1.253 + } 1.254 + mOutput << endl; 1.255 + } 1.256 +} 1.257 + 1.258 +// ------------------------------------------------------------------------------------------------ 1.259 +void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) 1.260 +{ 1.261 + meshes.push_back(MeshInstance()); 1.262 + MeshInstance& mesh = meshes.back(); 1.263 + 1.264 + mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_"+std::string(m->mName.data,m->mName.length) : ""); 1.265 + mesh.matname = GetMaterialName(m->mMaterialIndex); 1.266 + 1.267 + mesh.faces.resize(m->mNumFaces); 1.268 + for(unsigned int i = 0; i < m->mNumFaces; ++i) { 1.269 + const aiFace& f = m->mFaces[i]; 1.270 + 1.271 + Face& face = mesh.faces[i]; 1.272 + switch (f.mNumIndices) { 1.273 + case 1: 1.274 + face.kind = 'p'; 1.275 + break; 1.276 + case 2: 1.277 + face.kind = 'l'; 1.278 + break; 1.279 + default: 1.280 + face.kind = 'f'; 1.281 + } 1.282 + face.indices.resize(f.mNumIndices); 1.283 + 1.284 + for(unsigned int a = 0; a < f.mNumIndices; ++a) { 1.285 + const unsigned int idx = f.mIndices[a]; 1.286 + 1.287 + // XXX need a way to check if this is an unique vertex or if we had it already, 1.288 + // in which case we should instead reference the previous occurrence. 1.289 + ai_assert(m->mVertices); 1.290 + vp.push_back( mat * m->mVertices[idx] ); 1.291 + face.indices[a].vp = vp.size(); 1.292 + 1.293 + if (m->mNormals) { 1.294 + vn.push_back( m->mNormals[idx] ); 1.295 + } 1.296 + face.indices[a].vn = vn.size(); 1.297 + 1.298 + if (m->mTextureCoords[0]) { 1.299 + vt.push_back( m->mTextureCoords[0][idx] ); 1.300 + } 1.301 + face.indices[a].vt = vt.size(); 1.302 + } 1.303 + } 1.304 +} 1.305 + 1.306 +// ------------------------------------------------------------------------------------------------ 1.307 +void ObjExporter :: AddNode(const aiNode* nd, const aiMatrix4x4& mParent) 1.308 +{ 1.309 + const aiMatrix4x4& mAbs = mParent * nd->mTransformation; 1.310 + 1.311 + for(unsigned int i = 0; i < nd->mNumMeshes; ++i) { 1.312 + AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]],mAbs); 1.313 + } 1.314 + 1.315 + for(unsigned int i = 0; i < nd->mNumChildren; ++i) { 1.316 + AddNode(nd->mChildren[i],mAbs); 1.317 + } 1.318 +} 1.319 + 1.320 +#endif 1.321 +#endif