962 lines
31 KiB
C++
962 lines
31 KiB
C++
/****************************************************************************
|
|
* 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.20 2005/12/02 00:01:30 cignoni
|
|
Added loading of texturenames (normalmap still to do)
|
|
|
|
Revision 1.19 2005/11/25 10:23:27 cignoni
|
|
Added safe zero initialization of index of wedge texture
|
|
|
|
Revision 1.18 2005/11/23 16:59:55 callieri
|
|
corrected protected access methods (camera, similarity) of shot
|
|
|
|
Revision 1.17 2005/11/12 18:13:30 cignoni
|
|
Added support for non triangular faces (simple fan triangulation) and removed flags intiailization.
|
|
|
|
Revision 1.16 2005/10/14 15:09:56 cignoni
|
|
Added LoadMask without plyinfo and some comment on the mask usage
|
|
|
|
Revision 1.15 2005/06/10 15:05:00 cignoni
|
|
Made inline PlyType specializations
|
|
|
|
Revision 1.14 2005/04/14 15:09:38 ponchio
|
|
New gcc 3.3.3 (with bugs and features) now compiles.
|
|
|
|
Revision 1.13 2005/03/18 00:14:39 cignoni
|
|
removed small gcc compiling issues
|
|
|
|
Revision 1.12 2005/02/08 17:28:22 tarini
|
|
changed 120 "const static" to "static const", and added missing "format" fields to all PropDescriptor literals, to keep Mingw compiler happy
|
|
|
|
Revision 1.11 2005/01/03 10:35:47 cignoni
|
|
Improved the compatibility for ply format for faces having the list size (e.g. number of vertexes of a face) as a char instead of a uchar.
|
|
Added a couple of new face descriptors, corrected a bug in error reporting function (and restructured) and translated a few comments.
|
|
Thanks to Patrick Min for the careful bug reporting
|
|
|
|
Revision 1.10 2004/10/07 14:51:10 ganovelli
|
|
added setidentity della camera
|
|
|
|
Revision 1.9 2004/10/07 14:19:06 ganovelli
|
|
shot/camera io added
|
|
|
|
Revision 1.8 2004/06/23 15:36:43 cignoni
|
|
Restructured management of error, now the standard open for any mesh type return the error code, the default success value is zero
|
|
Any import class has a method ErrorMsg that give a verbal description of an error code.
|
|
|
|
Revision 1.7 2004/06/11 17:09:41 ganovelli
|
|
inclusion of vector..minorchanges
|
|
|
|
Revision 1.6 2004/05/28 14:11:13 ganovelli
|
|
changes to comply io_mask moving in vcg::ply namesp
|
|
|
|
Revision 1.5 2004/05/12 10:19:30 ganovelli
|
|
new line added at the end of file
|
|
|
|
Revision 1.4 2004/05/04 02:36:07 ganovelli
|
|
#ifndef __VCGLIB_IMPORTERPLY added
|
|
|
|
Revision 1.3 2004/04/03 13:30:01 cignoni
|
|
missing include allocate.h
|
|
|
|
Revision 1.2 2004/03/09 21:26:47 cignoni
|
|
cr lf mismatch
|
|
|
|
Revision 1.1 2004/03/03 15:00:51 cignoni
|
|
Initial commit
|
|
|
|
****************************************************************************/
|
|
#ifndef __VCGLIB_IMPORTERPLY
|
|
#define __VCGLIB_IMPORTERPLY
|
|
|
|
#include<wrap/callback.h>
|
|
#include<wrap/ply/plylib.h>
|
|
#include<wrap/ply/io_mask.h>
|
|
#include<wrap/io_trimesh/io_ply.h>
|
|
#include<vcg/complex/trimesh/allocate.h>
|
|
#include<vcg/space/color4.h>
|
|
#include <vector>
|
|
|
|
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 OpenMeshType::FaceType FaceType;
|
|
typedef typename OpenMeshType::VertexIterator VertexIterator;
|
|
typedef typename OpenMeshType::FaceIterator FaceIterator;
|
|
|
|
//template <class T> int PlyType () { assert(0); return 0;}
|
|
|
|
#define MAX_USER_DATA 256
|
|
// Struttura ausiliaria per la lettura del file ply
|
|
struct LoadPly_FaceAux
|
|
{
|
|
unsigned char size;
|
|
int v[512];
|
|
int flags;
|
|
float q;
|
|
float tcoord[32];
|
|
unsigned char ntcoord;
|
|
int tcoordind;
|
|
float colors[32];
|
|
unsigned char ncolors;
|
|
|
|
unsigned char r;
|
|
unsigned char g;
|
|
unsigned char b;
|
|
|
|
unsigned char data[MAX_USER_DATA];
|
|
};
|
|
|
|
struct LoadPly_TristripAux
|
|
{
|
|
int size;
|
|
int *v;
|
|
unsigned char data[MAX_USER_DATA];
|
|
};
|
|
|
|
// Struttura ausiliaria per la lettura del file ply
|
|
template<class S>
|
|
struct LoadPly_VertAux
|
|
{
|
|
S p[3];
|
|
int flags;
|
|
float q;
|
|
unsigned char r;
|
|
unsigned char g;
|
|
unsigned char b;
|
|
unsigned char data[MAX_USER_DATA];
|
|
};
|
|
|
|
// Struttura ausiliaria caricamento 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;
|
|
};
|
|
|
|
static const PropDescriptor &VertDesc(int i)
|
|
{
|
|
static const PropDescriptor pv[9]={
|
|
{"vertex", "x", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,p),0,0,0,0,0 ,0},
|
|
{"vertex", "y", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,p) + sizeof(ScalarType),0,0,0,0,0 ,0},
|
|
{"vertex", "z", ply::T_FLOAT, PlyType<ScalarType>(),offsetof(LoadPly_VertAux<ScalarType>,p) + 2*sizeof(ScalarType),0,0,0,0,0 ,0},
|
|
{"vertex", "flags", ply::T_INT, ply::T_INT, offsetof(LoadPly_VertAux<ScalarType>,flags),0,0,0,0,0 ,0},
|
|
{"vertex", "quality", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,q),0,0,0,0,0 ,0},
|
|
{"vertex", "red" , ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,r),0,0,0,0,0 ,0},
|
|
{"vertex", "green", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,g),0,0,0,0,0 ,0},
|
|
{"vertex", "blue" , ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_VertAux<ScalarType>,b),0,0,0,0,0 ,0},
|
|
{"vertex", "confidence",ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_VertAux<ScalarType>,q),0,0,0,0,0 ,0},
|
|
};
|
|
return pv[i];
|
|
}
|
|
|
|
|
|
static const PropDescriptor &FaceDesc(int i)
|
|
{
|
|
static const PropDescriptor qf[12]=
|
|
{
|
|
{"face", "vertex_indices", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_UCHAR,ply::T_UCHAR,offsetof(LoadPly_FaceAux,size) ,0},
|
|
{"face", "flags", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,flags), 0,0,0,0,0 ,0},
|
|
{"face", "quality", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_FaceAux,q), 0,0,0,0,0 ,0},
|
|
{"face", "texcoord", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_FaceAux,tcoord), 1,0,ply::T_UCHAR,ply::T_UCHAR,offsetof(LoadPly_FaceAux,ntcoord) ,0},
|
|
{"face", "color", ply::T_FLOAT, ply::T_FLOAT, offsetof(LoadPly_FaceAux,colors), 1,0,ply::T_UCHAR,ply::T_UCHAR,offsetof(LoadPly_FaceAux,ncolors) ,0},
|
|
{"face", "texnumber", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,tcoordind), 0,0,0,0,0 ,0},
|
|
{"face", "red" , ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,r), 0,0,0,0,0 ,0},
|
|
{"face", "green", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,g), 0,0,0,0,0 ,0},
|
|
{"face", "blue" , ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,b), 0,0,0,0,0 ,0},
|
|
{"face", "vertex_index", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_UCHAR,ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0},
|
|
{"face", "vertex_indices", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_CHAR,ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0},
|
|
{"face", "vertex_index", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_CHAR,ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,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 &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 ]="Unespected 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_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();
|
|
};
|
|
|
|
|
|
/// Standard call for reading a mesh
|
|
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.mask=loadmask;
|
|
return Open(m, filename,pi);
|
|
loadmask=pi.mask;
|
|
}
|
|
|
|
|
|
/// read a mesh with all the possible option specified in the PlyInfo obj.
|
|
static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
|
|
{
|
|
assert(filename!=0);
|
|
std::vector<VertexPointer> index;
|
|
LoadPly_FaceAux fa;
|
|
LoadPly_TristripAux tsa;
|
|
LoadPly_VertAux<ScalarType> va;
|
|
|
|
pi.mask = 0;
|
|
bool multit = false; // true if texture has a per face int spec the texture index
|
|
|
|
va.flags = 42;
|
|
|
|
pi.status = ::vcg::ply::E_NOERROR;
|
|
|
|
// init defaults
|
|
VertexType tv;
|
|
//tv.ClearFlags();
|
|
if( VertexType::HasQuality() ) tv.Q()=1.0;
|
|
if( VertexType::HasColor() ) tv.C()=Color4b(Color4b::White);
|
|
|
|
FaceType tf;
|
|
tf.UberFlags() = 0;
|
|
if( FaceType::HasFaceQuality() ) tf.Q()=1.0;
|
|
if( FaceType::HasWedgeColor() ) tf.WC(0)=tf.WC(1)=tf.WC(2)=Color4b(Color4b::White);
|
|
if( FaceType::HasFaceColor() ) tf.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 |= ply::PLYMask::PM_CAMERA;
|
|
}
|
|
|
|
// Descrittori dati standard (vertex coord e faces)
|
|
if( pf.AddToRead(VertDesc(0))==-1 ) { pi.status = PlyInfo::E_NO_VERTEX; return pi.status; }
|
|
if( pf.AddToRead(VertDesc(1))==-1 ) { pi.status = PlyInfo::E_NO_VERTEX; return pi.status; }
|
|
if( pf.AddToRead(VertDesc(2))==-1 ) { 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
|
|
if( pf.AddToRead(FaceDesc(9))==-1 )
|
|
if( pf.AddToRead(FaceDesc(10))==-1 )
|
|
if( pf.AddToRead(FaceDesc(11))==-1 )
|
|
if(pf.AddToRead(TristripDesc(0))==-1) // Se fallisce tutto si prova a vedere se ci sono tristrip alla levoy.
|
|
{ pi.status = PlyInfo::E_NO_FACE; return pi.status; }
|
|
|
|
// Descrittori facoltativi dei flags
|
|
|
|
if(VertexType::HasFlags() && (pf.AddToRead(VertDesc(3))!=-1 ) )
|
|
pi.mask |= ply::PLYMask::PM_VERTFLAGS;
|
|
|
|
if( VertexType::HasQuality() )
|
|
{
|
|
if( pf.AddToRead(VertDesc(4))!=-1 ||
|
|
pf.AddToRead(VertDesc(8))!=-1 )
|
|
pi.mask |= ply::PLYMask::PM_VERTQUALITY;
|
|
}
|
|
|
|
if( VertexType::HasColor() )
|
|
{
|
|
if( pf.AddToRead(VertDesc(5))!=-1 )
|
|
{
|
|
pf.AddToRead(VertDesc(6));
|
|
pf.AddToRead(VertDesc(7));
|
|
pi.mask |= ply::PLYMask::PM_VERTCOLOR;
|
|
}
|
|
}
|
|
|
|
// se ci sono i flag per vertice ci devono essere anche i flag per faccia
|
|
if( pf.AddToRead(FaceDesc(1))!=-1 )
|
|
pi.mask |= ply::PLYMask::PM_FACEFLAGS;
|
|
|
|
if( FaceType::HasFaceQuality())
|
|
{
|
|
if( pf.AddToRead(FaceDesc(2))!=-1 )
|
|
pi.mask |= ply::PLYMask::PM_FACEQUALITY;
|
|
}
|
|
|
|
if( FaceType::HasFaceColor() )
|
|
{
|
|
if( pf.AddToRead(FaceDesc(6))!=-1 )
|
|
{
|
|
pf.AddToRead(FaceDesc(7));
|
|
pf.AddToRead(FaceDesc(8));
|
|
pi.mask |= ply::PLYMask::PM_FACECOLOR;
|
|
}
|
|
}
|
|
|
|
|
|
if( FaceType::HasWedgeTexture() )
|
|
{
|
|
if( pf.AddToRead(FaceDesc(3))!=-1 )
|
|
{
|
|
if(pf.AddToRead(FaceDesc(5))==0) {
|
|
multit=true; // try to read also the multi texture indicies
|
|
pi.mask |= ply::PLYMask::PM_WEDGTEXMULTI;
|
|
}
|
|
pi.mask |= ply::PLYMask::PM_WEDGTEXCOORD;
|
|
}
|
|
}
|
|
|
|
if( FaceType::HasWedgeColor() || FaceType::HasFaceColor() || VertexType::HasColor())
|
|
{
|
|
if( pf.AddToRead(FaceDesc(4))!=-1 )
|
|
{
|
|
pi.mask |= ply::PLYMask::PM_WEDGCOLOR;
|
|
}
|
|
}
|
|
|
|
// Descrittori definiti dall'utente,
|
|
std::vector<PropDescriptor> VPV(pi.vdn); // property descriptor relative al tipo LoadPly_VertexAux
|
|
std::vector<PropDescriptor> FPV(pi.fdn); // property descriptor relative al tipo LoadPly_FaceAux
|
|
if(pi.vdn>0){
|
|
// Compute the total size needed to load additional per vertex data.
|
|
size_t totsz=0;
|
|
for(int i=0;i<pi.vdn;i++){
|
|
VPV[i] = pi.VertexData[i];
|
|
VPV[i].offset1=offsetof(LoadPly_VertAux<ScalarType>,data)+totsz;
|
|
totsz+=pi.VertexData[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.fdn>0){
|
|
size_t totsz=0;
|
|
for(int i=0;i<pi.fdn;i++){
|
|
FPV[i] = pi.FaceData[i];
|
|
FPV[i].offset1=offsetof(LoadPly_FaceAux,data)+totsz;
|
|
totsz+=pi.FaceData[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();
|
|
for(int i=0;i<int(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.Similarity().SetIdentity();
|
|
// view point
|
|
m.shot.Similarity().tra[0] = -ca.view_px;
|
|
m.shot.Similarity().tra[1] = -ca.view_py;
|
|
m.shot.Similarity().tra[2] = -ca.view_pz;
|
|
|
|
// axis (i.e. rotation).
|
|
m.shot.Similarity().rot[0][0] = ca.x_axisx;
|
|
m.shot.Similarity().rot[0][1] = ca.x_axisy;
|
|
m.shot.Similarity().rot[0][2] = ca.x_axisz;
|
|
|
|
m.shot.Similarity().rot[1][0] = ca.y_axisx;
|
|
m.shot.Similarity().rot[1][1] = ca.y_axisy;
|
|
m.shot.Similarity().rot[1][2] = ca.y_axisz;
|
|
|
|
m.shot.Similarity().rot[2][0] = ca.z_axisx;
|
|
m.shot.Similarity().rot[2][1] = ca.z_axisy;
|
|
m.shot.Similarity().rot[2][2] = ca.z_axisz;
|
|
|
|
//intrinsic
|
|
m.shot.Camera().f = ca.focal;
|
|
m.shot.Camera().s[0] = ca.scalex;
|
|
m.shot.Camera().s[1] = ca.scaley;
|
|
m.shot.Camera().c[0] = ca.centerx;
|
|
m.shot.Camera().c[1] = ca.centery;
|
|
m.shot.Camera().viewport[0] = ca.viewportx;
|
|
m.shot.Camera().viewport[1] = ca.viewporty;
|
|
m.shot.Camera().k[0] = ca.k1;
|
|
m.shot.Camera().k[1] = ca.k2;
|
|
m.shot.Camera().k[2] = ca.k3;
|
|
m.shot.Camera().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");
|
|
//(*vi).UberFlags()=0; // No more necessary, since 9/2005 flags are set to zero in the constuctor.
|
|
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( pi.mask & ply::PLYMask::PM_VERTFLAGS )
|
|
(*vi).UberFlags() = va.flags;
|
|
|
|
if( pi.mask & ply::PLYMask::PM_VERTQUALITY )
|
|
(*vi).Q() = va.q;
|
|
|
|
if( pi.mask & ply::PLYMask::PM_VERTCOLOR )
|
|
{
|
|
(*vi).C()[0] = va.r;
|
|
(*vi).C()[1] = va.g;
|
|
(*vi).C()[2] = va.b;
|
|
(*vi).C()[3] = 255;
|
|
}
|
|
|
|
|
|
for(int k=0;k<pi.vdn;k++)
|
|
memcpy((char *)(&*vi) + pi.VertexData[k].offset1,
|
|
(char *)(&va) + VPV[k].offset1,
|
|
VPV[k].memtypesize());
|
|
++vi;
|
|
}
|
|
|
|
index.resize(n);
|
|
for(j=0,vi=m.vert.begin();j<n;++j,++vi)
|
|
index[j] = &*vi;
|
|
}
|
|
else if( !strcmp( pf.ElemName(i),"face") )/************************************************************/
|
|
{
|
|
int j;
|
|
|
|
FaceIterator fi=Allocator<OpenMeshType>::AddFaces(m,n);
|
|
pf.SetCurElement(i);
|
|
|
|
for(j=0;j<n;++j)
|
|
{
|
|
int k;
|
|
|
|
if(pi.cb && (j%1000)==0) pi.cb(50+j*50/n,"Face Loading");
|
|
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 & ply::PLYMask::PM_WEDGCOLOR ) || ( pi.mask & ply::PLYMask::PM_WEDGTEXCOORD ) )
|
|
{
|
|
pi.status = PlyInfo::E_NO_3VERTINFACE;
|
|
return pi.status;
|
|
}
|
|
}
|
|
|
|
if( pi.mask & ply::PLYMask::PM_FACEFLAGS )
|
|
{
|
|
(*fi).UberFlags() = fa.flags;
|
|
}
|
|
|
|
if( pi.mask & ply::PLYMask::PM_FACEQUALITY )
|
|
{
|
|
(*fi).Q() = fa.q;
|
|
}
|
|
|
|
if( pi.mask & ply::PLYMask::PM_FACECOLOR )
|
|
{
|
|
(*fi).C()[0] = fa.r;
|
|
(*fi).C()[1] = fa.g;
|
|
(*fi).C()[2] = fa.b;
|
|
(*fi).C()[3] = 255;
|
|
}
|
|
|
|
if( pi.mask & ply::PLYMask::PM_WEDGTEXCOORD )
|
|
{
|
|
for(int k=0;k<3;++k)
|
|
{
|
|
(*fi).WT(k).u() = fa.tcoord[k*2+0];
|
|
(*fi).WT(k).v() = fa.tcoord[k*2+1];
|
|
if(multit) (*fi).WT(k).n() = fa.tcoordind;
|
|
else (*fi).WT(k).n()=0; // safely intialize texture index
|
|
}
|
|
}
|
|
|
|
if( pi.mask & ply::PLYMask::PM_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()){
|
|
{
|
|
(*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);
|
|
}
|
|
}
|
|
}
|
|
/// Now the temporary struct 'fa' is ready to be copied into the real face '*fi'
|
|
/// This loop
|
|
for(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] ];
|
|
}
|
|
|
|
for(k=0;k<pi.fdn;k++)
|
|
memcpy((char *)(&(*fi)) + pi.FaceData[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;
|
|
}
|
|
for(int qq=0;qq<fa.size-3;++qq)
|
|
{
|
|
(*fi).V(0) = index[ fa.v[0] ];
|
|
for(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] ];
|
|
}
|
|
|
|
for(k=0;k<pi.fdn;k++)
|
|
memcpy((char *)(&(*fi)) + pi.FaceData[k].offset1,
|
|
(char *)(&fa) + FPV[k].offset1, FPV[k].memtypesize());
|
|
++fi;
|
|
}
|
|
|
|
}
|
|
}else if( !strcmp( pf.ElemName(i),"tristrips") )//////////////////// LETTURA TRISTRIP DI STANFORD
|
|
{
|
|
int j;
|
|
pf.SetCurElement(i);
|
|
int numvert_tmp = (int)m.vert.size();
|
|
for(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 pi.status;
|
|
}
|
|
int remainder=0;
|
|
//int startface=m.face.size();
|
|
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 pi.status;
|
|
}
|
|
if(tsa.v[k+2]==-1)
|
|
{
|
|
k+=2;
|
|
if(k%2) remainder=0;
|
|
else remainder=1;
|
|
continue;
|
|
}
|
|
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) math::Swap (tf.V(0), tf.V(1) );
|
|
m.face.push_back( tf );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Skippaggio elementi non gestiti
|
|
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();
|
|
|
|
for(int co=0;co<int(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 i,j,n;
|
|
|
|
if( TFILE == c.substr(0,TFILE.length()) )
|
|
{
|
|
bufstr = c.substr(TFILE.length()+1);
|
|
n = bufstr.length();
|
|
for(i=0;i<n;i++)
|
|
if( bufstr[i]!=' ' && bufstr[i]!='\t' && bufstr[i]>32 && bufstr[i]<125 ) bufclean.push_back(bufstr[i]);
|
|
|
|
char buf2[255];
|
|
ply::interpret_texture_name( bufclean.c_str(),filename,buf2 );
|
|
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;
|
|
VertexIterator vi;
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
if( ! (*vi).IsD() )
|
|
++m.vn;
|
|
|
|
m.fn = 0;
|
|
FaceIterator fi;
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
if( ! (*fi).IsD() )
|
|
++m.fn;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Caricamento camera da un ply
|
|
int LoadCamera(const char * filename)
|
|
{
|
|
vcg::ply::PlyFile pf;
|
|
if( pf.Open(filename,vcg::ply::PlyFile::MODE_READ)==-1 )
|
|
{
|
|
this->pi.status = pf.GetError();
|
|
return this->pi.status;
|
|
}
|
|
|
|
|
|
bool found = true;
|
|
int i;
|
|
for(i=0;i<23;++i)
|
|
{
|
|
if( pf.AddToRead(CameraDesc(i))==-1 )
|
|
{
|
|
found = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
return this->pi.status;
|
|
|
|
for(i=0;i<int(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 )
|
|
{
|
|
this->pi.status = PlyInfo::E_SHORTFILE;
|
|
return this->pi.status;
|
|
}
|
|
this->camera.valid = true;
|
|
this->camera.view_p[0] = ca.view_px;
|
|
this->camera.view_p[1] = ca.view_py;
|
|
this->camera.view_p[2] = ca.view_pz;
|
|
this->camera.x_axis[0] = ca.x_axisx;
|
|
this->camera.x_axis[1] = ca.x_axisy;
|
|
this->camera.x_axis[2] = ca.x_axisz;
|
|
this->camera.y_axis[0] = ca.y_axisx;
|
|
this->camera.y_axis[1] = ca.y_axisy;
|
|
this->camera.y_axis[2] = ca.y_axisz;
|
|
this->camera.z_axis[0] = ca.z_axisx;
|
|
this->camera.z_axis[1] = ca.z_axisy;
|
|
this->camera.z_axis[2] = ca.z_axisz;
|
|
this->camera.f = ca.focal;
|
|
this->camera.s[0] = ca.scalex;
|
|
this->camera.s[1] = ca.scaley;
|
|
this->camera.c[0] = ca.centerx;
|
|
this->camera.c[1] = ca.centery;
|
|
this->camera.viewport[0] = ca.viewportx;
|
|
this->camera.viewport[1] = ca.viewporty;
|
|
this->camera.k[0] = ca.k1;
|
|
this->camera.k[1] = ca.k2;
|
|
this->camera.k[2] = ca.k3;
|
|
this->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 |= ply::PLYMask::PM_VERTCOORD;
|
|
|
|
if( pf.AddToRead(VertDesc(3))!=-1 ) mask |= ply::PLYMask::PM_VERTFLAGS;
|
|
if( pf.AddToRead(VertDesc(4))!=-1 ) mask |= ply::PLYMask::PM_VERTQUALITY;
|
|
if( pf.AddToRead(VertDesc(8))!=-1 ) mask |= ply::PLYMask::PM_VERTQUALITY;
|
|
if( ( pf.AddToRead(VertDesc(5))!=-1 ) &&
|
|
( pf.AddToRead(VertDesc(6))!=-1 ) &&
|
|
( pf.AddToRead(VertDesc(7))!=-1 ) ) mask |= ply::PLYMask::PM_VERTCOLOR;
|
|
|
|
if( pf.AddToRead(FaceDesc(0))!=-1 ) mask |= ply::PLYMask::PM_FACEINDEX;
|
|
if( pf.AddToRead(FaceDesc(1))!=-1 ) mask |= ply::PLYMask::PM_FACEFLAGS;
|
|
|
|
if( pf.AddToRead(FaceDesc(2))!=-1 ) mask |= ply::PLYMask::PM_FACEQUALITY;
|
|
if( pf.AddToRead(FaceDesc(3))!=-1 ) mask |= ply::PLYMask::PM_WEDGTEXCOORD;
|
|
if( pf.AddToRead(FaceDesc(5))!=-1 ) mask |= ply::PLYMask::PM_WEDGTEXMULTI;
|
|
if( pf.AddToRead(FaceDesc(4))!=-1 ) mask |= ply::PLYMask::PM_WEDGCOLOR;
|
|
if( ( pf.AddToRead(FaceDesc(6))!=-1 ) &&
|
|
( pf.AddToRead(FaceDesc(7))!=-1 ) &&
|
|
( pf.AddToRead(FaceDesc(8))!=-1 ) ) mask |= ply::PLYMask::PM_FACECOLOR;
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
}; // end class
|
|
|
|
|
|
|
|
} // end namespace tri
|
|
} // end namespace io
|
|
} // end namespace vcg
|
|
|
|
#endif
|