From e71a29248fe54035dd175446e9a51361f88c3f9b Mon Sep 17 00:00:00 2001 From: cignoni Date: Tue, 7 Mar 2006 13:19:29 +0000 Subject: [PATCH] First Release with OBJ import support --- wrap/io_trimesh/export_obj.h | 36 +- wrap/io_trimesh/import.h | 13 +- wrap/io_trimesh/import_obj.h | 1162 +++++++++++++++++++++++++++++++++ wrap/io_trimesh/io_material.h | 136 ++++ 4 files changed, 1326 insertions(+), 21 deletions(-) create mode 100644 wrap/io_trimesh/import_obj.h create mode 100644 wrap/io_trimesh/io_material.h diff --git a/wrap/io_trimesh/export_obj.h b/wrap/io_trimesh/export_obj.h index 210b8ff4..3fadba36 100644 --- a/wrap/io_trimesh/export_obj.h +++ b/wrap/io_trimesh/export_obj.h @@ -25,6 +25,9 @@ History $Log: not supported by cvs2svn $ + Revision 1.2 2006/02/28 14:38:09 corsini + remove qt include + Revision 1.1 2006/02/16 19:28:36 fmazzant transfer of Export_3ds.h, Export_obj.h, Io_3ds_obj_material.h from Meshlab to vcg @@ -75,7 +78,7 @@ #include #include #include -#include "io_3ds_obj_material.h" +#include "io_material.h" #include #include #include @@ -151,10 +154,8 @@ namespace io { /* function which saves in OBJ file format */ - static int SaveASCII(SaveMeshType &m, const char * filename, ObjInfo &oi) + static int SaveASCII(SaveMeshType &m, const char * filename, int mask, CallBackPos *cb=0) { - CallBackPos *cb = oi.cb; - if(m.vert.size() == 0) return E_NOTVEXTEXVALID; if(m.face.size() == 0) @@ -177,7 +178,7 @@ namespace io { fprintf(fp,"# Object %s\n#\n# Vertices: %d\n# Faces: %d\n#\n####\n",fn.substr(i+1).c_str(),m.vert.size(),m.face.size()); //library materials - if(oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) + if(mask & vcg::tri::io::Mask::IOM_FACECOLOR) fprintf(fp,"mtllib ./%s.mtl\n\n",fn.substr(i+1).c_str()); //vertexs + normal @@ -188,7 +189,7 @@ namespace io { for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if( !(*vi).IsD() ) { //saves normal per vertex - if(oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL | oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) + if(mask & vcg::tri::io::Mask::IOM_VERTNORMAL | mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) { if(AddNewNormalVertex(NormalVertex,(*vi).N(),value)) { @@ -201,7 +202,7 @@ namespace io { fprintf(fp,"v %f %f %f\n",(*vi).P()[0],(*vi).P()[1],(*vi).P()[2]); if (cb !=NULL) - (*cb)(100.0 * (float)++current/(float)max, "writing vertices "); + (*cb)((100*++current)/max, "writing vertices "); else { fclose(fp); return E_ABORTED;} } @@ -215,7 +216,7 @@ namespace io { /*int*/ value = 1;//tmp for(fi=m.face.begin(); fi!=m.face.end(); ++fi) if( !(*fi).IsD() ) { - if(oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) + if(mask & vcg::tri::io::Mask::IOM_FACECOLOR) { int index = vcg::tri::io::Materials::CreateNewMaterial(m,materials,material_num,fi); @@ -239,7 +240,7 @@ namespace io { unsigned int MAX = 3; for(unsigned int k=0;k #include #include #include @@ -68,7 +72,7 @@ template class Importer { private: - enum KnownTypes { KT_UNKNOWN, KT_PLY, KT_STL, KT_OFF }; + enum KnownTypes { KT_UNKNOWN, KT_PLY, KT_STL, KT_OFF, KT_OBJ }; static int &LastType() { static int lastType= KT_UNKNOWN; @@ -112,7 +116,12 @@ static int Open(OpenMeshType &m, const char *filename, int &loadmask, CallBackPo err = ImporterOFF::Open(m, filename, loadmask, cb); LastType()=KT_OFF; } - else { + else if(FileExtension(filename,"obj")) + { + err = ImporterOBJ::Open(m, filename, loadmask, cb); + LastType()=KT_OBJ; + } + else { err=1; LastType()=KT_UNKNOWN; } diff --git a/wrap/io_trimesh/import_obj.h b/wrap/io_trimesh/import_obj.h new file mode 100644 index 00000000..418512c6 --- /dev/null +++ b/wrap/io_trimesh/import_obj.h @@ -0,0 +1,1162 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +/**************************************************************************** + History + +$Log: not supported by cvs2svn $ +Initial Working version coded by Buzzelli. +****************************************************************************/ + +#ifndef __VCGLIB_IMPORT_OBJ +#define __VCGLIB_IMPORT_OBJ + +#include +#include +#include +#include + +#include +#include +#include + + +namespace vcg { +namespace tri { +namespace io { + +/** +This class encapsulate a filter for importing obj (Alias Wavefront) meshes. +Warning: this code assume little endian (PC) architecture!!! +*/ +template +class ImporterOBJ +{ +public: + +typedef typename OpenMeshType::VertexPointer VertexPointer; +typedef typename OpenMeshType::ScalarType ScalarType; +typedef typename OpenMeshType::VertexType VertexType; +typedef typename OpenMeshType::FaceType FaceType; +typedef typename OpenMeshType::VertexIterator VertexIterator; +typedef typename OpenMeshType::FaceIterator FaceIterator; +typedef typename OpenMeshType::CoordType CoordType; + +class Info +{ +public: + + Info() + { + mask = 0; + cb = 0; + } + + /// It returns a bit mask describing the field preesnt in the ply file + int mask; + + /// a Simple callback that can be used for long obj parsing. + // it returns the current position, and formats a string with a description of what th efunction is doing (loading vertexes, faces...) + CallBackPos *cb; + + /// number of vertices + int numVertices; + + /// number of triangles + int numTriangles; + +}; // end class + + +struct OBJFacet +{ + CoordType n; + CoordType t; + CoordType v[3]; + + short attr; // material index +}; + +struct TexCoord +{ + float u; + float v; +}; + +struct Material +{ + Material() + { + strcpy(name, "default_material"); + ambient = Point3f( .2f, .2f, .2f); + diffuse = Point3f(1.0f, 1.0f, 1.0f); + specular = Point3f(1.0f, 1.0f, 1.0f); + + shininess = 0; + alpha = 1.0f; + + strcpy(textureFileName, ""); + textureIdx = -1; + }; + + char name[FILENAME_MAX]; + + Point3f ambient; + Point3f diffuse; + Point3f specular; + + int shininess; + float alpha; + + bool bSpecular; + + char textureFileName[FILENAME_MAX]; + short textureIdx; +}; + +enum OBJError { + // Successfull opening + E_NOERROR = 0x000, // 0 (position of correspondig string in the array) + + // Non Critical Errors (only odd numbers) + E_NON_CRITICAL_ERROR = 0x001, + E_MATERIAL_FILE_NOT_FOUND = 0x003, // 1 + E_MATERIAL_NOT_FOUND = 0x005, // 2 + E_TEXTURE_NOT_FOUND = 0x007, // 3 + E_VERTICES_WITH_SAME_IDX_IN_FACE = 0x009, // 4 + + // Critical Opening Errors (only even numbers) + E_CANTOPEN = 0x00A, // 5 + E_UNESPECTEDEOF = 0x00C, // 6 + E_ABORTED = 0x00E, // 7 + E_NO_VERTEX = 0x010, // 8 + E_NO_FACE = 0x012, // 9 + E_BAD_VERTEX_STATEMENT = 0x014, // 10 + E_BAD_VERT_TEX_STATEMENT = 0x016, // 11 + E_BAD_VERT_NORMAL_STATEMENT = 0x018, // 12 + E_LESS_THAN_3VERTINFACE = 0x01A, // 13 + E_BAD_VERT_INDEX = 0x01C, // 14 + E_BAD_VERT_TEX_INDEX = 0x01E, // 15 + E_BAD_VERT_NORMAL_INDEX = 0x020 // 16 +}; + +static const char* ErrorMsg(int error) +{ + static const char* obj_error_msg[] = + { + "No errors", // 0 + + "Material library file not found, a default white material is used", // 1 + "Some materials definitions were not found, a default white material is used where no material was available", // 2 + "Texture file not found", // 3 + "Identical index vertices found in the same face", // 4 + + "Can't open file", // 5 + "Premature End of file", // 6 + "File opening aborted", // 7 + "No vertex field found", // 8 + "No face field found", // 9 + "Vertex statement with less than 3 coords", // 10 + "Texture coords statement with less than 2 coords", // 11 + "Vertex normal statement with less than 3 coords", // 12 + "Face with less than 3 vertices", // 13 + "Bad vertex index in face", // 14 + "Bad texture coords index in face", // 15 + "Bad vertex normal index in face" // 16 + }; + + // due to approximation, following line works well for either even (critical err codes) + // or odd (non critical ones) numbers + error = (int) error/2; + + if(error>15 || error<0) return "Unknown error"; + else return obj_error_msg[error]; +}; + +static int Open(OpenMeshType &mesh, const char *filename, int &loadmask, CallBackPos *cb=0) +{ + Info oi; + oi.mask=-1; + oi.cb=cb; + int ret=Open(mesh,filename,oi); + loadmask=oi.mask; + return ret; +} + +/*! +* Opens an object file (in ascii format) and populates the mesh passed as first +* accordingly to read data +* \param m The mesh model to be populated with data stored into the file +* \param filename The name of the file to be opened +* \param oi A structure containing infos about the object to be opened +*/ +static int Open( OpenMeshType &m, const char * filename, Info &oi) +{ + int result = E_NOERROR; + + m.Clear(); + CallBackPos *cb = oi.cb; + + // if LoadMask has not been called yet, we call it here + if (oi.mask == -1) + LoadMask(filename, oi); + + if (oi.numVertices == 0) + return E_NO_VERTEX; + + if (oi.numTriangles == 0) + return E_NO_FACE; + + std::ifstream stream(filename); + if (stream.fail()) + return E_CANTOPEN; + + std::vector materials; // materials vector + std::vector texCoords; // texture coordinates + std::vector normals; // vertex normals + + std::vector< std::string > tokens; + std::string header; + + short currentMaterialIdx = 0; // index of current material into materials vector + Material defaultMaterial; // default material: white + materials.push_back(defaultMaterial); + + int numVertices = 0; // stores the number of vertices been read till now + int numTriangles = 0; // stores the number of faces been read till now + int numTexCoords = 0; // stores the number of texture coordinates been read till now + int numVNormals = 0; // stores the number of vertex normals been read till now + + int numVerticesPlusFaces = oi.numVertices + oi.numTriangles; + + // vertices and faces allocatetion + VertexIterator vi = Allocator::AddVertices(m,oi.numVertices); + FaceIterator fi = Allocator::AddFaces(m,oi.numTriangles); + + // parsing file + while (!stream.eof()) + { + tokens.clear(); + TokenizeNextLine(stream, tokens); + + unsigned numTokens = tokens.size(); + if (numTokens > 0) + { + header.clear(); + header = tokens[0]; + + if (header.compare("v")==0) // vertex + { + if (numTokens < 4) return E_BAD_VERTEX_STATEMENT; + + (*vi).P()[0] = (ScalarType) atof(tokens[1].c_str()); + (*vi).P()[1] = (ScalarType) atof(tokens[2].c_str()); + (*vi).P()[2] = (ScalarType) atof(tokens[3].c_str()); + ++numVertices; + + // assigning vertex color + // ---------------------- + if( oi.mask & vcg::tri::io::Mask::IOM_VERTCOLOR) + { + Material material = materials[currentMaterialIdx]; + Point3f diffuseColor = material.diffuse; + unsigned char r = (unsigned char) (diffuseColor[0] * 255.0); + unsigned char g = (unsigned char) (diffuseColor[1] * 255.0); + unsigned char b = (unsigned char) (diffuseColor[2] * 255.0); + unsigned char alpha = (unsigned char) (material.alpha * 255.0); + Color4b vertexColor = Color4b(r, g, b, alpha); + (*vi).C()[0] = vertexColor[0]; + (*vi).C()[1] = vertexColor[1]; + (*vi).C()[2] = vertexColor[2]; + (*vi).C()[3] = vertexColor[3]; + } + + ++vi; // move to next vertex iterator + + // callback invocation, abort loading process if the call returns false + if ((cb !=NULL) && (((numTriangles + numVertices)%100)==0) && !(*cb)((100*(numTriangles + numVertices))/numVerticesPlusFaces, "Vertex Loading")) + return E_ABORTED; + } + else if (header.compare("vt")==0) // vertex texture coords + { + if (numTokens < 3) return E_BAD_VERT_TEX_STATEMENT; + + TexCoord t; + t.u = (ScalarType) atof(tokens[1].c_str()); + t.v = (ScalarType) atof(tokens[2].c_str()); + texCoords.push_back(t); + + numTexCoords++; + } + else if (header.compare("vn")==0) // vertex normal + { + if (numTokens != 4) return E_BAD_VERT_NORMAL_STATEMENT; + + CoordType n; + n[0] = (ScalarType) atof(tokens[1].c_str()); + n[1] = (ScalarType) atof(tokens[2].c_str()); + n[2] = (ScalarType) atof(tokens[3].c_str()); + normals.push_back(n); + + numVNormals++; + } + else if (header.compare("f")==0) // face + { + if (numTokens < 4) return E_LESS_THAN_3VERTINFACE; + + int v1_index, v2_index, v3_index; + int vt1_index, vt2_index, vt3_index; + int vn1_index, vn2_index, vn3_index; + + if (( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) && + ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) ) + { + std::string vertex; + std::string texcoord; + std::string normal; + + SplitVVTVNToken(tokens[1], vertex, texcoord, normal); + v1_index = atoi(vertex.c_str()); + vt1_index = atoi(texcoord.c_str()); + vn1_index = atoi(normal.c_str()); + + SplitVVTVNToken(tokens[2], vertex, texcoord, normal); + v2_index = atoi(vertex.c_str()); + vt2_index = atoi(texcoord.c_str()); + vn2_index = atoi(normal.c_str()); + + SplitVVTVNToken(tokens[3], vertex, texcoord, normal); + v3_index = atoi(vertex.c_str()); + vt3_index = atoi(texcoord.c_str()); + vn3_index = atoi(normal.c_str()); + } + else if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) + { + std::string vertex; + std::string texcoord; + + SplitVVTToken(tokens[1], vertex, texcoord); + v1_index = atoi(vertex.c_str()); + vt1_index = atoi(texcoord.c_str()); + + SplitVVTToken(tokens[2], vertex, texcoord); + v2_index = atoi(vertex.c_str()); + vt2_index = atoi(texcoord.c_str()); + + SplitVVTToken(tokens[3], vertex, texcoord); + v3_index = atoi(vertex.c_str()); + vt3_index = atoi(texcoord.c_str()); + } + else if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) + { + std::string vertex; + std::string normal; + + SplitVVNToken(tokens[1], vertex, normal); + v1_index = atoi(vertex.c_str()); + vn1_index = atoi(normal.c_str()); + + SplitVVNToken(tokens[2], vertex, normal); + v2_index = atoi(vertex.c_str()); + vn2_index = atoi(normal.c_str()); + + SplitVVNToken(tokens[3], vertex, normal); + v3_index = atoi(vertex.c_str()); + vn3_index = atoi(normal.c_str()); + } + else + { + v1_index = atoi(tokens[1].c_str()); + v2_index = atoi(tokens[2].c_str()); + v3_index = atoi(tokens[3].c_str()); + } + + if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) + { + // verifying validity of texture coords indices + // -------------------------------------------- + if (vt1_index < 0) + { + vt1_index += numTexCoords; + if (vt1_index < 0) return E_BAD_VERT_TEX_INDEX; + } + else if (vt1_index > numTexCoords) return E_BAD_VERT_TEX_INDEX; + else --vt1_index; + + if (vt2_index < 0) + { + vt2_index += numTexCoords; + if (vt2_index < 0) return E_BAD_VERT_TEX_INDEX; + } + else if (vt2_index > numTexCoords) return E_BAD_VERT_TEX_INDEX; + else --vt2_index; + + if (vt3_index < 0) + { + vt3_index += numTexCoords; + if (vt3_index < 0) return E_BAD_VERT_TEX_INDEX; + } + else if (vt3_index > numTexCoords) return E_BAD_VERT_TEX_INDEX; + else --vt3_index; + + + // assigning wedge texture coordinates + // ----------------------------------- + Material material = materials[currentMaterialIdx]; + + TexCoord t = texCoords[vt1_index]; + (*fi).WT(0).u() = t.u; + (*fi).WT(0).v() = t.v; + (*fi).WT(0).n() = material.textureIdx; + + t = texCoords[vt2_index]; + (*fi).WT(1).u() = t.u; + (*fi).WT(1).v() = t.v; + (*fi).WT(1).n() = material.textureIdx; + + t = texCoords[vt3_index]; + (*fi).WT(2).u() = t.u; + (*fi).WT(2).v() = t.v; + (*fi).WT(2).n() = material.textureIdx; + } + + // verifying validity of vertex indices + // ------------------------------------ + if (v1_index < 0) + { + v1_index += numVertices; + if (v1_index < 0) return E_BAD_VERT_INDEX; + } + else if (v1_index > numVertices) return E_BAD_VERT_INDEX; + else v1_index--; // since index starts from 1 instead of 0 + + if (v2_index < 0) + { + v2_index += numVertices; + if (v2_index < 0) return E_BAD_VERT_INDEX; + } + else if (v2_index > numVertices) return E_BAD_VERT_INDEX; + else v2_index--; // since index starts from 1 instead of 0 + + if (v3_index < 0) + { + v3_index += numVertices; + if (v3_index < 0) return E_BAD_VERT_INDEX; + } + else if (v3_index > numVertices) return E_BAD_VERT_INDEX; + else v3_index--; // since index starts from 1 instead of 0 + + if ((v1_index == v2_index) || + (v1_index == v3_index) || + (v2_index == v3_index)) + result = E_VERTICES_WITH_SAME_IDX_IN_FACE; + + // assigning face vertices + // ----------------------- + (*fi).V(0) = &(m.vert[ v1_index ]); + (*fi).V(1) = &(m.vert[ v2_index ]); + (*fi).V(2) = &(m.vert[ v3_index ]); + + // assigning face normal + // --------------------- + if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) + { + // verifying validity of vertex normal indices + // ------------------------------------------- + if (vn1_index < 0) + { + vn1_index += numVNormals; + if (vn1_index < 0) return E_BAD_VERT_NORMAL_INDEX; + } + else if (vn1_index > numVNormals) return E_BAD_VERT_NORMAL_INDEX; + else vn1_index--; + + if (vn2_index < 0) + { + vn2_index += numVNormals; + if (vn2_index < 0) return E_BAD_VERT_NORMAL_INDEX; + } + else if (vn2_index > numVNormals) return E_BAD_VERT_NORMAL_INDEX; + else vn2_index--; + + if (vn3_index < 0) + { + vn3_index += numVNormals; + if (vn3_index < 0) return E_BAD_VERT_NORMAL_INDEX; + } + else if (vn3_index > numVNormals) return E_BAD_VERT_NORMAL_INDEX; + else vn3_index--; + + + // face normal is computed as an average of wedge normals + CoordType n = (normals[vn1_index] + normals[vn2_index] + normals[vn3_index]); + n.Normalize(); + + (*fi).N() = n; + + (*fi).WN(0) = normals[vn1_index]; + (*fi).WN(1) = normals[vn2_index]; + (*fi).WN(2) = normals[vn3_index]; + } + else // computing face normal from position of face vertices + face::ComputeNormalizedNormal(*fi); + + // assigning face color + // -------------------- + Color4b faceColor; // we declare this outside code block since other + // triangles of this face will share the same color + if( oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) + { + Material material = materials[currentMaterialIdx]; + Point3f diffuseColor = material.diffuse; + unsigned char r = (unsigned char) (diffuseColor[0] * 255.0); + unsigned char g = (unsigned char) (diffuseColor[1] * 255.0); + unsigned char b = (unsigned char) (diffuseColor[2] * 255.0); + unsigned char alpha = (unsigned char) (material.alpha * 255.0); + faceColor = Color4b(r, g, b, alpha); + (*fi).C()[0] = faceColor[0]; + (*fi).C()[1] = faceColor[1]; + (*fi).C()[2] = faceColor[2]; + (*fi).C()[3] = faceColor[3]; + } + + ++fi; + ++numTriangles; + + int vertexesPerFace = tokens.size() -1; + int iVertex = 3; + while (iVertex < vertexesPerFace) // add other triangles + { + int v4_index; + int vt4_index; + int vn4_index; + + if (( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) && + ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) ) + { + std::string vertex; + std::string texcoord; + std::string normal; + + SplitVVTVNToken(tokens[++iVertex], vertex, texcoord, normal); + v4_index = atoi(vertex.c_str()); + vt4_index = atoi(texcoord.c_str()); + vn4_index = atoi(normal.c_str()); + } + else if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) + { + std::string vertex; + std::string texcoord; + + SplitVVTToken(tokens[++iVertex], vertex, texcoord); + v4_index = atoi(vertex.c_str()); + vt4_index = atoi(texcoord.c_str()); + } + else if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) + { + std::string vertex; + std::string normal; + + SplitVVNToken(tokens[++iVertex], vertex, normal); + v4_index = atoi(vertex.c_str()); + vn4_index = atoi(normal.c_str()); + } + else + v4_index = atoi(tokens[++iVertex].c_str()); + + // assigning wedge texture coordinates + // ----------------------------------- + if( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD ) + { + // verifying validity of texture coords index + // ------------------------------------------ + if (vt4_index < 0) + { + vt4_index += numTexCoords; + if (vt4_index < 0) return E_BAD_VERT_TEX_INDEX; + } + else if (vt4_index > numTexCoords) return E_BAD_VERT_TEX_INDEX; + else --vt4_index; + + + Material material = materials[currentMaterialIdx]; + TexCoord t = texCoords[vt1_index]; + (*fi).WT(0).u() = t.u; + (*fi).WT(0).v() = t.v; + (*fi).WT(0).n() = material.textureIdx; + + t = texCoords[vt3_index]; + (*fi).WT(1).u() = t.u; + (*fi).WT(1).v() = t.v; + (*fi).WT(1).n() = material.textureIdx; + + t = texCoords[vt4_index]; + (*fi).WT(2).u() = t.u; + (*fi).WT(2).v() = t.v; + (*fi).WT(2).n() = material.textureIdx; + + vt3_index = vt4_index; + } + + // verifying validity of vertex index + // ---------------------------------- + if (v4_index < 0) + { + v4_index += numVertices; + if (v4_index < 0) return E_BAD_VERT_INDEX; + } + else if (v4_index > numVertices) return E_BAD_VERT_INDEX; + else v4_index--; // since index starts from 1 instead of 0 + + if ((v1_index == v4_index) || + (v3_index == v4_index)) + result = E_VERTICES_WITH_SAME_IDX_IN_FACE; + + // assigning face vertices + // ----------------------- + (*fi).V(0) = &(m.vert[ v1_index ]); + (*fi).V(1) = &(m.vert[ v3_index ]); + (*fi).V(2) = &(m.vert[ v4_index ]); + + // assigning face normal + // --------------------- + if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) + { + // verifying validity of vertex normal index + // ----------------------------------------- + if (vn4_index < 0) + { + vn4_index += numVNormals; + if (vn4_index < 0) return E_BAD_VERT_NORMAL_INDEX; + } + else if (vn4_index > numVNormals) return E_BAD_VERT_NORMAL_INDEX; + else vn4_index--; + + + // face normal is computed as an average of wedge normals + CoordType n = (normals[vn1_index] + normals[vn3_index] + normals[vn4_index]); + n.Normalize(); + + (*fi).N() = n; + + (*fi).WN(0) = normals[vn1_index]; + (*fi).WN(1) = normals[vn3_index]; + (*fi).WN(2) = normals[vn4_index]; + + vn3_index = vn4_index; + } + else // computing face normal from position of face vertices + face::ComputeNormalizedNormal(*fi); + + // assigning face color + // -------------------- + if( oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) + { + (*fi).C()[0] = faceColor[0]; + (*fi).C()[1] = faceColor[1]; + (*fi).C()[2] = faceColor[2]; + (*fi).C()[3] = faceColor[3]; + } + + // A face polygon composed of more than three vertices is tringulated + // according to the following schema: + // v5 + // / \ + // / \ + // / \ + // v1------v4 + // |\ / + // | \ / + // | \ / + // v2---v3 + // + // As shown above, the 5 vertices polygon (v1,v2,v3,v4,v5) + // has been split into the triangles (v1,v2,v3), (v1,v3,v4) e (v1,v4,v5). + // This way vertex v1 becomes the common vertex of all newly generated + // triangles, and this may lead to the creation of very thin triangles. + + ++fi; + ++numTriangles; + + v3_index = v4_index; + } + + // callback invocation, abort loading process if the call returns false + if ((cb !=NULL) && (((numTriangles + numVertices)%100)==0) && !(*cb)(100.0f * (float)(numTriangles + numVertices)/(float)numVerticesPlusFaces, "Face Loading")) + return E_ABORTED; + } + else if (header.compare("mtllib")==0) // material library + { + // obtain the name of the file containing materials library + std::string materialFileName = tokens[1]; + if (!LoadMaterials( materialFileName.c_str(), materials, m.textures)) + result = E_MATERIAL_FILE_NOT_FOUND; + } + else if (header.compare("usemtl")==0) // material usage + { + std::string materialName = tokens[1]; + bool found = false; + unsigned i = 0; + while (!found && (i < materials.size())) + { + std::string currentMaterialName = materials[i].name; + if (currentMaterialName == materialName) + { + currentMaterialIdx = i; + found = true; + } + ++i; + } + + if (!found) + { + currentMaterialIdx = 0; + result = E_MATERIAL_NOT_FOUND; + } + } + // we simply ignore other situations + } + } + + return result; +} // end of Open + + + /*! + * Read the next valid line and parses it into "tokens", allowing + * the tokens to be read one at a time. + * \param stream The object providing the input stream + * \param tokens The "tokens" in the next line + */ + inline static const void TokenizeNextLine(std::ifstream &stream, std::vector< std::string > &tokens) + { + std::string line; + do + std::getline(stream, line, '\n'); + while ((line[0] == '#' || line.length()==0) && !stream.eof()); // skip comments and empty lines + + if ((line[0] == '#') || (line.length() == 0)) // can be true only on last line of file + return; + + size_t from = 0; + size_t to = 0; + size_t length = line.size(); + tokens.clear(); + do + { + while ((line[from]==' ' || line[from]=='\t') && from!=length) + from++; + if(from!=length) + { + to = from+1; + while (line[to]!=' ' && to!=length) + to++; + tokens.push_back(line.substr(from, to-from).c_str()); + from = to; + } + } + while (from tokens; + + int numVertices = 0; // stores the number of vertexes been read till now + int numTriangles = 0; // stores the number of triangular faces been read till now + + const int deltaPos = 100; + int currPos = 0; + int lastPos = currPos; + + // cycle till we encounter first face + while (!stream.eof()) + { + tokens.clear(); + header.clear(); + TokenizeNextLine(stream, tokens); + + if (tokens.size() > 0) + { + header = tokens[0]; + + if (header.compare("v")==0) + { + ++numVertices; + if (bUsingMaterial) bHasPerVertexColor = true; + } + else if (header.compare("f")==0) + { + numTriangles += (tokens.size() - 3); + std::string remainingText = tokens[1]; + + // we base our assumption on the fact that the way vertex data is + // referenced into faces must be consistent among the entire file + int charIdx = 0; + size_t length = remainingText.size(); + char c; + while((charIdx != length) && ((c = remainingText[charIdx])!='/') && (c != ' ')) + ++charIdx; + + if (c == '/') + { + ++charIdx; + if ((charIdx != length) && ((c = remainingText[charIdx])!='/')) + { + bHasPerWedgeTexCoord = true; + + ++charIdx; + while((charIdx != length) && ((c = remainingText[charIdx])!='/') && (c != ' ')) + ++charIdx; + + if (c == '/') + bHasPerWedgeNormal = true; + break; + } + else + { + bHasPerWedgeNormal = true; + break; + } + } + + if (bUsingMaterial) bHasPerFaceColor = true; + } + else if (header.compare("usemtl")==0) + bUsingMaterial = true; + } + + // callback invocation, abort loading process if the call returns false + if (oi.cb !=NULL) + { + currPos = stream.tellg(); + if ((currPos - lastPos) > deltaPos) + { + if (!(*oi.cb)((100 * currPos)/length, "Loading mask...")) + return false; + lastPos = currPos; + } + } + } + + // after the encounter of first face we avoid to do additional tests + while (!stream.eof()) + { + tokens.clear(); + header.clear(); + TokenizeNextLine(stream, tokens); + + if (tokens.size() > 0) + { + header = tokens[0]; + + if (header.compare("v")==0) + { + ++numVertices; + if (bUsingMaterial) bHasPerVertexColor = true; + } + else if (header.compare("f")==0) + { + numTriangles += (tokens.size() - 3); + if (bUsingMaterial) bHasPerFaceColor = true; + } + else if (header.compare("usemtl")==0) + bUsingMaterial = true; + } + + // callback invocation, abort loading process if the call returns false + if (oi.cb !=NULL) + { + currPos = stream.tellg(); + if ((currPos - lastPos) > deltaPos) + { + if (!(*oi.cb)((100 * currPos)/length, "Loading mask...")) + return false; + lastPos = currPos; + } + } + } + + int mask = 0; + + if (bHasPerWedgeTexCoord) + mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD; + if (bHasPerWedgeNormal) + mask |= vcg::tri::io::Mask::IOM_WEDGNORMAL; + if (bHasPerVertexColor) + mask |= vcg::tri::io::Mask::IOM_VERTCOLOR; + if (bHasPerFaceColor) + mask |= vcg::tri::io::Mask::IOM_FACECOLOR; + + oi.mask = mask; + oi.numVertices = numVertices; + oi.numTriangles = numTriangles; + + return true; + } + + + static bool LoadMaterials(const char * filename, std::vector &materials, std::vector &textures) + { + // assumes we are in the right directory + + std::ifstream stream(filename); + if (stream.fail()) + return false; + + std::vector< std::string > tokens; + std::string header; + + materials.clear(); + Material currentMaterial; + + bool first = true; + while (!stream.eof()) + { + tokens.clear(); + TokenizeNextLine(stream, tokens); + + if (tokens.size() > 0) + { + header.clear(); + header = tokens[0]; + + if (header.compare("newmtl")==0) + { + if (!first) + { + materials.push_back(currentMaterial); + currentMaterial = Material(); + } + else + first = false; + + strcpy(currentMaterial.name, tokens[1].c_str()); + } + else if (header.compare("Ka")==0) + { + float r = (float) atof(tokens[1].c_str()); + float g = (float) atof(tokens[2].c_str()); + float b = (float) atof(tokens[3].c_str()); + + currentMaterial.ambient = Point3f(r, g, b); + } + else if (header.compare("Kd")==0) + { + float r = (float) atof(tokens[1].c_str()); + float g = (float) atof(tokens[2].c_str()); + float b = (float) atof(tokens[3].c_str()); + + currentMaterial.diffuse = Point3f(r, g, b); + } + else if (header.compare("Ks")==0) + { + float r = (float) atof(tokens[1].c_str()); + float g = (float) atof(tokens[2].c_str()); + float b = (float) atof(tokens[3].c_str()); + + currentMaterial.specular = Point3f(r, g, b); + } + else if ( (header.compare("d")==0) || + (header.compare("Tr")==0) ) // alpha + { + currentMaterial.alpha = (float) atof(tokens[1].c_str()); + } + else if (header.compare("Ns")==0) // shininess + { + currentMaterial.shininess = atoi(tokens[1].c_str()); + } + else if (header.compare("illum")==0) // specular illumination on/off + { + int illumination = atoi(tokens[1].c_str()); + currentMaterial.bSpecular = (illumination == 2); + } + else if (header.compare("map_Kd")==0) // texture name + { + std::string textureName = tokens[1]; + strcpy(currentMaterial.textureFileName, textureName.c_str()); + + // adding texture name into textures vector (if not already present) + // avoid adding the same name twice + bool found = false; + unsigned size = textures.size(); + unsigned j = 0; + while (!found && (j < size)) + { + if (textureName.compare(textures[j])==0) + { + currentMaterial.textureIdx = (int)j; + found = true; + } + ++j; + } + if (!found) + { + textures.push_back(textureName); + currentMaterial.textureIdx = (int)size; + } + } + // we simply ignore other situations + } + } + materials.push_back(currentMaterial); // add last read material + + stream.close(); + + return true; + } + +}; // end class +} // end Namespace tri +} // end Namespace io +} // end Namespace vcg + +#endif // ndef __VCGLIB_IMPORT_OBJ \ No newline at end of file diff --git a/wrap/io_trimesh/io_material.h b/wrap/io_trimesh/io_material.h new file mode 100644 index 00000000..9c5ef0c0 --- /dev/null +++ b/wrap/io_trimesh/io_material.h @@ -0,0 +1,136 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +/**************************************************************************** + History + + $Log: not supported by cvs2svn $ + Revision 1.1 2006/02/16 19:28:36 fmazzant + transfer of Export_3ds.h, Export_obj.h, Io_3ds_obj_material.h from Meshlab to vcg + + Revision 1.1 2006/02/06 11:04:40 fmazzant + added file material.h. it include struct Material, CreateNewMaterial(...) and MaterialsCompare(...) + + + ****************************************************************************/ + +#ifndef __VCGLIB_MATERIAL +#define __VCGLIB_MATERIAL + +namespace vcg { +namespace tri { +namespace io { + + /* + structures material + */ + struct Material + { + unsigned int index;//index of material + + Point3f Ka;//ambient + Point3f Kd;//diffuse + Point3f Ks;//specular + + float d;//alpha + float Tr;//alpha + + int illum;//specular illumination + float Ns; + + std::string map_Kd; //filename texture + }; + + + template + class Materials + { + public: + typedef typename SaveMeshType::FaceIterator FaceIterator; + typedef typename SaveMeshType::VertexIterator VertexIterator; + typedef typename SaveMeshType::VertexType VertexType; + + /* + creates a new meterial + */ + inline static int CreateNewMaterial(SaveMeshType &m, std::vector &materials, unsigned int index, FaceIterator &fi) + { + unsigned char r = (*fi).C()[0]; + unsigned char g = (*fi).C()[1]; + unsigned char b = (*fi).C()[2]; + unsigned char alpha = (*fi).C()[3]; + + Point3f diffuse = Point3f((float)r/255.0f,(float)g/255.0f,(float)b/255.0f);//diffuse + float Tr = (float)alpha/255.0f;//alpha + + int illum = 2; //default not use Ks! + float ns = 0.0; //default + + Material mtl; + + mtl.index = index;//index of materials + mtl.Ka = Point3f(0.2f,0.2f,0.2f);//ambient + mtl.Kd = diffuse;//diffuse + mtl.Ks = Point3f(1.0f,1.0f,1.0f);//specular + mtl.Tr = Tr;//alpha + mtl.Ns = ns; + mtl.illum = illum;//illumination + + if(m.textures.size() && (*fi).WT(0).n() >=0 ) + mtl.map_Kd = m.textures[(*fi).WT(0).n()]; + else + mtl.map_Kd = ""; + + int i = -1; + if((i = MaterialsCompare(materials,mtl)) == -1) + { + materials.push_back(mtl); + return materials.size(); + } + return i; + } + + /* + returns the index of the material if it exists inside the list of the materials, + otherwise it returns -1. + */ + inline static int MaterialsCompare(std::vector &materials, Material mtl) + { + for(int i=0;i