You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1301 lines
51 KiB
1301 lines
51 KiB
/**************************************************************************** |
|
* VCGLib o o * |
|
* Visual and Computer Graphics Library o o * |
|
* _ O _ * |
|
* Copyright(C) 2004-2016 \/)\/ * |
|
* 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. * |
|
* * |
|
****************************************************************************/ |
|
#ifndef __VCGLIB_IMPORTERPLY |
|
#define __VCGLIB_IMPORTERPLY |
|
|
|
#include <stddef.h> |
|
#include<wrap/callback.h> |
|
#include<wrap/ply/plylib.h> |
|
#include<wrap/io_trimesh/io_mask.h> |
|
#include<wrap/io_trimesh/io_ply.h> |
|
#include<vcg/complex/algorithms/create/platonic.h> |
|
|
|
namespace vcg { |
|
namespace tri { |
|
namespace io { |
|
|
|
template <class TYPE> |
|
int PlyType () { return 0;} |
|
|
|
|
|
// 10/6/05 Cignoni this specialization must be inlined becouse otherwise if we include this |
|
// .h in two different cpp we should get a double definition error during linking |
|
|
|
template <> inline int PlyType <float >() { return ply::T_FLOAT; } |
|
template <> inline int PlyType <double>() { return ply::T_DOUBLE; } |
|
template <> inline int PlyType <int >() { return ply::T_INT; } |
|
template <> inline int PlyType <short >() { return ply::T_SHORT; } |
|
template <> inline int PlyType <unsigned char >() { return ply::T_UCHAR; } |
|
|
|
/** |
|
This class encapsulate a filter for opening ply meshes. |
|
The ply file format is quite extensible... |
|
*/ |
|
template <class OpenMeshType> |
|
class ImporterPLY |
|
{ |
|
public: |
|
|
|
typedef ::vcg::ply::PropDescriptor PropDescriptor ; |
|
typedef typename OpenMeshType::VertexPointer VertexPointer; |
|
typedef typename OpenMeshType::ScalarType ScalarType; |
|
typedef typename OpenMeshType::VertexType VertexType; |
|
typedef typename VertexType::QualityType VertQualityType; |
|
typedef typename OpenMeshType::FaceType FaceType; |
|
typedef typename FaceType::QualityType FaceQualityType; |
|
typedef typename VertexType::TexCoordType::ScalarType TexScalarType; |
|
|
|
typedef typename OpenMeshType::VertexIterator VertexIterator; |
|
typedef typename OpenMeshType::FaceIterator FaceIterator; |
|
typedef typename OpenMeshType::EdgeIterator EdgeIterator; |
|
|
|
#define MAX_USER_DATA 256 |
|
// Auxiliary structure for reading ply files |
|
template<class S> |
|
struct LoadPly_FaceAux |
|
{ |
|
unsigned char size; |
|
int v[512]; |
|
int flags; |
|
S n[3]; |
|
S q; |
|
float texcoord[32]; |
|
unsigned char ntexcoord; |
|
int texcoordind; |
|
float colors[32]; |
|
unsigned char ncolors; |
|
|
|
unsigned char r; |
|
unsigned char g; |
|
unsigned char b; |
|
unsigned char a; |
|
|
|
unsigned char data[MAX_USER_DATA]; |
|
}; |
|
|
|
struct LoadPly_TristripAux |
|
{ |
|
int size; |
|
int *v; |
|
unsigned char data[MAX_USER_DATA]; |
|
}; |
|
|
|
struct LoadPly_EdgeAux |
|
{ |
|
int v1,v2; |
|
unsigned char data[MAX_USER_DATA]; |
|
}; |
|
|
|
// Yet another auxiliary data structure for loading some strange ply files |
|
// the original stanford range data... |
|
struct LoadPly_RangeGridAux { |
|
unsigned char num_pts; |
|
int pts[5]; |
|
}; |
|
|
|
|
|
// Auxiliary structure to load vertex data |
|
template<class S> |
|
struct LoadPly_VertAux |
|
{ |
|
S p[3]; |
|
S n[3]; |
|
int flags; |
|
S q; // the confidence |
|
float intensity; |
|
unsigned char r; |
|
unsigned char g; |
|
unsigned char b; |
|
unsigned char a; |
|
unsigned char data[MAX_USER_DATA]; |
|
float radius; |
|
float u,v,w; |
|
}; |
|
|
|
// Auxiliary structure to load the camera |
|
struct LoadPly_Camera |
|
{ |
|
float view_px; |
|
float view_py; |
|
float view_pz; |
|
float x_axisx; |
|
float x_axisy; |
|
float x_axisz; |
|
float y_axisx; |
|
float y_axisy; |
|
float y_axisz; |
|
float z_axisx; |
|
float z_axisy; |
|
float z_axisz; |
|
float focal; |
|
float scalex; |
|
float scaley; |
|
float centerx; |
|
float centery; |
|
int viewportx; |
|
int viewporty; |
|
float k1; |
|
float k2; |
|
float k3; |
|
float k4; |
|
}; |
|
|
|
#define _VERTDESC_LAST_ 34 |
|
static const PropDescriptor &VertDesc(int i) |
|
{ |
|
static const PropDescriptor pv[_VERTDESC_LAST_]={ |
|
/**** { elename, propname, storedtype1, memtype1, memoffset, */ |
|
/*00*/ {"vertex", "x", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,p),0,0,0,0,0 ,0}, |
|
/*01*/ {"vertex", "y", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,p) + sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/*02*/ {"vertex", "z", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,p) + 2*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/*03*/ {"vertex", "flags", ply::T_INT, ply::T_INT, offsetof(LoadPly_VertAux<ScalarType>,flags),0,0,0,0,0 ,0}, |
|
/*04*/ {"vertex", "quality", ply::T_FLOAT, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,q),0,0,0,0,0 ,0}, |
|
/*05*/ {"vertex", "red", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,r),0,0,0,0,0 ,0}, |
|
/*06*/ {"vertex", "green", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,g),0,0,0,0,0 ,0}, |
|
/*07*/ { "vertex", "blue", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,b),0,0,0,0,0 ,0}, |
|
/*08*/ { "vertex", "alpha", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,a),0,0,0,0,0 ,0}, |
|
/*09*/ {"vertex", "diffuse_red", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,r),0,0,0,0,0 ,0}, |
|
/*10*/ {"vertex", "diffuse_green", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,g),0,0,0,0,0 ,0}, |
|
/*11*/ {"vertex", "diffuse_blue", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,b),0,0,0,0,0 ,0}, |
|
/*12*/ {"vertex", "diffuse_alpha", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,a),0,0,0,0,0 ,0}, |
|
/*13*/ {"vertex", "confidence", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,q),0,0,0,0,0 ,0}, |
|
/*14*/ {"vertex", "nx", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,n) ,0,0,0,0,0 ,0}, |
|
/*15*/ {"vertex", "ny", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,n) + 1*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/*16*/ {"vertex", "nz", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,n) + 2*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/*17*/ {"vertex", "radius", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,radius),0,0,0,0,0 ,0}, |
|
/*18*/ {"vertex", "texture_u", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,u),0,0,0,0,0 ,0}, |
|
/*19*/ {"vertex", "texture_v", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,v),0,0,0,0,0 ,0}, |
|
/*20*/ {"vertex", "texture_w", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,w),0,0,0,0,0 ,0}, |
|
/*21*/ {"vertex", "intensity", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,intensity),0,0,0,0,0 ,0}, |
|
/*22*/ {"vertex", "s", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,u),0,0,0,0,0 ,0}, |
|
/*23*/ {"vertex", "t", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,v),0,0,0,0,0 ,0}, |
|
// DOUBLE |
|
/*24*/ {"vertex", "x", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,p),0,0,0,0,0 ,0}, |
|
/*25*/ {"vertex", "y", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,p) + sizeof(ScalarType) ,0,0,0,0,0 ,0}, |
|
/*26*/ {"vertex", "z", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,p) + 2*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/*27*/ {"vertex", "nx", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,n) ,0,0,0,0,0 ,0}, |
|
/*28*/ {"vertex", "ny", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,n) + 1*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/*29*/ {"vertex", "nz", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,n) + 2*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/*30*/ {"vertex", "radius", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,radius),0,0,0,0,0 ,0}, |
|
/*31*/ {"vertex", "quality", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,q),0,0,0,0,0 ,0}, |
|
/*32*/ {"vertex", "texture_u", ply::T_DOUBLE, PlyType<TexScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,u),0,0,0,0,0 ,0}, |
|
/*33*/ {"vertex", "texture_v", ply::T_DOUBLE, PlyType<TexScalarType>(), offsetof(LoadPly_VertAux<ScalarType>,v),0,0,0,0,0 ,0}, |
|
}; |
|
return pv[i]; |
|
} |
|
|
|
#define _FACEDESC_FIRST_ 13 // the first descriptor with possible vertex indices |
|
#define _FACEDESC_LAST_ 29 |
|
static const PropDescriptor &FaceDesc(int i) |
|
{ |
|
static const PropDescriptor qf[_FACEDESC_LAST_]= |
|
{ |
|
/* on file on memory on file on memory */ |
|
/* 0 */ {"face", "vertex_indices", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_UCHAR, ply::T_UCHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 1 */ {"face", "flags", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,flags), 0,0,0,0,0 ,0}, |
|
/* 2 */ {"face", "quality", ply::T_FLOAT, PlyType<ScalarType>(), offsetof(LoadPly_FaceAux<ScalarType>,q), 0,0,0,0,0 ,0}, |
|
/* 3 */ {"face", "texcoord", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_FaceAux<ScalarType>,texcoord), 1,0,ply::T_UCHAR, ply::T_UCHAR,offsetof(LoadPly_FaceAux<ScalarType>,ntexcoord) ,0}, |
|
/* 4 */ {"face", "color", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_FaceAux<ScalarType>,colors), 1,0,ply::T_UCHAR, ply::T_UCHAR,offsetof(LoadPly_FaceAux<ScalarType>,ncolors) ,0}, |
|
/* 5 */ {"face", "texnumber", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,texcoordind), 0,0,0,0,0 ,0}, |
|
/* 6 */ {"face", "red" , ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux<ScalarType>,r), 0,0,0,0,0 ,0}, |
|
/* 7 */ {"face", "green", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux<ScalarType>,g), 0,0,0,0,0 ,0}, |
|
/* 8 */ {"face", "blue", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux<ScalarType>,b), 0,0,0,0,0 ,0}, |
|
/* 9 */ {"face", "alpha", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux<ScalarType>,a), 0,0,0,0,0 ,0}, |
|
/* 10 */ {"face", "nx", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_FaceAux<ScalarType>,n) ,0,0,0,0,0 ,0}, |
|
/* 11 */ {"face", "ny", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_FaceAux<ScalarType>,n) + 1*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/* 12 */ {"face", "nz", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_FaceAux<ScalarType>,n) + 2*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/* 13 */ {"face", "vertex_index", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_UCHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 14 */ {"face", "vertex_index", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_CHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 15 */ {"face", "vertex_index", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_INT, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
|
|
/* 16 */ {"face", "vertex_indices", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_CHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 17 */ {"face", "vertex_indices", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_INT, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 18 */ {"face", "vertex_indices", ply::T_UINT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_UCHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 19 */ {"face", "vertex_indices", ply::T_UINT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_CHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 20 */ {"face", "vertex_indices", ply::T_UINT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_INT, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 21 */ {"face", "vertex_indices", ply::T_UINT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_USHORT,ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 22 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_CHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 23 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_UCHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
/* 24 */ {"face", "vertex_indices", ply::T_SHORT, ply::T_INT, offsetof(LoadPly_FaceAux<ScalarType>,v), 1,0,ply::T_INT, ply::T_CHAR,offsetof(LoadPly_FaceAux<ScalarType>,size) ,0}, |
|
// DOUBLE |
|
/* 25 */ {"face", "quality", ply::T_DOUBLE, PlyType<ScalarType>(), offsetof(LoadPly_FaceAux<ScalarType>,q), 0,0,0,0,0 ,0}, |
|
/* 26 */ {"face", "nx", ply::T_DOUBLE, PlyType<ScalarType>(),offsetof(LoadPly_FaceAux<ScalarType>,n) ,0,0,0,0,0 ,0}, |
|
/* 27 */ {"face", "ny", ply::T_DOUBLE, PlyType<ScalarType>(),offsetof(LoadPly_FaceAux<ScalarType>,n) + 1*sizeof(ScalarType),0,0,0,0,0 ,0}, |
|
/* 28 */ {"face", "nz", ply::T_DOUBLE, PlyType<ScalarType>(),offsetof(LoadPly_FaceAux<ScalarType>,n) + 2*sizeof(ScalarType),0,0,0,0,0 ,0} |
|
|
|
}; |
|
return qf[i]; |
|
} |
|
static const PropDescriptor &TristripDesc(int i) |
|
{ |
|
static const PropDescriptor qf[1]= |
|
{ |
|
{"tristrips","vertex_indices", ply::T_INT, ply::T_INT, offsetof(LoadPly_TristripAux,v), 1,1,ply::T_INT,ply::T_INT,offsetof(LoadPly_TristripAux,size) ,0}, |
|
}; |
|
return qf[i]; |
|
} |
|
|
|
static const PropDescriptor &EdgeDesc(int i) |
|
{ |
|
static const PropDescriptor qf[4]= |
|
{ |
|
{"edge","vertex1", ply::T_INT, ply::T_INT, offsetof(LoadPly_EdgeAux,v1), 0,0,0,0,0 ,0}, |
|
{"edge","vertex2", ply::T_INT, ply::T_INT, offsetof(LoadPly_EdgeAux,v2), 0,0,0,0,0 ,0}, |
|
{"edge","vertex1", ply::T_UINT, ply::T_INT, offsetof(LoadPly_EdgeAux,v1), 0,0,0,0,0 ,0}, |
|
{"edge","vertex2", ply::T_UINT, ply::T_INT, offsetof(LoadPly_EdgeAux,v2), 0,0,0,0,0 ,0}, |
|
}; |
|
return qf[i]; |
|
} |
|
|
|
// Descriptor for the Stanford Data Repository Range Maps. |
|
// In practice a grid with some invalid elements. Coords are saved only for good elements |
|
static const PropDescriptor &RangeDesc(int i) |
|
{ |
|
static const PropDescriptor range_props[1] = { |
|
{"range_grid","vertex_indices", ply::T_INT, ply::T_INT, offsetof(LoadPly_RangeGridAux,pts), 1, 0, ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_RangeGridAux,num_pts),0}, |
|
}; |
|
return range_props[i]; |
|
} |
|
|
|
|
|
static const PropDescriptor &CameraDesc(int i) |
|
{ |
|
static const PropDescriptor cad[23] = |
|
{ |
|
{"camera","view_px",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,view_px),0,0,0,0,0 ,0}, |
|
{"camera","view_py",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,view_py),0,0,0,0,0 ,0}, |
|
{"camera","view_pz",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,view_pz),0,0,0,0,0 ,0}, |
|
{"camera","x_axisx",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,x_axisx),0,0,0,0,0 ,0}, |
|
{"camera","x_axisy",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,x_axisy),0,0,0,0,0 ,0}, |
|
{"camera","x_axisz",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,x_axisz),0,0,0,0,0 ,0}, |
|
{"camera","y_axisx",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,y_axisx),0,0,0,0,0 ,0}, |
|
{"camera","y_axisy",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,y_axisy),0,0,0,0,0 ,0}, |
|
{"camera","y_axisz",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,y_axisz),0,0,0,0,0 ,0}, |
|
{"camera","z_axisx",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,z_axisx),0,0,0,0,0 ,0}, |
|
{"camera","z_axisy",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,z_axisy),0,0,0,0,0 ,0}, |
|
{"camera","z_axisz",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,z_axisz),0,0,0,0,0 ,0}, |
|
{"camera","focal" ,ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,focal ),0,0,0,0,0 ,0}, |
|
{"camera","scalex" ,ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,scalex ),0,0,0,0,0 ,0}, |
|
{"camera","scaley" ,ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,scaley ),0,0,0,0,0 ,0}, |
|
{"camera","centerx",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,centerx),0,0,0,0,0 ,0}, |
|
{"camera","centery",ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,centery),0,0,0,0,0 ,0}, |
|
{"camera","viewportx",ply::T_INT,ply::T_INT ,offsetof(LoadPly_Camera,viewportx),0,0,0,0,0 ,0}, |
|
{"camera","viewporty",ply::T_INT,ply::T_INT ,offsetof(LoadPly_Camera,viewporty),0,0,0,0,0 ,0}, |
|
{"camera","k1" ,ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,k1 ),0,0,0,0,0 ,0}, |
|
{"camera","k2" ,ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,k2 ),0,0,0,0,0 ,0}, |
|
{"camera","k3" ,ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,k3 ),0,0,0,0,0 ,0}, |
|
{"camera","k4" ,ply::T_FLOAT,ply::T_FLOAT,offsetof(LoadPly_Camera,k4 ),0,0,0,0,0 ,0} |
|
}; |
|
return cad[i]; |
|
} |
|
/// Standard call for knowing the meaning of an error code |
|
static const char *ErrorMsg(int error) |
|
{ |
|
static std::vector<std::string> ply_error_msg; |
|
if(ply_error_msg.empty()) |
|
{ |
|
ply_error_msg.resize(PlyInfo::E_MAXPLYINFOERRORS ); |
|
ply_error_msg[ply::E_NOERROR ]="No errors"; |
|
ply_error_msg[ply::E_CANTOPEN ]="Can't open file"; |
|
ply_error_msg[ply::E_NOTHEADER ]="Header not found"; |
|
ply_error_msg[ply::E_UNESPECTEDEOF ]="Eof in header"; |
|
ply_error_msg[ply::E_NOFORMAT ]="Format not found"; |
|
ply_error_msg[ply::E_SYNTAX ]="Syntax error on header"; |
|
ply_error_msg[ply::E_PROPOUTOFELEMENT]="Property without element"; |
|
ply_error_msg[ply::E_BADTYPENAME ]="Bad type name"; |
|
ply_error_msg[ply::E_ELEMNOTFOUND ]="Element not found"; |
|
ply_error_msg[ply::E_PROPNOTFOUND ]="Property not found"; |
|
ply_error_msg[ply::E_BADTYPE ]="Bad type on addtoread"; |
|
ply_error_msg[ply::E_INCOMPATIBLETYPE]="Incompatible type"; |
|
ply_error_msg[ply::E_BADCAST ]="Bad cast"; |
|
|
|
ply_error_msg[PlyInfo::E_NO_VERTEX ]="No vertex field found"; |
|
ply_error_msg[PlyInfo::E_NO_FACE ]="No face field found"; |
|
ply_error_msg[PlyInfo::E_SHORTFILE ]="Unexpected EOF"; |
|
ply_error_msg[PlyInfo::E_NO_3VERTINFACE ]="Face with more than 3 vertices"; |
|
ply_error_msg[PlyInfo::E_BAD_VERT_INDEX ]="Bad vertex index in face"; |
|
ply_error_msg[PlyInfo::E_BAD_VERT_INDEX_EDGE ]="Bad vertex index in edge"; |
|
ply_error_msg[PlyInfo::E_NO_6TCOORD ]="Face with no 6 texture coordinates"; |
|
ply_error_msg[PlyInfo::E_DIFFER_COLORS ]="Number of color differ from vertices"; |
|
} |
|
|
|
if(error>PlyInfo::E_MAXPLYINFOERRORS || error<0) return "Unknown error"; |
|
else return ply_error_msg[error].c_str(); |
|
}; |
|
|
|
// to check if a given error is critical or not. |
|
static bool ErrorCritical(int err) |
|
{ |
|
if ((err == ply::E_NOERROR) || (err == PlyInfo::E_NO_FACE)) return false; |
|
return true; |
|
} |
|
|
|
|
|
/// Standard call for reading a mesh, returns 0 on success. |
|
static int Open( OpenMeshType &m, const char * filename, CallBackPos *cb=0) |
|
{ |
|
PlyInfo pi; |
|
pi.cb=cb; |
|
return Open(m, filename, pi); |
|
} |
|
|
|
/// Read a mesh and store in loadmask the loaded field |
|
/// Note that loadmask is not read! just modified. You cannot specify what fields |
|
/// have to be read. ALL the data for which your mesh HasSomething and are present |
|
/// in the file are read in. |
|
static int Open( OpenMeshType &m, const char * filename, int & loadmask, CallBackPos *cb =0) |
|
{ |
|
PlyInfo pi; |
|
pi.cb=cb; |
|
int r = Open(m, filename,pi); |
|
loadmask=pi.mask; |
|
return r; |
|
} |
|
|
|
|
|
/// read a mesh with all the possible option specified in the PlyInfo obj, returns 0 on success. |
|
static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi ) |
|
{ |
|
assert(filename!=0); |
|
std::vector<VertexPointer> index; // vector of vertex pointers filled at the end of the vertex loading. |
|
LoadPly_FaceAux<ScalarType> fa; |
|
LoadPly_EdgeAux ea; |
|
LoadPly_VertAux<ScalarType> va; |
|
|
|
pi.mask = 0; |
|
bool hasIntensity = false; // the intensity is a strange way to code single channel color used sometimes in rangemap. it is a kind of color. so it do not need another entry in the IOM mask. |
|
bool multit = false; // true if texture has a per face int spec the texture index |
|
|
|
va.flags = 42; |
|
|
|
pi.status = ::vcg::ply::E_NOERROR; |
|
|
|
/* |
|
// TO BE REMOVED: tv not used AND "spurious" vertex declaration causes error if ocf |
|
|
|
// init defaults |
|
VertexType tv; |
|
//tv.ClearFlags(); |
|
|
|
if (vcg::tri::HasPerVertexQuality(m)) tv.Q() = (typename OpenMeshType::VertexType::QualityType)1.0; |
|
if (vcg::tri::HasPerVertexColor (m)) tv.C() = Color4b(Color4b::White); |
|
*/ |
|
|
|
// Descrittori delle strutture |
|
|
|
//bool isvflags = false; // Il file contiene i flags |
|
|
|
|
|
// The main descriptor of the ply file |
|
vcg::ply::PlyFile pf; |
|
|
|
// Open the file and parse the header |
|
if( pf.Open(filename,vcg::ply::PlyFile::MODE_READ)==-1 ) |
|
{ |
|
pi.status = pf.GetError(); |
|
return pi.status; |
|
} |
|
pi.header = pf.GetHeader(); |
|
|
|
// Descrittori della camera |
|
{ // Check that all the camera properties are present. |
|
bool found = true; |
|
for(int i=0;i<23;++i) |
|
{ |
|
if( pf.AddToRead(CameraDesc(i))==-1 ) { |
|
found = false; |
|
break; |
|
} |
|
} |
|
if(found) pi.mask |= Mask::IOM_CAMERA; |
|
} |
|
|
|
// Standard data desciptors (vertex coord and faces) |
|
if( pf.AddToRead(VertDesc(0))==-1 && pf.AddToRead(VertDesc(24)) ) { pi.status = PlyInfo::E_NO_VERTEX; return pi.status; } |
|
if( pf.AddToRead(VertDesc(1))==-1 && pf.AddToRead(VertDesc(25)) ) { pi.status = PlyInfo::E_NO_VERTEX; return pi.status; } |
|
if( pf.AddToRead(VertDesc(2))==-1 && pf.AddToRead(VertDesc(26)) ) { pi.status = PlyInfo::E_NO_VERTEX; return pi.status; } |
|
if( pf.AddToRead(FaceDesc(0))==-1 ) // Se fallisce si prova anche la sintassi di rapidform con index al posto di indices |
|
{ |
|
int ii; |
|
for (ii=_FACEDESC_FIRST_;ii< _FACEDESC_LAST_;++ii) |
|
if( pf.AddToRead(FaceDesc(ii))!=-1 ) break; |
|
|
|
if (ii==_FACEDESC_LAST_) |
|
if(pf.AddToRead(TristripDesc(0))==-1) // Se fallisce tutto si prova a vedere se ci sono tristrip alla levoy. |
|
if(pf.AddToRead(RangeDesc(0))==-1) // Se fallisce tutto si prova a vedere se ci sono rangemap alla levoy. |
|
{ |
|
pi.status = PlyInfo::E_NO_FACE; |
|
//return pi.status; no face is not a critical error. let's continue. |
|
} |
|
|
|
} |
|
// Optional flag descriptors |
|
if((pf.AddToRead(EdgeDesc(0) )!= -1 || pf.AddToRead(EdgeDesc(2) )!= -1) && |
|
(pf.AddToRead(EdgeDesc(1)) != -1 || pf.AddToRead(EdgeDesc(3)) != -1)) |
|
pi.mask |= Mask::IOM_EDGEINDEX; |
|
|
|
if(vcg::tri::HasPerVertexFlags(m) && pf.AddToRead(VertDesc(3))!=-1 ) |
|
pi.mask |= Mask::IOM_VERTFLAGS; |
|
|
|
if( vcg::tri::HasPerVertexNormal(m) ) |
|
{ |
|
if( pf.AddToRead(VertDesc(14))!=-1 && pf.AddToRead(VertDesc(15))!=-1 && pf.AddToRead(VertDesc(16))!=-1 ) |
|
pi.mask |= Mask::IOM_VERTNORMAL; |
|
else // try also for Normals stored with doubles |
|
if( pf.AddToRead(VertDesc(27))!=-1 && pf.AddToRead(VertDesc(28))!=-1 && pf.AddToRead(VertDesc(29))!=-1 ) |
|
pi.mask |= Mask::IOM_VERTNORMAL; |
|
|
|
} |
|
|
|
if( vcg::tri::HasPerVertexQuality(m) ) |
|
{ |
|
if( pf.AddToRead(VertDesc(4))!=-1 || |
|
pf.AddToRead(VertDesc(13))!=-1 ) |
|
pi.mask |= Mask::IOM_VERTQUALITY; |
|
else |
|
if (pf.AddToRead(VertDesc(31))!=-1) |
|
pi.mask |= Mask::IOM_VERTQUALITY; |
|
} |
|
|
|
if(vcg::tri::HasPerVertexColor(m) ) |
|
{ |
|
if( pf.AddToRead(VertDesc(5))!=-1 ) |
|
{ |
|
pf.AddToRead(VertDesc(6)); |
|
pf.AddToRead(VertDesc(7)); |
|
pf.AddToRead(VertDesc(8)); |
|
pi.mask |= Mask::IOM_VERTCOLOR; |
|
} |
|
if( pf.AddToRead(VertDesc(9))!=-1 ) |
|
{ |
|
pf.AddToRead(VertDesc(10)); |
|
pf.AddToRead(VertDesc(11)); |
|
pf.AddToRead(VertDesc(12)); |
|
pi.mask |= Mask::IOM_VERTCOLOR; |
|
} |
|
if( pf.AddToRead(VertDesc(21))!=-1 ) |
|
{ |
|
hasIntensity = true; |
|
pi.mask |= Mask::IOM_VERTCOLOR; |
|
} |
|
|
|
} |
|
if( tri::HasPerVertexTexCoord(m) ) |
|
{ |
|
if(( pf.AddToRead(VertDesc(22))!=-1 )&& (pf.AddToRead(VertDesc(23))!=-1)) |
|
{ |
|
pi.mask |= Mask::IOM_VERTTEXCOORD; |
|
} |
|
if(( pf.AddToRead(VertDesc(18))!=-1 )&& (pf.AddToRead(VertDesc(19))!=-1)) |
|
{ |
|
pi.mask |= Mask::IOM_VERTTEXCOORD; |
|
} |
|
if(( pf.AddToRead(VertDesc(32))!=-1 )&& (pf.AddToRead(VertDesc(33))!=-1)) |
|
{ |
|
pi.mask |= Mask::IOM_VERTTEXCOORD; |
|
} |
|
} |
|
if(tri::HasPerVertexRadius(m)) |
|
{ |
|
if( pf.AddToRead(VertDesc(17))!=-1 ) |
|
pi.mask |= Mask::IOM_VERTRADIUS; |
|
else if( pf.AddToRead(VertDesc(30))!=-1 ) |
|
pi.mask |= Mask::IOM_VERTRADIUS; |
|
} |
|
// se ci sono i flag per vertice ci devono essere anche i flag per faccia |
|
if( pf.AddToRead(FaceDesc(1))!=-1 ) |
|
pi.mask |= Mask::IOM_FACEFLAGS; |
|
|
|
if (vcg::tri::HasPerFaceNormal(m)) |
|
{ |
|
if (pf.AddToRead(FaceDesc(10)) != -1 && pf.AddToRead(FaceDesc(11)) != -1 && pf.AddToRead(FaceDesc(12)) != -1) |
|
pi.mask |= Mask::IOM_FACENORMAL; |
|
else if (pf.AddToRead(FaceDesc(26)) != -1 && pf.AddToRead(FaceDesc(27)) != -1 && pf.AddToRead(FaceDesc(28)) != -1) |
|
pi.mask |= Mask::IOM_FACENORMAL; |
|
} |
|
|
|
if( vcg::tri::HasPerFaceQuality(m) ) |
|
{ |
|
if( pf.AddToRead(FaceDesc(2))!=-1 ) |
|
pi.mask |= Mask::IOM_FACEQUALITY; |
|
else if (pf.AddToRead(FaceDesc(25)) != -1) |
|
pi.mask |= Mask::IOM_FACEQUALITY; |
|
} |
|
|
|
if( vcg::tri::HasPerFaceColor(m) ) |
|
{ |
|
if( pf.AddToRead(FaceDesc(6))!=-1 ) |
|
{ |
|
pf.AddToRead(FaceDesc(7)); |
|
pf.AddToRead(FaceDesc(8)); |
|
pf.AddToRead(FaceDesc(9)); |
|
pi.mask |= Mask::IOM_FACECOLOR; |
|
} |
|
} |
|
|
|
|
|
if( vcg::tri::HasPerWedgeTexCoord(m) ) |
|
{ |
|
if( pf.AddToRead(FaceDesc(3))!=-1 ) |
|
{ |
|
if(pf.AddToRead(FaceDesc(5))==0) { |
|
multit=true; // try to read also the multi texture indicies |
|
pi.mask |= Mask::IOM_WEDGTEXMULTI; |
|
} |
|
pi.mask |= Mask::IOM_WEDGTEXCOORD; |
|
} |
|
} |
|
|
|
if( vcg::tri::HasPerFaceColor(m) || vcg::tri::HasPerVertexColor(m) || vcg::tri::HasPerWedgeColor(m) ) |
|
{ |
|
if( pf.AddToRead(FaceDesc(4))!=-1 ) |
|
{ |
|
pi.mask |= Mask::IOM_WEDGCOLOR; |
|
} |
|
} |
|
|
|
// User defined descriptors |
|
std::vector<PropDescriptor> VPV(pi.VertDescriptorVec.size()); // property descriptor relative al tipo LoadPly_VertexAux |
|
std::vector<PropDescriptor> FPV(pi.FaceDescriptorVec.size()); // property descriptor relative al tipo LoadPly_FaceAux |
|
if(pi.VertDescriptorVec.size()>0){ |
|
// Compute the total size needed to load additional per vertex data. |
|
size_t totsz=0; |
|
for(size_t i=0;i<pi.VertDescriptorVec.size();i++){ |
|
VPV[i] = pi.VertDescriptorVec[i]; |
|
VPV[i].offset1=offsetof(LoadPly_VertAux<ScalarType>,data)+totsz; |
|
totsz+=pi.VertDescriptorVec[i].memtypesize(); |
|
if( pf.AddToRead(VPV[i])==-1 ) { pi.status = pf.GetError(); return pi.status; } |
|
} |
|
if(totsz > MAX_USER_DATA) |
|
{ |
|
pi.status = vcg::ply::E_BADTYPE; |
|
return pi.status; |
|
} |
|
} |
|
if(pi.FaceDescriptorVec.size()>0){ |
|
size_t totsz=0; |
|
for(size_t i=0;i<pi.FaceDescriptorVec.size();i++){ |
|
FPV[i] = pi.FaceDescriptorVec[i]; |
|
FPV[i].offset1=offsetof(LoadPly_FaceAux<ScalarType>,data)+totsz; |
|
totsz+=pi.FaceDescriptorVec[i].memtypesize(); |
|
if( pf.AddToRead(FPV[i])==-1 ) { pi.status = pf.GetError(); return pi.status; } |
|
} |
|
if(totsz > MAX_USER_DATA) |
|
{ |
|
pi.status = vcg::ply::E_BADTYPE; |
|
return pi.status; |
|
} |
|
} |
|
|
|
/**************************************************************/ |
|
/* Main Reading Loop */ |
|
/**************************************************************/ |
|
m.Clear(); |
|
PlyAttributeHelper<OpenMeshType> PAH(pi,m); |
|
|
|
for(size_t i=0;i<pf.elements.size();i++) |
|
{ |
|
int n = pf.ElemNumber(i); |
|
|
|
if( !strcmp( pf.ElemName(i),"camera" ) ) |
|
{ |
|
pf.SetCurElement(i); |
|
|
|
LoadPly_Camera ca; |
|
|
|
for(int j=0;j<n;++j) |
|
{ |
|
if( pf.Read( (void *)&(ca) )==-1 ) |
|
{ |
|
pi.status = PlyInfo::E_SHORTFILE; |
|
return pi.status; |
|
} |
|
//camera.valid = true; |
|
|
|
// extrinsic |
|
m.shot.Extrinsics.SetIdentity(); |
|
// view point |
|
m.shot.Extrinsics.SetTra(Point3<ScalarType>( ca.view_px,ca.view_py,ca.view_pz)); |
|
|
|
// axis (i.e. rotation). |
|
Matrix44<ScalarType> rm; |
|
rm.SetIdentity(); |
|
rm[0][0] = ca.x_axisx; |
|
rm[0][1] = ca.x_axisy; |
|
rm[0][2] = ca.x_axisz; |
|
|
|
rm[1][0] = ca.y_axisx; |
|
rm[1][1] = ca.y_axisy; |
|
rm[1][2] = ca.y_axisz; |
|
|
|
rm[2][0] = ca.z_axisx; |
|
rm[2][1] = ca.z_axisy; |
|
rm[2][2] = ca.z_axisz; |
|
|
|
m.shot.Extrinsics.SetRot(rm); |
|
|
|
//intrinsic |
|
m.shot.Intrinsics.FocalMm = ca.focal; |
|
m.shot.Intrinsics.PixelSizeMm[0] = ca.scalex; |
|
m.shot.Intrinsics.PixelSizeMm[1] = ca.scaley; |
|
m.shot.Intrinsics.CenterPx[0] = ca.centerx; |
|
m.shot.Intrinsics.CenterPx[1] = ca.centery; |
|
m.shot.Intrinsics.ViewportPx[0] = ca.viewportx; |
|
m.shot.Intrinsics.ViewportPx[1] = ca.viewporty; |
|
m.shot.Intrinsics.k[0] = ca.k1; |
|
m.shot.Intrinsics.k[1] = ca.k2; |
|
m.shot.Intrinsics.k[2] = ca.k3; |
|
m.shot.Intrinsics.k[3] = ca.k4; |
|
|
|
} |
|
} |
|
else if( !strcmp( pf.ElemName(i),"vertex" ) ) |
|
{ |
|
int j; |
|
|
|
pf.SetCurElement(i); |
|
VertexIterator vi=Allocator<OpenMeshType>::AddVertices(m,n); |
|
|
|
for(j=0;j<n;++j) |
|
{ |
|
if(pi.cb && (j%1000)==0) pi.cb(j*50/n,"Vertex Loading"); |
|
va.a = 255; |
|
if( pf.Read( (void *)&(va) )==-1 ) |
|
{ |
|
pi.status = PlyInfo::E_SHORTFILE; |
|
return pi.status; |
|
} |
|
|
|
(*vi).P()[0] = va.p[0]; |
|
(*vi).P()[1] = va.p[1]; |
|
(*vi).P()[2] = va.p[2]; |
|
|
|
if( HasPerVertexFlags(m) && (pi.mask & Mask::IOM_VERTFLAGS) ) |
|
(*vi).Flags() = va.flags; |
|
|
|
if( pi.mask & Mask::IOM_VERTQUALITY ) |
|
(*vi).Q() = (VertQualityType)va.q; |
|
|
|
if( pi.mask & Mask::IOM_VERTNORMAL ) |
|
{ |
|
(*vi).N()[0]=va.n[0]; |
|
(*vi).N()[1]=va.n[1]; |
|
(*vi).N()[2]=va.n[2]; |
|
} |
|
|
|
if( pi.mask & Mask::IOM_VERTTEXCOORD ) |
|
{ |
|
(*vi).T().P().X() = va.u; |
|
(*vi).T().P().Y() = va.v; |
|
} |
|
|
|
if( pi.mask & Mask::IOM_VERTCOLOR ) |
|
{ |
|
if(hasIntensity) |
|
(*vi).C().SetGrayShade(va.intensity); |
|
else |
|
{ |
|
(*vi).C()[0] = va.r; |
|
(*vi).C()[1] = va.g; |
|
(*vi).C()[2] = va.b; |
|
(*vi).C()[3] = va.a; |
|
} |
|
} |
|
if( pi.mask & Mask::IOM_VERTRADIUS ) |
|
(*vi).R() = va.radius; |
|
|
|
// Now try to read additional data as described in the PlyInfo VertDescriptorVec; two cases: |
|
// 1) you are using attributes (so the corresponding entry of VecAttrNameVec is not empty) |
|
// 2) your vertex type has some space and you just use memcopy |
|
|
|
for(size_t k=0;k<pi.VertDescriptorVec.size();k++) |
|
{ |
|
if(pi.VertDescriptorVec.size() && !pi.VertAttrNameVec[k].empty()) |
|
{ |
|
double td(0); float tf(0);int ti;short ts; char tc; unsigned char tu; |
|
char *vad = (char *)(&va) + VPV[k].offset1; |
|
|
|
switch (pi.VertDescriptorVec[k].stotype1) |
|
{ |
|
case ply::T_FLOAT : tf = *((float*)vad); PAH.thfv[k][&*vi] = tf; break; |
|
case ply::T_DOUBLE : td = *((double*)vad); PAH.thdv[k][&*vi] = td; break; |
|
case ply::T_INT : ti = *((int*)vad); PAH.thiv[k][&*vi] = ti; break; |
|
case ply::T_SHORT : ts = *((short*)vad); PAH.thsv[k][&*vi] = ts; break; |
|
case ply::T_CHAR : tc = *((char*)vad); PAH.thcv[k][&*vi] = tc; break; |
|
case ply::T_UCHAR : tu = *((unsigned char*)vad); PAH.thuv[k][&*vi] = tu; break; |
|
default : assert(0); |
|
} |
|
} |
|
else |
|
{ |
|
memcpy((char *)(&*vi) + pi.VertDescriptorVec[k].offset1, |
|
(char *)(&va) + VPV[k].offset1, |
|
VPV[k].memtypesize()); |
|
} |
|
} |
|
|
|
++vi; |
|
} // end of vertex element reading |
|
|
|
index.resize(n); |
|
for(j=0,vi=m.vert.begin();j<n;++j,++vi) |
|
index[j] = &*vi; |
|
} |
|
/******************** EDGE ELEMENTS READING LOOP *******************************/ |
|
else if( !strcmp( pf.ElemName(i),"edge") && (n>0) ) |
|
{ |
|
assert( pi.mask & Mask::IOM_EDGEINDEX ); |
|
EdgeIterator ei=Allocator<OpenMeshType>::AddEdges(m,n); |
|
pf.SetCurElement(i); |
|
for(int j=0;j<n;++j) |
|
{ |
|
if(pi.cb && (j%1000)==0) pi.cb(50+j*50/n,"Edge Loading"); |
|
if( pf.Read(&ea)==-1 ) |
|
{ |
|
pi.status = PlyInfo::E_SHORTFILE; |
|
return pi.status; |
|
} |
|
if( ea.v1<0 || ea.v2<0 || ea.v1>=m.vn || ea.v2>=m.vn) |
|
{ |
|
pi.status = PlyInfo::E_BAD_VERT_INDEX_EDGE; |
|
return pi.status; |
|
} |
|
(*ei).V(0) = index[ ea.v1 ]; |
|
(*ei).V(1) = index[ ea.v2 ]; |
|
++ei; |
|
} |
|
} |
|
/******************** FACE ELEMENT READING ****************************************/ |
|
else if( !strcmp( pf.ElemName(i),"face") && (n>0) ) |
|
{ |
|
FaceIterator fi=Allocator<OpenMeshType>::AddFaces(m,n); |
|
pf.SetCurElement(i); |
|
|
|
for(int j=0;j<n;++j) // main reading loop |
|
{ |
|
if(pi.cb && (j%1000)==0) pi.cb(50+j*50/n,"Face Loading"); |
|
fa.a = 255; |
|
if( pf.Read(&fa)==-1 ) |
|
{ |
|
pi.status = PlyInfo::E_SHORTFILE; |
|
return pi.status; |
|
} |
|
if(fa.size!=3) |
|
{ // Non triangular face are manageable ONLY if there are no Per Wedge attributes |
|
if( ( pi.mask & Mask::IOM_WEDGCOLOR ) || ( pi.mask & Mask::IOM_WEDGTEXCOORD ) ) |
|
{ |
|
pi.status = PlyInfo::E_NO_3VERTINFACE; |
|
return pi.status; |
|
} |
|
} |
|
|
|
if(HasPolyInfo(m)) (*fi).Alloc(fa.size); |
|
|
|
if(HasPerFaceFlags(m) &&( pi.mask & Mask::IOM_FACEFLAGS) ) |
|
{ |
|
(*fi).Flags() = fa.flags; |
|
} |
|
|
|
if (pi.mask & Mask::IOM_FACENORMAL) |
|
{ |
|
(*fi).N()[0] = fa.n[0]; |
|
(*fi).N()[1] = fa.n[1]; |
|
(*fi).N()[2] = fa.n[2]; |
|
} |
|
|
|
if( pi.mask & Mask::IOM_FACEQUALITY ) |
|
{ |
|
(*fi).Q() = (typename OpenMeshType::FaceType::QualityType) fa.q; |
|
} |
|
|
|
if( pi.mask & Mask::IOM_FACECOLOR ) |
|
{ |
|
(*fi).C()[0] = fa.r; |
|
(*fi).C()[1] = fa.g; |
|
(*fi).C()[2] = fa.b; |
|
(*fi).C()[3] = fa.a; |
|
} |
|
|
|
if( pi.mask & Mask::IOM_WEDGTEXCOORD ) |
|
{ |
|
for(int k=0;k<3;++k) |
|
{ |
|
(*fi).WT(k).u() = fa.texcoord[k*2+0]; |
|
(*fi).WT(k).v() = fa.texcoord[k*2+1]; |
|
if(multit) (*fi).WT(k).n() = fa.texcoordind; |
|
else (*fi).WT(k).n()=0; // safely intialize texture index |
|
} |
|
} |
|
|
|
if( pi.mask & Mask::IOM_WEDGCOLOR ) |
|
{ |
|
if(FaceType::HasWedgeColor()){ |
|
for(int k=0;k<3;++k) |
|
{ |
|
(*fi).WC(k)[0] = (unsigned char)(fa.colors[k*3+0]*255); |
|
(*fi).WC(k)[1] = (unsigned char)(fa.colors[k*3+1]*255); |
|
(*fi).WC(k)[2] = (unsigned char)(fa.colors[k*3+2]*255); |
|
} |
|
} |
|
//if(FaceType::HasFaceColor()){ |
|
//if(pi.mask & Mask::IOM_FACECOLOR){ |
|
if(HasPerFaceColor(m)) { |
|
(*fi).C()[0] = (unsigned char)((fa.colors[0*3+0]*255+fa.colors[1*3+0]*255+fa.colors[2*3+0]*255)/3.0f); |
|
(*fi).C()[1] = (unsigned char)((fa.colors[0*3+1]*255+fa.colors[1*3+1]*255+fa.colors[2*3+1]*255)/3.0f); |
|
(*fi).C()[2] = (unsigned char)((fa.colors[0*3+2]*255+fa.colors[1*3+2]*255+fa.colors[2*3+2]*255)/3.0f); |
|
} |
|
} |
|
|
|
if (HasPolyInfo(m)) |
|
{ |
|
for(int k=0; k<fa.size; ++k) |
|
{ |
|
if( fa.v[k]<0 || fa.v[k]>=m.vn ) |
|
{ |
|
pi.status = PlyInfo::E_BAD_VERT_INDEX; |
|
return pi.status; |
|
} |
|
(*fi).V(k) = index[ fa.v[k] ]; |
|
} |
|
fi++; |
|
continue; |
|
} |
|
|
|
/// Now the temporary struct 'fa' is ready to be copied into the real face '*fi' |
|
/// This loop |
|
for(int k=0;k<3;++k) |
|
{ |
|
if( fa.v[k]<0 || fa.v[k]>=m.vn ) |
|
{ |
|
pi.status = PlyInfo::E_BAD_VERT_INDEX; |
|
return pi.status; |
|
} |
|
(*fi).V(k) = index[ fa.v[k] ]; |
|
} |
|
|
|
// tag faux vertices of first face |
|
if (fa.size>3) fi->SetF(2); |
|
|
|
// Now try to read additional data as described in the PlyInfo FaceDescriptorVe; two cases: |
|
// 1) you are using attributes (so the corresponding entry of FaceAttrNameVec is not empty) |
|
// 2) your face type has some space and you just use memcopy |
|
|
|
for(size_t k=0;k<pi.FaceDescriptorVec.size();k++) |
|
{ |
|
if(pi.FaceAttrNameVec.size() && !pi.FaceAttrNameVec[k].empty()) |
|
{ |
|
double td(0); float tf(0);int ti;short ts; char tc; unsigned char tu; |
|
char *vad = (char *)(&fa) + FPV[k].offset1; |
|
|
|
switch (pi.FaceDescriptorVec[k].stotype1) |
|
{ |
|
case ply::T_FLOAT : tf = *((float*)vad); PAH.thff[k][&*fi] = tf; break; |
|
case ply::T_DOUBLE : td = *((double*)vad); PAH.thdf[k][&*fi] = td; break; |
|
case ply::T_INT : ti = *((int*)vad); PAH.thif[k][&*fi] = ti; break; |
|
case ply::T_SHORT : ts = *((short*)vad); PAH.thsf[k][&*fi] = ts; break; |
|
case ply::T_CHAR : tc = *((char*)vad); PAH.thcf[k][&*fi] = tc; break; |
|
case ply::T_UCHAR : tu = *((unsigned char*)vad); PAH.thuf[k][&*fi] = tu; break; |
|
default : assert(0); |
|
} |
|
|
|
} |
|
else |
|
{ |
|
memcpy((char *)(&(*fi)) + pi.FaceDescriptorVec[k].offset1, |
|
(char *)(&fa) + FPV[k].offset1, |
|
FPV[k].memtypesize()); |
|
} |
|
} |
|
|
|
++fi; |
|
|
|
// Non Triangular Faces Loop |
|
// It performs a simple fan triangulation. |
|
if(fa.size>3) |
|
{ |
|
int curpos=int(fi-m.face.begin()); |
|
Allocator<OpenMeshType>::AddFaces(m,fa.size-3); |
|
fi=m.face.begin()+curpos; |
|
pi.mask |= Mask::IOM_BITPOLYGONAL; |
|
} |
|
for(int qq=0;qq<fa.size-3;++qq) |
|
{ |
|
if(HasPolyInfo(m)) (*fi).Alloc(3); |
|
|
|
(*fi).V(0) = index[ fa.v[0] ]; |
|
for(int k=1;k<3;++k) |
|
{ |
|
if( fa.v[2+qq]<0 || fa.v[2+qq]>=m.vn ) |
|
{ |
|
pi.status = PlyInfo::E_BAD_VERT_INDEX; |
|
return pi.status; |
|
} |
|
(*fi).V(k) = index[ fa.v[1+qq+k] ]; |
|
|
|
} |
|
if( pi.mask & Mask::IOM_FACEQUALITY ) |
|
(*fi).Q() = (typename OpenMeshType::FaceType::QualityType) |
|
fa.q; |
|
if( pi.mask & Mask::IOM_FACECOLOR ) |
|
(*fi).C() = Color4b(fa.r,fa.g,fa.b,255); |
|
// tag faux vertices of extra faces |
|
fi->SetF(0); |
|
if(qq<(fa.size-4)) fi->SetF(2); |
|
|
|
for(size_t k=0;k<pi.FaceDescriptorVec.size();k++) |
|
memcpy((char *)(&(*fi)) + pi.FaceDescriptorVec[k].offset1, |
|
(char *)(&fa) + FPV[k].offset1, FPV[k].memtypesize()); |
|
++fi; |
|
} |
|
|
|
} |
|
} |
|
else if( !strcmp( pf.ElemName(i),"tristrips") )//////////////////// Reading TRISTRIP (rarely used, found in old STANFORD PLY) |
|
{ |
|
if(! PlyParseStanfordTriStrips(pf, i, n, m, index, pi) ) return pi.status; |
|
} |
|
else if( !strcmp( pf.ElemName(i),"range_grid") )//////////////////// Reading RANGEMAP (rarely used, found in old STANFORD PLY) |
|
{ |
|
if(! PlyParseStanfordRangeMaps(pf, i, m, pi) ) return pi.status; |
|
} |
|
else |
|
{ |
|
int n = pf.ElemNumber(i); |
|
pf.SetCurElement(i); |
|
|
|
for(int j=0;j<n;j++) |
|
{ |
|
if( pf.Read(0)==-1) |
|
{ |
|
pi.status = PlyInfo::E_SHORTFILE; |
|
return pi.status; |
|
} |
|
} |
|
} |
|
} |
|
|
|
// Parsing texture names |
|
m.textures.clear(); |
|
m.normalmaps.clear(); |
|
const size_t linesize=1024; |
|
|
|
for(size_t co=0;co<pf.comments.size();++co) |
|
{ |
|
std::string TFILE = "TextureFile"; |
|
std::string NFILE = "TextureNormalFile"; |
|
std::string &c = pf.comments[co]; |
|
// char buf[256]; |
|
std::string bufstr,bufclean; |
|
int n; |
|
|
|
if( TFILE == c.substr(0,TFILE.length()) ) |
|
{ |
|
bufstr = c.substr(TFILE.length()+1); |
|
n = static_cast<int>(bufstr.length()); |
|
for(int i=0;i<n;i++) |
|
if( bufstr[i]!=' ' && bufstr[i]!='\t' && bufstr[i]>32 && bufstr[i]<125 ) bufclean.push_back(bufstr[i]); |
|
|
|
char buf2[linesize]; |
|
ply::interpret_texture_name( bufclean.c_str(),filename,buf2,linesize ); |
|
m.textures.push_back( std::string(buf2) ); |
|
} |
|
/*if( !strncmp(c,NFILE,strlen(NFILE)) ) |
|
{ |
|
strcpy(buf,c+strlen(NFILE)+1); |
|
n = strlen(buf); |
|
for(i=j=0;i<n;i++) |
|
if( buf[i]!=' ' && buf[i]!='\t' && buf[i]>32 && buf[i]<125 ) buf[j++] = buf[i]; |
|
|
|
buf[j] = 0; |
|
char buf2[255]; |
|
__interpret_texture_name( buf,filename,buf2 ); |
|
m.normalmaps.push_back( string(buf2) ); |
|
}*/ |
|
} |
|
|
|
// vn and fn should be correct but if someone wrongly saved some deleted elements they can be wrong. |
|
m.vn = 0; |
|
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) |
|
if( ! (*vi).IsD() ) |
|
++m.vn; |
|
|
|
m.fn = 0; |
|
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) |
|
if( ! (*fi).IsD() ) |
|
++m.fn; |
|
|
|
tri::UpdateBounding<OpenMeshType>::Box(m); |
|
return 0; |
|
} |
|
|
|
|
|
// Loading only a Camera from PLY |
|
int LoadCamera(const char * filename, vcg::Camera<ScalarType> camera, PlyInfo &pi) |
|
{ |
|
vcg::ply::PlyFile pf; |
|
if( pf.Open(filename,vcg::ply::PlyFile::MODE_READ)==-1 ) |
|
{ |
|
pi.status = pf.GetError(); |
|
return pi.status; |
|
} |
|
|
|
|
|
bool found = true; |
|
for(int i=0;i<23;++i) |
|
{ |
|
if( pf.AddToRead(CameraDesc(i))==-1 ) |
|
{ |
|
found = false; |
|
break; |
|
} |
|
} |
|
|
|
if(!found) |
|
return pi.status; |
|
|
|
for(size_t i=0;i<pf.elements.size();i++) |
|
{ |
|
int n = pf.ElemNumber(i); |
|
|
|
if( !strcmp( pf.ElemName(i),"camera" ) ) |
|
{ |
|
pf.SetCurElement(i); |
|
|
|
LoadPly_Camera ca; |
|
|
|
for(int j=0;j<n;++j) |
|
{ |
|
if( pf.Read( (void *)&(ca) )==-1 ) |
|
{ |
|
pi.status = PlyInfo::E_SHORTFILE; |
|
return pi.status; |
|
} |
|
camera.valid = true; |
|
camera.view_p[0] = ca.view_px; |
|
camera.view_p[1] = ca.view_py; |
|
camera.view_p[2] = ca.view_pz; |
|
camera.x_axis[0] = ca.x_axisx; |
|
camera.x_axis[1] = ca.x_axisy; |
|
camera.x_axis[2] = ca.x_axisz; |
|
camera.y_axis[0] = ca.y_axisx; |
|
camera.y_axis[1] = ca.y_axisy; |
|
camera.y_axis[2] = ca.y_axisz; |
|
camera.z_axis[0] = ca.z_axisx; |
|
camera.z_axis[1] = ca.z_axisy; |
|
camera.z_axis[2] = ca.z_axisz; |
|
camera.f = ca.focal; |
|
camera.s[0] = ca.scalex; |
|
camera.s[1] = ca.scaley; |
|
camera.c[0] = ca.centerx; |
|
camera.c[1] = ca.centery; |
|
camera.viewport[0] = ca.viewportx; |
|
camera.viewport[1] = ca.viewporty; |
|
camera.k[0] = ca.k1; |
|
camera.k[1] = ca.k2; |
|
camera.k[2] = ca.k3; |
|
camera.k[3] = ca.k4; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
static bool LoadMask(const char * filename, int &mask) |
|
{ |
|
PlyInfo pi; |
|
return LoadMask(filename, mask,pi); |
|
} |
|
static bool LoadMask(const char * filename, int &mask, PlyInfo &pi) |
|
{ |
|
mask=0; |
|
vcg::ply::PlyFile pf; |
|
if( pf.Open(filename,vcg::ply::PlyFile::MODE_READ)==-1 ) |
|
{ |
|
pi.status = pf.GetError(); |
|
return false; |
|
} |
|
|
|
if( pf.AddToRead(VertDesc( 0))!=-1 && |
|
pf.AddToRead(VertDesc( 1))!=-1 && |
|
pf.AddToRead(VertDesc( 2))!=-1 ) mask |= Mask::IOM_VERTCOORD; |
|
if( pf.AddToRead(VertDesc(24))!=-1 && |
|
pf.AddToRead(VertDesc(25))!=-1 && |
|
pf.AddToRead(VertDesc(26))!=-1 ) mask |= Mask::IOM_VERTCOORD; |
|
|
|
if( pf.AddToRead(VertDesc(14))!=-1 && |
|
pf.AddToRead(VertDesc(15))!=-1 && |
|
pf.AddToRead(VertDesc(16))!=-1 ) mask |= Mask::IOM_VERTNORMAL; |
|
if( pf.AddToRead(VertDesc(27))!=-1 && |
|
pf.AddToRead(VertDesc(28))!=-1 && |
|
pf.AddToRead(VertDesc(29))!=-1 ) mask |= Mask::IOM_VERTNORMAL; |
|
|
|
if( pf.AddToRead(VertDesc( 3))!=-1 ) mask |= Mask::IOM_VERTFLAGS; |
|
if( pf.AddToRead(VertDesc( 4))!=-1 ) mask |= Mask::IOM_VERTQUALITY; |
|
if( pf.AddToRead(VertDesc(13))!=-1 ) mask |= Mask::IOM_VERTQUALITY; |
|
if( pf.AddToRead(VertDesc(17))!=-1 ) mask |= Mask::IOM_VERTRADIUS; |
|
if( pf.AddToRead(VertDesc(30))!=-1 ) mask |= Mask::IOM_VERTRADIUS; |
|
if( pf.AddToRead(VertDesc(31))!=-1 ) mask |= Mask::IOM_VERTQUALITY; |
|
if( pf.AddToRead(VertDesc( 5))!=-1 && |
|
pf.AddToRead(VertDesc( 6))!=-1 && |
|
pf.AddToRead(VertDesc( 7))!=-1 ) mask |= Mask::IOM_VERTCOLOR; |
|
if( pf.AddToRead(VertDesc( 9))!=-1 && |
|
pf.AddToRead(VertDesc(10))!=-1 && |
|
pf.AddToRead(VertDesc(11))!=-1 ) mask |= Mask::IOM_VERTCOLOR; |
|
if( pf.AddToRead(VertDesc(21))!=-1 ) mask |= Mask::IOM_VERTCOLOR; |
|
|
|
if( pf.AddToRead(VertDesc(22))!=-1 && |
|
pf.AddToRead(VertDesc(23))!=-1) mask |= Mask::IOM_VERTTEXCOORD; |
|
|
|
if( pf.AddToRead(VertDesc(18))!=-1 && |
|
pf.AddToRead(VertDesc(19))!=-1) mask |= Mask::IOM_VERTTEXCOORD; |
|
|
|
if( pf.AddToRead(VertDesc(32))!=-1 && |
|
pf.AddToRead(VertDesc(33))!=-1) mask |= Mask::IOM_VERTTEXCOORD; |
|
|
|
if( pf.AddToRead(FaceDesc(0))!=-1 ) mask |= Mask::IOM_FACEINDEX; |
|
if( pf.AddToRead(FaceDesc(1))!=-1 ) mask |= Mask::IOM_FACEFLAGS; |
|
if( pf.AddToRead(FaceDesc(10))!=-1 && |
|
pf.AddToRead(FaceDesc(11))!=-1 && |
|
pf.AddToRead(FaceDesc(12))!=-1 ) mask |= Mask::IOM_FACENORMAL; |
|
if( pf.AddToRead(FaceDesc(26))!=-1 && |
|
pf.AddToRead(FaceDesc(27))!=-1 && |
|
pf.AddToRead(FaceDesc(28))!=-1 ) mask |= Mask::IOM_FACENORMAL; |
|
if( pf.AddToRead(FaceDesc(2))!=-1 ) mask |= Mask::IOM_FACEQUALITY; |
|
if( pf.AddToRead(FaceDesc(25))!=-1 ) mask |= Mask::IOM_FACEQUALITY; |
|
if( pf.AddToRead(FaceDesc(3))!=-1 ) mask |= Mask::IOM_WEDGTEXCOORD; |
|
if( pf.AddToRead(FaceDesc(5))!=-1 ) mask |= Mask::IOM_WEDGTEXMULTI; |
|
if( pf.AddToRead(FaceDesc(4))!=-1 ) mask |= Mask::IOM_WEDGCOLOR; |
|
if( pf.AddToRead(FaceDesc(6))!=-1 && |
|
pf.AddToRead(FaceDesc(7))!=-1 && |
|
pf.AddToRead(FaceDesc(8))!=-1 ) mask |= Mask::IOM_FACECOLOR; |
|
|
|
return true; |
|
} |
|
static bool PlyParseStanfordTriStrips( vcg::ply::PlyFile &pf, const int i, const int n, OpenMeshType &m, const std::vector<VertexPointer> &index, PlyInfo &pi) |
|
{ |
|
LoadPly_TristripAux tsa; |
|
pf.SetCurElement(i); |
|
int numvert_tmp = (int)m.vert.size(); |
|
for(int j=0;j<n;++j) |
|
{ |
|
int k; |
|
if(pi.cb && (j%1000)==0) pi.cb(50+j*50/n,"Tristrip Face Loading"); |
|
if( pf.Read(&tsa)==-1 ) |
|
{ |
|
pi.status = PlyInfo::E_SHORTFILE; |
|
return false; |
|
} |
|
int remainder=0; |
|
for(k=0;k<tsa.size-2;++k) |
|
{ |
|
if(pi.cb && (k%1000)==0) pi.cb(50+k*50/tsa.size,"Tristrip Face Loading"); |
|
if(tsa.v[k]<0 || tsa.v[k]>=numvert_tmp ) { |
|
pi.status = PlyInfo::E_BAD_VERT_INDEX; |
|
return false; |
|
} |
|
if(tsa.v[k+2]==-1) |
|
{ |
|
k+=2; |
|
if(k%2) remainder=0; |
|
else remainder=1; |
|
continue; |
|
} |
|
Allocator<OpenMeshType>::AddFaces(m,1); |
|
FaceType &tf =m.face.back(); |
|
tf.V(0) = index[ tsa.v[k+0] ]; |
|
tf.V(1) = index[ tsa.v[k+1] ]; |
|
tf.V(2) = index[ tsa.v[k+2] ]; |
|
if((k+remainder)%2) std::swap (tf.V(0), tf.V(1) ); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
static bool PlyParseStanfordRangeMaps( vcg::ply::PlyFile &pf, int i, OpenMeshType &m, PlyInfo &pi) |
|
{ |
|
LoadPly_RangeGridAux rga; |
|
std::vector<int> RangeGridAuxVec; |
|
int RangeGridCols=0; |
|
int RangeGridRows=0; |
|
|
|
//qDebug("Starting Reading of Range Grid"); |
|
if(RangeGridCols==0) // not initialized. |
|
{ |
|
for(size_t co=0;co< pf.comments.size();++co) |
|
{ |
|
std::string num_cols = "num_cols"; |
|
std::string num_rows = "num_rows"; |
|
std::string &c = pf.comments[co]; |
|
std::string bufstr,bufclean; |
|
if( num_cols == c.substr(0,num_cols.length()) ) |
|
{ |
|
bufstr = c.substr(num_cols.length()+1); |
|
RangeGridCols = atoi(bufstr.c_str()); |
|
} |
|
if( num_rows == c.substr(0,num_rows.length()) ) |
|
{ |
|
bufstr = c.substr(num_rows.length()+1); |
|
RangeGridRows = atoi(bufstr.c_str()); |
|
} |
|
} |
|
//qDebug("Rows %i Cols %i",RangeGridRows,RangeGridCols); |
|
} |
|
int totPnt = RangeGridCols*RangeGridRows; |
|
// standard reading; |
|
pf.SetCurElement(i); |
|
for(int j=0;j<totPnt;++j) |
|
{ |
|
if(pi.cb && (j%1000)==0) pi.cb(50+j*50/totPnt,"RangeMap Face Loading"); |
|
if( pf.Read(&rga)==-1 ) |
|
{ |
|
//qDebug("Error after loading %i elements",j); |
|
pi.status = PlyInfo::E_SHORTFILE; |
|
return false; |
|
} |
|
else |
|
{ |
|
if(rga.num_pts == 0) |
|
RangeGridAuxVec.push_back(-1); |
|
else |
|
RangeGridAuxVec.push_back(rga.pts[0]); |
|
} |
|
} |
|
//qDebug("Completed the reading of %i indexes",RangeGridAuxVec.size()); |
|
tri::SparseFaceGrid(m, RangeGridAuxVec, RangeGridCols,RangeGridRows); |
|
|
|
return true; |
|
} |
|
|
|
|
|
}; // end class |
|
|
|
|
|
} // end namespace tri |
|
} // end namespace io |
|
} // end namespace vcg |
|
|
|
#endif |
|
|
|
|