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