Improved management of fauxbit for quad and polygonal meshes in OBJ (did not set the high level polygonal bit) and OFF (wrong faux bits for polygonal faces with more than 4 sides)

This commit is contained in:
Paolo Cignoni 2013-04-12 09:49:51 +00:00
parent 371ff46282
commit e77e13a8fe
2 changed files with 70 additions and 60 deletions

View File

@ -8,7 +8,7 @@
* \ * * \ *
* All rights reserved. * * All rights reserved. *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
@ -44,7 +44,7 @@ namespace vcg {
namespace tri { namespace tri {
namespace io { namespace io {
/** /**
This class encapsulate a filter for importing obj (Alias Wavefront) meshes. This class encapsulate a filter for importing obj (Alias Wavefront) meshes.
Warning: this code assume little endian (PC) architecture!!! Warning: this code assume little endian (PC) architecture!!!
*/ */
@ -74,7 +74,7 @@ namespace vcg {
} }
/// It returns a bit mask describing the field preesnt in the ply file /// It returns a bit mask describing the field preesnt in the ply file
int mask; int mask;
/// a Simple callback that can be used for long obj parsing. /// 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...) // it returns the current position, and formats a string with a description of what th efunction is doing (loading vertexes, faces...)
@ -82,7 +82,7 @@ namespace vcg {
/// number of vertices /// number of vertices
int numVertices; int numVertices;
/// number of faces (the number of triangles could be /// number of faces (the number of triangles could be
/// larger in presence of polygonal faces /// larger in presence of polygonal faces
int numFaces; int numFaces;
/// number of texture coords indexes /// number of texture coords indexes
@ -102,7 +102,7 @@ namespace vcg {
// short attr; // material index // short attr; // material index
//}; //};
struct ObjIndexedFace struct ObjIndexedFace
{ {
void set(const int & num){v.resize(num);n.resize(num); t.resize(num);} void set(const int & num){v.resize(num);n.resize(num); t.resize(num);}
std::vector<int> v; std::vector<int> v;
std::vector<int> n; std::vector<int> n;
@ -146,7 +146,7 @@ namespace vcg {
// to check if a given error is critical or not. // to check if a given error is critical or not.
static bool ErrorCritical(int err) static bool ErrorCritical(int err)
{ {
if(err<0x00A && err>=0) return false; if(err<0x00A && err>=0) return false;
return true; return true;
} }
@ -169,7 +169,7 @@ namespace vcg {
"No face field found", // 9 "No face field found", // 9
"Vertex statement with less than 3 coords", // 10 "Vertex statement with less than 3 coords", // 10
"Texture coords statement with less than 2 coords", // 11 "Texture coords statement with less than 2 coords", // 11
"Vertex normal statement with less than 3 coords", // 12 "Vertex normal statement with less than 3 coords", // 12
"Face with less than 3 vertices", // 13 "Face with less than 3 vertices", // 13
"Bad vertex index in face", // 14 "Bad vertex index in face", // 14
"Bad texture coords index in face", // 15 "Bad texture coords index in face", // 15
@ -184,7 +184,7 @@ namespace vcg {
else return obj_error_msg[error]; else return obj_error_msg[error];
}; };
// Helper functions that checks the range of indexes // Helper functions that checks the range of indexes
// putting them in the correct range if less than zero (as in the obj style) // putting them in the correct range if less than zero (as in the obj style)
static bool GoodObjIndex(int &index, const int maxVal) static bool GoodObjIndex(int &index, const int maxVal)
@ -248,7 +248,7 @@ namespace vcg {
std::string header; std::string header;
short currentMaterialIdx = 0; // index of current material into materials vector short currentMaterialIdx = 0; // index of current material into materials vector
Color4b currentColor=Color4b::LightGray; // we declare this outside code block since other Color4b currentColor=Color4b::LightGray; // we declare this outside code block since other
// triangles of this face will share the same color // triangles of this face will share the same color
Material defaultMaterial; // default material: white Material defaultMaterial; // default material: white
@ -265,7 +265,7 @@ namespace vcg {
VertexIterator vi = vcg::tri::Allocator<OpenMeshType>::AddVertices(m,oi.numVertices); VertexIterator vi = vcg::tri::Allocator<OpenMeshType>::AddVertices(m,oi.numVertices);
//FaceIterator fi = Allocator<OpenMeshType>::AddFaces(m,oi.numFaces); //FaceIterator fi = Allocator<OpenMeshType>::AddFaces(m,oi.numFaces);
std::vector<Color4b> vertexColorVector; std::vector<Color4b> vertexColorVector;
ObjIndexedFace ff; ObjIndexedFace ff;
const char *loadingStr = "Loading"; const char *loadingStr = "Loading";
while (!stream.eof()) while (!stream.eof())
{ {
@ -337,7 +337,7 @@ namespace vcg {
CoordType n; CoordType n;
n[0] = (ScalarType) atof(tokens[1].c_str()); n[0] = (ScalarType) atof(tokens[1].c_str());
n[1] = (ScalarType) atof(tokens[2].c_str()); n[1] = (ScalarType) atof(tokens[2].c_str());
n[2] = (ScalarType) atof(tokens[3].c_str()); n[2] = (ScalarType) atof(tokens[3].c_str());
normals.push_back(n); normals.push_back(n);
numVNormals++; numVNormals++;
@ -416,6 +416,8 @@ namespace vcg {
GoodObjIndex(indexTVect[pi],oi.numTexCoords); GoodObjIndex(indexTVect[pi],oi.numTexCoords);
polygonVect[0][pi].Import(m.vert[indexVVect[pi]].cP()); polygonVect[0][pi].Import(m.vert[indexVVect[pi]].cP());
} }
if(vertexesPerFace>3)
oi.mask |= Mask::IOM_BITPOLYGONAL;
if(vertexesPerFace<5) if(vertexesPerFace<5)
InternalFanTessellator(polygonVect, indexTriangulatedVect); InternalFanTessellator(polygonVect, indexTriangulatedVect);
@ -463,7 +465,7 @@ namespace vcg {
{ // verifying validity of texture coords indices { // verifying validity of texture coords indices
bool invalid = false; bool invalid = false;
for(int i=0;i<3;i++) for(int i=0;i<3;i++)
if(!GoodObjIndex(ff.t[i],oi.numTexCoords)) if(!GoodObjIndex(ff.t[i],oi.numTexCoords))
{ {
//return E_BAD_VERT_TEX_INDEX; //return E_BAD_VERT_TEX_INDEX;
invalid = true; invalid = true;
@ -882,7 +884,7 @@ namespace vcg {
lineCount++; lineCount++;
std::getline(stream, line); std::getline(stream, line);
totRead+=line.size(); totRead+=line.size();
if(oi.cb && (lineCount%1000)==0) if(oi.cb && (lineCount%1000)==0)
(*oi.cb)( (int)(100.0*(float(totRead))/float(length)), "Loading mask..."); (*oi.cb)( (int)(100.0*(float(totRead))/float(length)), "Loading mask...");
if(line.size()>2) if(line.size()>2)
{ {
@ -908,17 +910,17 @@ namespace vcg {
} }
} }
oi.mask = 0; oi.mask = 0;
if (oi.numTexCoords) if (oi.numTexCoords)
{ {
if (oi.numTexCoords==oi.numVertices) if (oi.numTexCoords==oi.numVertices)
oi.mask |= vcg::tri::io::Mask::IOM_VERTTEXCOORD; oi.mask |= vcg::tri::io::Mask::IOM_VERTTEXCOORD;
oi.mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD; oi.mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;
// Usually if you have tex coords you also have materials // Usually if you have tex coords you also have materials
oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
} }
if(bHasPerFaceColor) oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; if(bHasPerFaceColor) oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
if(bHasPerVertexColor) oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR; if(bHasPerVertexColor) oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR;
if (bHasNormals) { if (bHasNormals) {
if (oi.numNormals == oi.numVertices) if (oi.numNormals == oi.numVertices)
oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;
@ -975,7 +977,7 @@ namespace vcg {
first = false; first = false;
//strcpy(currentMaterial.name, tokens[1].c_str()); //strcpy(currentMaterial.name, tokens[1].c_str());
if(tokens.size() < 2) if(tokens.size() < 2)
return false; return false;
currentMaterial.materialName=tokens[1]; currentMaterial.materialName=tokens[1];
} }
else if (header.compare("Ka")==0) else if (header.compare("Ka")==0)
@ -1015,7 +1017,7 @@ namespace vcg {
return false; return false;
currentMaterial.Tr = (float) atof(tokens[1].c_str()); currentMaterial.Tr = (float) atof(tokens[1].c_str());
} }
else if (header.compare("Ns")==0) // shininess else if (header.compare("Ns")==0) // shininess
{ {
if (tokens.size() < 2) if (tokens.size() < 2)
return false; return false;

View File

@ -8,7 +8,7 @@
* \ * * \ *
* All rights reserved. * * All rights reserved. *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
@ -37,7 +37,7 @@ namespace vcg
{ {
// /** \addtogroup */ // /** \addtogroup */
// /* @{ */ // /* @{ */
/** /**
This class encapsulate a filter for importing OFF meshes. This class encapsulate a filter for importing OFF meshes.
A basic description of the OFF file format can be found at http://www.geomview.org/docs/html/geomview_41.html A basic description of the OFF file format can be found at http://www.geomview.org/docs/html/geomview_41.html
*/ */
@ -58,7 +58,7 @@ namespace vcg
// OFF codes // OFF codes
enum OFFCodes {NoError=0, CantOpen, InvalidFile, enum OFFCodes {NoError=0, CantOpen, InvalidFile,
InvalidFile_MissingOFF, InvalidFile_MissingOFF,
UnsupportedFormat, ErrorNotTriangularFace,ErrorHighDimension,ErrorDegenerateFace}; UnsupportedFormat, ErrorNotTriangularFace,ErrorHighDimension,ErrorDegenerateFace};
/*! /*!
* Standard call for knowing the meaning of an error code * Standard call for knowing the meaning of an error code
@ -71,9 +71,9 @@ namespace vcg
{ {
"No errors", "Can't open file", "Invalid file", "No errors", "Can't open file", "Invalid file",
"Invalid file: OFF file should have in the first line the OFF keyword as a first token", "Invalid file: OFF file should have in the first line the OFF keyword as a first token",
"Unsupported format", "Face with more than 3 vertices","File with high dimensional vertexes are not supported", "Error Degenerate Face with less than 3 vertices" }; "Unsupported format", "Face with more than 3 vertices","File with high dimensional vertexes are not supported", "Error Degenerate Face with less than 3 vertices" };
if(message_code>6 || message_code<0) if(message_code>6 || message_code<0)
return "Unknown error"; return "Unknown error";
else else
return error_msg[message_code]; return error_msg[message_code];
@ -90,9 +90,9 @@ namespace vcg
{ {
// To obtain the loading mask all the file must be parsed // To obtain the loading mask all the file must be parsed
// to distinguish between per-vertex and per-face color attribute. // to distinguish between per-vertex and per-face color attribute.
loadmask=0; loadmask=0;
MESH_TYPE dummyMesh; MESH_TYPE dummyMesh;
return (Open(dummyMesh, filename, loadmask)==NoError); return (Open(dummyMesh, filename, loadmask)==NoError);
} }
static int Open(MESH_TYPE &mesh, const char *filename,CallBackPos *cb=0) static int Open(MESH_TYPE &mesh, const char *filename,CallBackPos *cb=0)
@ -109,7 +109,7 @@ namespace vcg
* \return the operation result * \return the operation result
*/ */
static int Open(MESH_TYPE &mesh, const char *filename, int &loadmask, static int Open(MESH_TYPE &mesh, const char *filename, int &loadmask,
CallBackPos *cb=0) CallBackPos *cb=0)
{ {
std::ifstream stream(filename); std::ifstream stream(filename);
if (stream.fail()) if (stream.fail())
@ -129,14 +129,14 @@ namespace vcg
[ST][C][N][4][n]OFF # Header keyword [ST][C][N][4][n]OFF # Header keyword
[Ndim] # Space dimension of vertices, present only if nOFF [Ndim] # Space dimension of vertices, present only if nOFF
NVertices NFaces NEdges # NEdges not used or checked NVertices NFaces NEdges # NEdges not used or checked
x[0] y[0] z[0] # Vertices, possibly with normals, colors, and/or texture coordinates, in that order, if the prefixes N, C, ST are present. x[0] y[0] z[0] # Vertices, possibly with normals, colors, and/or texture coordinates, in that order, if the prefixes N, C, ST are present.
# If 4OFF, each vertex has 4 components including a final homogeneous component. # If 4OFF, each vertex has 4 components including a final homogeneous component.
# If nOFF, each vertex has Ndim components. # If nOFF, each vertex has Ndim components.
# If 4nOFF, each vertex has Ndim+1 components. # If 4nOFF, each vertex has Ndim+1 components.
... ...
x[NVertices-1] y[NVertices-1] z[NVertices-1] x[NVertices-1] y[NVertices-1] z[NVertices-1]
# Faces # Faces
# Nv = # vertices on this face # Nv = # vertices on this face
# v[0] ... v[Nv-1]: vertex indices # v[0] ... v[Nv-1]: vertex indices
@ -147,7 +147,7 @@ namespace vcg
# nothing: default # nothing: default
# integer: colormap index # integer: colormap index
# 3 or 4 integers: RGB[A] values 0..255 # 3 or 4 integers: RGB[A] values 0..255
# 3 or 4 floats: RGB[A] values 0..1 # 3 or 4 floats: RGB[A] values 0..1
*/ */
std::string header = tokens[0]; std::string header = tokens[0];
if (header.rfind("OFF") != std::basic_string<char>::npos) if (header.rfind("OFF") != std::basic_string<char>::npos)
@ -163,11 +163,11 @@ namespace vcg
} }
else return InvalidFile_MissingOFF; else return InvalidFile_MissingOFF;
// If the file is slightly malformed and it has nvert and nface AFTER the OFF string instead of in the next line // If the file is slightly malformed and it has nvert and nface AFTER the OFF string instead of in the next line
// we manage it here... // we manage it here...
if(tokens.size()==1) TokenizeNextLine(stream, tokens); if(tokens.size()==1) TokenizeNextLine(stream, tokens);
else tokens.erase(tokens.begin(),tokens.begin()+1); else tokens.erase(tokens.begin(),tokens.begin()+1);
// Update loading mask // Update loading mask
/////////////////////////////////////// ///////////////////////////////////////
@ -178,11 +178,11 @@ namespace vcg
if (isColorDefined) { loadmask |= Mask::IOM_VERTCOLOR;loadmask |= Mask::IOM_FACECOLOR;} if (isColorDefined) { loadmask |= Mask::IOM_VERTCOLOR;loadmask |= Mask::IOM_FACECOLOR;}
//if(onlyMaskFlag) return NoError; //if(onlyMaskFlag) return NoError;
mesh.Clear(); mesh.Clear();
// check on next 2 lines to detect corrupted files // check on next 2 lines to detect corrupted files
if(tokens.size() < 3) if(tokens.size() < 3)
return InvalidFile; return InvalidFile;
@ -208,7 +208,7 @@ namespace vcg
for (unsigned int i=0; i<nVertices; i++, v_iter++) for (unsigned int i=0; i<nVertices; i++, v_iter++)
{ {
if (cb && (i%1000)==0) if (cb && (i%1000)==0)
cb(i*50/nVertices, "Vertex Loading"); cb(i*50/nVertices, "Vertex Loading");
// Read 3 vertex coordinates // Read 3 vertex coordinates
@ -280,20 +280,20 @@ namespace vcg
{ {
// read RGB color // read RGB color
if (tokens[k].find(".") == size_t(-1))// if it is a float there is a dot if (tokens[k].find(".") == size_t(-1))// if it is a float there is a dot
{ {
// integers // integers
unsigned char r = unsigned char r =
static_cast<unsigned char>(atoi(tokens[k].c_str())); static_cast<unsigned char>(atoi(tokens[k].c_str()));
unsigned char g = unsigned char g =
static_cast<unsigned char>(atoi(tokens[k+1].c_str())); static_cast<unsigned char>(atoi(tokens[k+1].c_str()));
unsigned char b = unsigned char b =
static_cast<unsigned char>(atoi(tokens[k+2].c_str())); static_cast<unsigned char>(atoi(tokens[k+2].c_str()));
vcg::Color4b color(r, g, b, 255); vcg::Color4b color(r, g, b, 255);
(*v_iter).C().Import(color); (*v_iter).C().Import(color);
} }
else else
{ {
// floats // floats
float r = static_cast<float>(atof(tokens[k].c_str())); float r = static_cast<float>(atof(tokens[k].c_str()));
float g = static_cast<float>(atof(tokens[k+1].c_str())); float g = static_cast<float>(atof(tokens[k+1].c_str()));
@ -307,13 +307,13 @@ namespace vcg
{ {
// read RGBA color // read RGBA color
if (tokens[k].find(".") == size_t(-1)) if (tokens[k].find(".") == size_t(-1))
{ {
// integers // integers
unsigned char r = unsigned char r =
static_cast<unsigned char>(atoi(tokens[k].c_str())); static_cast<unsigned char>(atoi(tokens[k].c_str()));
unsigned char g = unsigned char g =
static_cast<unsigned char>(atoi(tokens[k+1].c_str())); static_cast<unsigned char>(atoi(tokens[k+1].c_str()));
unsigned char b = unsigned char b =
static_cast<unsigned char>(atoi(tokens[k+2].c_str())); static_cast<unsigned char>(atoi(tokens[k+2].c_str()));
unsigned char a = unsigned char a =
static_cast<unsigned char>(atoi(tokens[k+3].c_str())); static_cast<unsigned char>(atoi(tokens[k+3].c_str()));
@ -322,7 +322,7 @@ namespace vcg
(*v_iter).C().Import(color); (*v_iter).C().Import(color);
} }
else else
{ {
// floats // floats
float r = static_cast<float>(atof(tokens[k].c_str())); float r = static_cast<float>(atof(tokens[k].c_str()));
float g = static_cast<float>(atof(tokens[k+1].c_str())); float g = static_cast<float>(atof(tokens[k+1].c_str()));
@ -410,7 +410,7 @@ namespace vcg
nFaces += trigs; nFaces += trigs;
Allocator<MESH_TYPE>::AddFaces(mesh, trigs); Allocator<MESH_TYPE>::AddFaces(mesh, trigs);
std::vector<int> vertIndices(vert_per_face); std::vector<int> vertIndices(vert_per_face);
std::vector<vcg::Point3f > polygonVect(vert_per_face); // vec of polygon loops used for the triangulation of polygonal face std::vector<vcg::Point3f > polygonVect(vert_per_face); // vec of polygon loops used for the triangulation of polygonal face
for (int j=0; j < vert_per_face; j++) for (int j=0; j < vert_per_face; j++)
{ {
if (k == tokens.size()) // if EOL // Go to next line when needed if (k == tokens.size()) // if EOL // Go to next line when needed
@ -420,7 +420,7 @@ namespace vcg
k = 0; k = 0;
} }
vertIndices[j] = atoi(tokens[k].c_str()); vertIndices[j] = atoi(tokens[k].c_str());
polygonVect[j].Import<ScalarType> (mesh.vert[ vertIndices[j] ].P()); polygonVect[j].Import<ScalarType> (mesh.vert[ vertIndices[j] ].P());
k++; k++;
} }
if(vert_per_face==4) if(vert_per_face==4)
@ -449,7 +449,7 @@ namespace vcg
{ {
std::vector<int> indexTriangulatedVect; std::vector<int> indexTriangulatedVect;
// TessellatePlanarPolygon3(polygonVect,indexTriangulatedVect); // TessellatePlanarPolygon3(polygonVect,indexTriangulatedVect);
std::vector< std::vector<Point3f> > loopVect; std::vector< std::vector<Point3f> > loopVect;
loopVect.push_back(polygonVect); loopVect.push_back(polygonVect);
#ifdef __gl_h_ #ifdef __gl_h_
//qDebug("OK: using opengl tessellation for a polygon of %i vertices",vertexesPerFace); //qDebug("OK: using opengl tessellation for a polygon of %i vertices",vertexesPerFace);
@ -463,6 +463,14 @@ namespace vcg
mesh.face[f+j/3].V(0) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+0] ] ]); mesh.face[f+j/3].V(0) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+0] ] ]);
mesh.face[f+j/3].V(1) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+1] ] ]); mesh.face[f+j/3].V(1) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+1] ] ]);
mesh.face[f+j/3].V(2) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+2] ] ]); mesh.face[f+j/3].V(2) = &(mesh.vert[ vertIndices[ indexTriangulatedVect[j+2] ] ]);
// To correctly set Faux edges we have to clear the faux bit for all the edges that do not correspond to consecutive vertices
// Consecutivity is in the space of the index of the polygon.
for(int qq=0;qq<3;++qq)
{
if( (indexTriangulatedVect[j+qq]+1)%indexTriangulatedVect.size() == indexTriangulatedVect[j+(qq+1)%3])
mesh.face[f+j/3].ClearF(qq);
else mesh.face[f+j/3].SetF(qq);
}
} }
} }
f+=trigs; f+=trigs;
@ -471,11 +479,11 @@ namespace vcg
// NOTE: It is assumed that colored face takes exactly one text line // NOTE: It is assumed that colored face takes exactly one text line
// (otherwise it is impossible to parse color information since // (otherwise it is impossible to parse color information since
// color components can vary) // color components can vary)
size_t color_elements = tokens.size() - vert_per_face-1; size_t color_elements = tokens.size() - vert_per_face-1;
isColorDefined |= (color_elements>0); isColorDefined |= (color_elements>0);
if(isColorDefined) loadmask |= Mask::IOM_FACECOLOR; if(isColorDefined) loadmask |= Mask::IOM_FACECOLOR;
if( (color_elements>0) && tri::HasPerFaceColor(mesh) ) if( (color_elements>0) && tri::HasPerFaceColor(mesh) )
{ {
@ -551,21 +559,21 @@ namespace vcg
} // end Open } // end Open
protected: protected:
/*! /*!
* Read the next valid line and parses it into "tokens", allowing the tokens to be read one at a time. * 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 stream The object providing the input stream
* \param tokens The "tokens" in the next line * \param tokens The "tokens" in the next line
*/ */
inline static void TokenizeNextLine(std::ifstream &stream, std::vector< std::string > &tokens) inline static void TokenizeNextLine(std::ifstream &stream, std::vector< std::string > &tokens)
{ {
std::string line; std::string line;
do do
std::getline(stream, line, '\n'); std::getline(stream, line, '\n');
while (line[0] == '#' || line.length()==0 || line[0]=='\r'); while (line[0] == '#' || line.length()==0 || line[0]=='\r');
size_t from = 0; size_t from = 0;
size_t to = 0; size_t to = 0;
size_t length = line.size(); size_t length = line.size();
tokens.clear(); tokens.clear();
@ -590,9 +598,9 @@ namespace vcg
* \param i the color index * \param i the color index
* \return the corresponding <CODE>vcg::Color4f</CODE> color * \return the corresponding <CODE>vcg::Color4f</CODE> color
*/ */
static const vcg::Color4f ColorMap(int i) static const vcg::Color4f ColorMap(int i)
{ {
static const float colorMap[148][4] = static const float colorMap[148][4] =
{ {
{ 1.0f, 1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f },
{ 1.0f, 1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f },