vrshoot

annotate 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
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2012, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41 #include "AssimpPCH.h"
nuclear@0 42
nuclear@0 43 #ifndef ASSIMP_BUILD_NO_EXPORT
nuclear@0 44 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
nuclear@0 45
nuclear@0 46 #include "ObjExporter.h"
nuclear@0 47 #include "assimp/version.h"
nuclear@0 48
nuclear@0 49 using namespace Assimp;
nuclear@0 50 namespace Assimp {
nuclear@0 51
nuclear@0 52 // ------------------------------------------------------------------------------------------------
nuclear@0 53 // Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp
nuclear@0 54 void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
nuclear@0 55 {
nuclear@0 56 // invoke the exporter
nuclear@0 57 ObjExporter exporter(pFile, pScene);
nuclear@0 58
nuclear@0 59 // we're still here - export successfully completed. Write both the main OBJ file and the material script
nuclear@0 60 {
nuclear@0 61 boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
nuclear@0 62 if(outfile == NULL) {
nuclear@0 63 throw DeadlyExportError("could not open output .obj file: " + std::string(pFile));
nuclear@0 64 }
nuclear@0 65 outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
nuclear@0 66 }
nuclear@0 67 {
nuclear@0 68 boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(exporter.GetMaterialLibFileName(),"wt"));
nuclear@0 69 if(outfile == NULL) {
nuclear@0 70 throw DeadlyExportError("could not open output .mtl file: " + std::string(exporter.GetMaterialLibFileName()));
nuclear@0 71 }
nuclear@0 72 outfile->Write( exporter.mOutputMat.str().c_str(), static_cast<size_t>(exporter.mOutputMat.tellp()),1);
nuclear@0 73 }
nuclear@0 74 }
nuclear@0 75
nuclear@0 76 } // end of namespace Assimp
nuclear@0 77
nuclear@0 78
nuclear@0 79 // ------------------------------------------------------------------------------------------------
nuclear@0 80 ObjExporter :: ObjExporter(const char* _filename, const aiScene* pScene)
nuclear@0 81 : filename(_filename)
nuclear@0 82 , pScene(pScene)
nuclear@0 83 , endl("\n")
nuclear@0 84 {
nuclear@0 85 // make sure that all formatting happens using the standard, C locale and not the user's current locale
nuclear@0 86 const std::locale& l = std::locale("C");
nuclear@0 87 mOutput.imbue(l);
nuclear@0 88 mOutputMat.imbue(l);
nuclear@0 89
nuclear@0 90 WriteGeometryFile();
nuclear@0 91 WriteMaterialFile();
nuclear@0 92 }
nuclear@0 93
nuclear@0 94 // ------------------------------------------------------------------------------------------------
nuclear@0 95 std::string ObjExporter :: GetMaterialLibName()
nuclear@0 96 {
nuclear@0 97 // within the Obj file, we use just the relative file name with the path stripped
nuclear@0 98 const std::string& s = GetMaterialLibFileName();
nuclear@0 99 std::string::size_type il = s.find_last_of("/\\");
nuclear@0 100 if (il != std::string::npos) {
nuclear@0 101 return s.substr(il + 1);
nuclear@0 102 }
nuclear@0 103
nuclear@0 104 return s;
nuclear@0 105 }
nuclear@0 106
nuclear@0 107 // ------------------------------------------------------------------------------------------------
nuclear@0 108 std::string ObjExporter :: GetMaterialLibFileName()
nuclear@0 109 {
nuclear@0 110 return filename + ".mtl";
nuclear@0 111 }
nuclear@0 112
nuclear@0 113 // ------------------------------------------------------------------------------------------------
nuclear@0 114 void ObjExporter :: WriteHeader(std::ostringstream& out)
nuclear@0 115 {
nuclear@0 116 out << "# File produced by Open Asset Import Library (http://www.assimp.sf.net)" << endl;
nuclear@0 117 out << "# (assimp v" << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' << aiGetVersionRevision() << ")" << endl << endl;
nuclear@0 118 }
nuclear@0 119
nuclear@0 120 // ------------------------------------------------------------------------------------------------
nuclear@0 121 std::string ObjExporter :: GetMaterialName(unsigned int index)
nuclear@0 122 {
nuclear@0 123 const aiMaterial* const mat = pScene->mMaterials[index];
nuclear@0 124 aiString s;
nuclear@0 125 if(AI_SUCCESS == mat->Get(AI_MATKEY_NAME,s)) {
nuclear@0 126 return std::string(s.data,s.length);
nuclear@0 127 }
nuclear@0 128
nuclear@0 129 char number[ sizeof(unsigned int) * 3 + 1 ];
nuclear@0 130 ASSIMP_itoa10(number,index);
nuclear@0 131 return "$Material_" + std::string(number);
nuclear@0 132 }
nuclear@0 133
nuclear@0 134 // ------------------------------------------------------------------------------------------------
nuclear@0 135 void ObjExporter :: WriteMaterialFile()
nuclear@0 136 {
nuclear@0 137 WriteHeader(mOutputMat);
nuclear@0 138
nuclear@0 139 for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
nuclear@0 140 const aiMaterial* const mat = pScene->mMaterials[i];
nuclear@0 141
nuclear@0 142 int illum = 1;
nuclear@0 143 mOutputMat << "newmtl " << GetMaterialName(i) << endl;
nuclear@0 144
nuclear@0 145 aiColor4D c;
nuclear@0 146 if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE,c)) {
nuclear@0 147 mOutputMat << "kd " << c.r << " " << c.g << " " << c.b << endl;
nuclear@0 148 }
nuclear@0 149 if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT,c)) {
nuclear@0 150 mOutputMat << "ka " << c.r << " " << c.g << " " << c.b << endl;
nuclear@0 151 }
nuclear@0 152 if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) {
nuclear@0 153 mOutputMat << "ks " << c.r << " " << c.g << " " << c.b << endl;
nuclear@0 154 }
nuclear@0 155
nuclear@0 156 float o;
nuclear@0 157 if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
nuclear@0 158 mOutputMat << "d " << o << endl;
nuclear@0 159 }
nuclear@0 160
nuclear@0 161 if(AI_SUCCESS == mat->Get(AI_MATKEY_SHININESS,o) && o) {
nuclear@0 162 mOutputMat << "Ns " << o << endl;
nuclear@0 163 illum = 2;
nuclear@0 164 }
nuclear@0 165
nuclear@0 166 mOutputMat << "illum " << illum << endl;
nuclear@0 167
nuclear@0 168 aiString s;
nuclear@0 169 if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_DIFFUSE(0),s)) {
nuclear@0 170 mOutputMat << "map_kd " << s.data << endl;
nuclear@0 171 }
nuclear@0 172 if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_AMBIENT(0),s)) {
nuclear@0 173 mOutputMat << "map_ka " << s.data << endl;
nuclear@0 174 }
nuclear@0 175 if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SPECULAR(0),s)) {
nuclear@0 176 mOutputMat << "map_ks " << s.data << endl;
nuclear@0 177 }
nuclear@0 178 if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SHININESS(0),s)) {
nuclear@0 179 mOutputMat << "map_ns " << s.data << endl;
nuclear@0 180 }
nuclear@0 181 if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_HEIGHT(0),s) || AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_NORMALS(0),s)) {
nuclear@0 182 // implementations seem to vary here, so write both variants
nuclear@0 183 mOutputMat << "bump " << s.data << endl;
nuclear@0 184 mOutputMat << "map_bump " << s.data << endl;
nuclear@0 185 }
nuclear@0 186
nuclear@0 187 mOutputMat << endl;
nuclear@0 188 }
nuclear@0 189 }
nuclear@0 190
nuclear@0 191 // ------------------------------------------------------------------------------------------------
nuclear@0 192 void ObjExporter :: WriteGeometryFile()
nuclear@0 193 {
nuclear@0 194 WriteHeader(mOutput);
nuclear@0 195 mOutput << "mtllib " << GetMaterialLibName() << endl << endl;
nuclear@0 196
nuclear@0 197 // collect mesh geometry
nuclear@0 198 aiMatrix4x4 mBase;
nuclear@0 199 AddNode(pScene->mRootNode,mBase);
nuclear@0 200
nuclear@0 201 // write vertex positions
nuclear@0 202 mOutput << "# " << vp.size() << " vertex positions" << endl;
nuclear@0 203 BOOST_FOREACH(const aiVector3D& v, vp) {
nuclear@0 204 mOutput << "v " << v.x << " " << v.y << " " << v.z << endl;
nuclear@0 205 }
nuclear@0 206 mOutput << endl;
nuclear@0 207
nuclear@0 208 // write uv coordinates
nuclear@0 209 mOutput << "# " << vt.size() << " UV coordinates" << endl;
nuclear@0 210 BOOST_FOREACH(const aiVector3D& v, vt) {
nuclear@0 211 mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl;
nuclear@0 212 }
nuclear@0 213 mOutput << endl;
nuclear@0 214
nuclear@0 215 // write vertex normals
nuclear@0 216 mOutput << "# " << vn.size() << " vertex normals" << endl;
nuclear@0 217 BOOST_FOREACH(const aiVector3D& v, vn) {
nuclear@0 218 mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl;
nuclear@0 219 }
nuclear@0 220 mOutput << endl;
nuclear@0 221
nuclear@0 222 // now write all mesh instances
nuclear@0 223 BOOST_FOREACH(const MeshInstance& m, meshes) {
nuclear@0 224 mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl;
nuclear@0 225 mOutput << "g " << m.name << endl;
nuclear@0 226 mOutput << "usemtl " << m.matname << endl;
nuclear@0 227
nuclear@0 228 BOOST_FOREACH(const Face& f, m.faces) {
nuclear@0 229 mOutput << f.kind << ' ';
nuclear@0 230 BOOST_FOREACH(const FaceVertex& fv, f.indices) {
nuclear@0 231 mOutput << ' ' << fv.vp;
nuclear@0 232
nuclear@0 233 if (f.kind != 'p') {
nuclear@0 234 if (fv.vt || f.kind == 'f') {
nuclear@0 235 mOutput << '/';
nuclear@0 236 }
nuclear@0 237 if (fv.vt) {
nuclear@0 238 mOutput << fv.vt;
nuclear@0 239 }
nuclear@0 240 if (f.kind == 'f') {
nuclear@0 241 mOutput << '/';
nuclear@0 242 if (fv.vn) {
nuclear@0 243 mOutput << fv.vn;
nuclear@0 244 }
nuclear@0 245 }
nuclear@0 246 }
nuclear@0 247 }
nuclear@0 248
nuclear@0 249 mOutput << endl;
nuclear@0 250 }
nuclear@0 251 mOutput << endl;
nuclear@0 252 }
nuclear@0 253 }
nuclear@0 254
nuclear@0 255 // ------------------------------------------------------------------------------------------------
nuclear@0 256 void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat)
nuclear@0 257 {
nuclear@0 258 meshes.push_back(MeshInstance());
nuclear@0 259 MeshInstance& mesh = meshes.back();
nuclear@0 260
nuclear@0 261 mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_"+std::string(m->mName.data,m->mName.length) : "");
nuclear@0 262 mesh.matname = GetMaterialName(m->mMaterialIndex);
nuclear@0 263
nuclear@0 264 mesh.faces.resize(m->mNumFaces);
nuclear@0 265 for(unsigned int i = 0; i < m->mNumFaces; ++i) {
nuclear@0 266 const aiFace& f = m->mFaces[i];
nuclear@0 267
nuclear@0 268 Face& face = mesh.faces[i];
nuclear@0 269 switch (f.mNumIndices) {
nuclear@0 270 case 1:
nuclear@0 271 face.kind = 'p';
nuclear@0 272 break;
nuclear@0 273 case 2:
nuclear@0 274 face.kind = 'l';
nuclear@0 275 break;
nuclear@0 276 default:
nuclear@0 277 face.kind = 'f';
nuclear@0 278 }
nuclear@0 279 face.indices.resize(f.mNumIndices);
nuclear@0 280
nuclear@0 281 for(unsigned int a = 0; a < f.mNumIndices; ++a) {
nuclear@0 282 const unsigned int idx = f.mIndices[a];
nuclear@0 283
nuclear@0 284 // XXX need a way to check if this is an unique vertex or if we had it already,
nuclear@0 285 // in which case we should instead reference the previous occurrence.
nuclear@0 286 ai_assert(m->mVertices);
nuclear@0 287 vp.push_back( mat * m->mVertices[idx] );
nuclear@0 288 face.indices[a].vp = vp.size();
nuclear@0 289
nuclear@0 290 if (m->mNormals) {
nuclear@0 291 vn.push_back( m->mNormals[idx] );
nuclear@0 292 }
nuclear@0 293 face.indices[a].vn = vn.size();
nuclear@0 294
nuclear@0 295 if (m->mTextureCoords[0]) {
nuclear@0 296 vt.push_back( m->mTextureCoords[0][idx] );
nuclear@0 297 }
nuclear@0 298 face.indices[a].vt = vt.size();
nuclear@0 299 }
nuclear@0 300 }
nuclear@0 301 }
nuclear@0 302
nuclear@0 303 // ------------------------------------------------------------------------------------------------
nuclear@0 304 void ObjExporter :: AddNode(const aiNode* nd, const aiMatrix4x4& mParent)
nuclear@0 305 {
nuclear@0 306 const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
nuclear@0 307
nuclear@0 308 for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
nuclear@0 309 AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]],mAbs);
nuclear@0 310 }
nuclear@0 311
nuclear@0 312 for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
nuclear@0 313 AddNode(nd->mChildren[i],mAbs);
nuclear@0 314 }
nuclear@0 315 }
nuclear@0 316
nuclear@0 317 #endif
nuclear@0 318 #endif