Visualization Library 2.1.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ioPLY.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #include "ioPLY.hpp"
33 #include <vlCore/Log.hpp>
34 #include <vlCore/Say.hpp>
36 #include <vlCore/FileSystem.hpp>
37 #include <vlCore/TextStream.hpp>
38 #include <vlCore/VirtualFile.hpp>
39 #include <vlGraphics/Effect.hpp>
40 #include <vlGraphics/Actor.hpp>
42 
43 using namespace vl;
44 //-----------------------------------------------------------------------------
46 {
48 
49  if (file)
50  return loadPLY( file.get() );
51  else
52  {
53  Log::error( Say("Could not locate '%s'.\n") << path );
54  return NULL;
55  }
56 }
57 //-----------------------------------------------------------------------------
59 {
60  PlyLoader ply;
61  ref<ResourceDatabase> res_db = ply.loadPly(file);
62  return res_db;
63 }
64 //-----------------------------------------------------------------------------
66 {
67  switch(scalarType())
68  {
69  case PlyChar: mData.mChar = file->readSInt8(); break;
70  case PlyUChar: mData.mUChar = file->readUInt8(); break;
71  case PlyShort: mData.mShort = file->readSInt16(le); break;
72  case PlyUShort: mData.mUShort = file->readUInt16(le); break;
73  case PlyInt: mData.mInt = file->readSInt32(le); break;
74  case PlyUInt: mData.mUInt = file->readUInt32(le); break;
75  case PlyFloat: mData.mFloat = file->readFloat(le); break;
76  case PlyDouble: mData.mDouble = file->readDouble(le); break;
77  default:
78  Log::error("PlyLoader: scalar read error.\n");
79  }
80 }
82 {
83  int idata;
84  double ddata;
85  switch(scalarType())
86  {
87  case PlyChar: text->readInt(idata); mData.mChar = (char)idata; break;
88  case PlyUChar: text->readInt(idata); mData.mUChar = (unsigned char)idata; break;
89  case PlyShort: text->readInt(idata); mData.mShort = (short)idata; break;
90  case PlyUShort: text->readInt(idata); mData.mUShort = (unsigned short)idata; break;
91  case PlyInt: text->readInt(idata); mData.mInt = (int)idata; break;
92  case PlyUInt: text->readInt(idata); mData.mUInt = (unsigned int)idata; break;
93  case PlyFloat: text->readDouble(ddata); mData.mFloat = (float)ddata; break;
94  case PlyDouble: text->readDouble(ddata); mData.mDouble = (double)ddata; break;
95  default:
96  Log::error("PlyLoader: scalar read error.\n");
97  }
98 }
100 {
101  switch(scalarType())
102  {
103  case PlyChar: return (float)mData.mChar;
104  case PlyUChar: return (float)mData.mUChar;
105  case PlyShort: return (float)mData.mShort;
106  case PlyUShort: return (float)mData.mUShort;
107  case PlyInt: return (float)mData.mInt;
108  case PlyUInt: return (float)mData.mUInt;
109  case PlyFloat: return mData.mFloat;
110  case PlyDouble: return (float)mData.mDouble;
111  default:
112  Log::error("PlyLoader: getAsFloat() error.\n");
113  return 0.0f;
114  }
115 }
117 {
118  switch(scalarType())
119  {
120  case PlyChar: return (int)mData.mChar;
121  case PlyUChar: return (int)mData.mUChar;
122  case PlyShort: return (int)mData.mShort;
123  case PlyUShort: return (int)mData.mUShort;
124  case PlyInt: return (int)mData.mInt;
125  case PlyUInt: return (int)mData.mUInt;
126  case PlyFloat: return (int)mData.mFloat;
127  case PlyDouble: return (int)mData.mDouble;
128  default:
129  Log::error("PlyLoader: getAsFloat() error.\n");
130  return 0;
131  }
132 }
134 {
135  mVertex.resize(3);
136  mNormal.resize(3);
137  mColor.resize(4);
138  if (name() == "vertex")
139  {
140  for(unsigned int j=0; j<properties().size(); ++j)
141  {
142  PlyScalar* scalar = cast<PlyScalar>(properties()[j].get()); VL_CHECK(scalar)
143  if (scalar)
144  {
145  if (scalar->name() == "x")
146  mVertex[0] = scalar;
147  else
148  if (scalar->name() == "y")
149  mVertex[1] = scalar;
150  else
151  if (scalar->name() == "z")
152  mVertex[2] = scalar;
153  else
154  if (scalar->name() == "nx")
155  mNormal[0] = scalar;
156  else
157  if (scalar->name() == "ny")
158  mNormal[1] = scalar;
159  else
160  if (scalar->name() == "nz")
161  mNormal[2] = scalar;
162  else
163  if (scalar->name() == "red")
164  mColor[0] = scalar;
165  else
166  if (scalar->name() == "green")
167  mColor[1] = scalar;
168  else
169  if (scalar->name() == "blue")
170  mColor[2] = scalar;
171  else
172  if (scalar->name() == "alpha")
173  mColor[3] = scalar;
174  }
175  }
176  }
177 }
179 {
180  // reposition to the correct location
181  file->seekSet(0);
182  std::string str;
183  do
184  {
185  unsigned char ch = file->readUInt8();
186  if (ch == '\n' && str == "end_header")
187  break;
188  if (ch == '\n')
189  {
190  str.clear();
191  continue;
192  }
193  str.push_back( ch );
194  } while(true);
195 
196  for(unsigned i=0; i<mElements.size(); ++i)
197  for(int j=0; j<mElements[i]->elemCount(); ++j)
198  {
199  mElements[i]->read(file, littleEndian());
200  newElement(mElements[i].get());
201  }
202 }
204 {
205  for(unsigned i=0; i<mElements.size(); ++i)
206  for(int j=0; j<mElements[i]->elemCount(); ++j)
207  {
208  mElements[i]->read(text);
209  newElement(mElements[i].get());
210  }
211 }
213 {
214  if (el->name() == "vertex")
215  {
216  for(unsigned int j=0; j<el->properties().size(); ++j)
217  {
218  if (mVerts)
219  mVerts->at(mVertexIndex) = el->getVertex();
220  if (mNormals)
221  mNormals->at(mVertexIndex) = el->getNormal();
222  if (mColors)
223  mColors->at(mVertexIndex) = el->getColor();
224  }
225 
226  ++mVertexIndex;
227  }
228  else
229  if (el->name() == "face")
230  {
231  for(unsigned int j=0; j<el->properties().size(); ++j)
232  {
233  PlyScalarList* list = cast<PlyScalarList>(el->properties()[j].get()); VL_CHECK(list)
234  if (list && list->name() == "vertex_indices")
235  {
236  for(int i=1; i<(int)list->scalars().size()-1; ++i)
237  {
238  if (mIndices.capacity() - mIndices.size() == 0)
239  mIndices.reserve( mIndices.capacity() * 2 );
240  mIndices.push_back( list->scalars()[0].getAsInt());
241  mIndices.push_back( list->scalars()[i].getAsInt());
242  mIndices.push_back( list->scalars()[i+1].getAsInt());
243  }
244  }
245  }
246  }
247 }
249 {
250  if (type == "int8") return PlyChar; else
251  if (type == "char") return PlyChar; else
252  if (type == "uint8") return PlyChar; else
253  if (type == "uchar") return PlyUChar; else
254  if (type == "ushort") return PlyUShort; else
255  if (type == "uint16") return PlyUShort; else
256  if (type == "short") return PlyShort; else
257  if (type == "int16") return PlyShort; else
258  if (type == "int") return PlyInt; else
259  if (type == "int32") return PlyInt; else
260  if (type == "uint") return PlyUInt; else
261  if (type == "uint32") return PlyUInt; else
262  if (type == "float") return PlyFloat; else
263  if (type == "float32") return PlyFloat; else
264  if (type == "float64") return PlyDouble; else
265  if (type == "double") return PlyDouble;
266  else
267  {
268  Log::error("PlyLoader: type parse error.\n");
269  return PlyError;
270  }
271 }
273 {
274  // allocate space for vertices, normals and colors.
275  for(unsigned int i=0; i<elements().size(); ++i)
276  {
277  if (elements()[i]->name() == "vertex")
278  {
279  for(unsigned int j=0; j<elements()[i]->properties().size(); ++j)
280  {
281  if (elements()[i]->properties()[j]->name() == "x")
282  {
283  mVerts = new ArrayFloat3;
284  mVerts->resize( elements()[i]->elemCount() );
285  }
286  if (elements()[i]->properties()[j]->name() == "nx")
287  {
288  mNormals = new ArrayFloat3;
289  mNormals->resize( elements()[i]->elemCount() );
290  }
291  if (elements()[i]->properties()[j]->name() == "red")
292  {
293  mColors = new ArrayUByte4;
294  mColors->resize( elements()[i]->elemCount() );
295  memset(mColors->ptr(), 0xFF, sizeof(mColors->at(0))*mColors->size());
296  }
297  }
298  elements()[i]->analyze();
299  }
300  }
301  if (mVerts->size() == 0)
302  {
303  Log::error("PlyLoader: no vertices found.\n");
304  }
305 }
307 {
308  mVerts = NULL;
309  mNormals = NULL;
310  mColors = NULL;
311  mIndices.reserve(100);
312  bool ok = true;
313  elements().clear();
314  String str;
315  // ply loader
316  line_reader->readLineLF(str);
317  if (str.trim() != "ply")
318  return false;
319  // format
320  line_reader->readLineLF(str);
321  if (str.trim() == "format ascii 1.0")
322  {
323  mBinary = false;
324  }
325  else
326  if (str.trim() == "format binary_little_endian 1.0")
327  {
328  mBinary = true;
329  mLittleEndian = true;
330  }
331  else
332  if (str.trim() == "format binary_big_endian 1.0")
333  {
334  mBinary = true;
335  mLittleEndian = false;
336  }
337  else
338  return false;
339  // read elements
340  while ( (line_reader->readLineLF(str)) && str.trim() != "end_header")
341  {
342  if (str.startsWith("comment"))
343  continue;
344  else
345  if (str.startsWith("element"))
346  {
347  elements().push_back(new PlyElement);
348  elements().back()->setName( str.field(' ',1) );
349  elements().back()->setElemCount( str.field(' ',2).toInt() );
350  }
351  else
352  if (str.startsWith("property"))
353  {
354  String prop_type = str.field(' ',1);
355  ref<PlyScalar> prop;
356  ref<PlyScalarList> scalar_list;
357  if (prop_type == "list")
358  {
359  String num_type = str.field(' ',2);
360  String idx_type = str.field(' ',3);
361  String name = str.field(' ',4);
362  if (name.empty())
363  {
364  Log::error("PLY parse error #5.\n");
365  return false;
366  }
367 
368  scalar_list = new PlyScalarList;
369  elements().back()->properties().push_back(scalar_list);
370 
371  scalar_list->setCountType(translateType(num_type));
372  scalar_list->setScalarType(translateType(idx_type));
373  scalar_list->setName(name);
374  }
375  else
376  {
377  prop = new PlyScalar;
378  elements().back()->properties().push_back(prop);
379  prop->setName( str.field(' ',2) );
380  prop->setScalarType(translateType(prop_type));
381  }
382  }
383  else
384  {
385  Log::error("PLY parse error #2.\n");
386  return false;
387  }
388  }
389  analyzeHeader();
390  mVertexIndex = 0;
391  return ok;
392 }
394 {
395  ref<TextStream> line_reader = new TextStream;
396 
397  line_reader->setInputFile(file);
398 
399  readHeader(line_reader.get());
400 
401  if (binary())
402  readElements(file);
403  else
404  readElements(line_reader.get());
405  file->close();
406 
407  if (mIndices.empty() || !mVerts)
408  return NULL;
409 
410  ref<Geometry> geom = new Geometry;
411  geom->setVertexArray(mVerts.get());
412  geom->setNormalArray(mNormals.get());
413  geom->setColorArray(mColors.get());
415  geom->drawCalls().push_back(de.get());
416  de->indexBuffer()->resize(mIndices.size());
417  memcpy(de->indexBuffer()->ptr(), &mIndices[0], sizeof(unsigned int)*mIndices.size());
418 
419  // Effect
420  ref<Effect> effect = new Effect;
421 
422  // Detph test
423  effect->shader()->enable(EN_DEPTH_TEST);
424 
425  // Lighting
426  if( mNormals )
427  effect->shader()->enable(EN_LIGHTING);
428 
429  // note: we don't insert any light
430  if (mColors)
431  effect->shader()->gocMaterial()->setColorMaterialEnabled(true);
432 
434  res_db->resources().push_back( new Actor(geom.get(), effect.get(), NULL ) );
435  return res_db;
436 }
437 //-----------------------------------------------------------------------------
Associates a Renderable object to an Effect and Transform.
Definition: Actor.hpp:130
bool mBinary
Definition: ioPLY.hpp:259
VLCORE_EXPORT FileSystem * defFileSystem()
Returns the default FileSystem used by VisualizationLibrary.
Definition: pimpl.cpp:97
float getAsFloat() const
Definition: ioPLY.cpp:99
Used by PlyLoader.
Definition: ioPLY.hpp:118
Used by PlyLoader.
Definition: ioPLY.hpp:183
const T * get() const
Definition: Object.hpp:128
An abstract class representing a file.
Definition: VirtualFile.hpp:60
If enabled, do depth comparisons and update the depth buffer; Note that even if the depth buffer exis...
A simple String formatting class.
Definition: Say.hpp:124
std::vector< unsigned int > mIndices
Definition: ioPLY.hpp:257
The String class implements an advanced UTF16 (Unicode BMP) string manipulation engine.
Definition: String.hpp:62
If enabled, use the current lighting parameters to compute the vertex color; Otherwise, simply associate the current color with each vertex, see also Material, LightModel, and Light.
virtual void read(VirtualFile *file, bool le)
Definition: ioPLY.cpp:65
int readSInt32(bool little_endian_data=true)
Reads single entry.
const std::vector< PlyScalar > & scalars() const
Definition: ioPLY.hpp:151
ref< ArrayFloat3 > mNormals
Definition: ioPLY.hpp:255
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
void setVertexArray(ArrayAbstract *data)
Conventional vertex array.
Definition: Geometry.cpp:155
virtual ref< VirtualFile > locateFile(const String &full_path, const String &alternate_path=String()) const
Looks for a VirtualFile on the disk and in the currently active FileSystem.
Definition: FileSystem.cpp:61
void resize(size_t dim)
Definition: Array.hpp:233
short readSInt16(bool little_endian_data=true)
Reads single entry.
void setNormalArray(ArrayAbstract *data)
Conventional normal array.
Definition: Geometry.cpp:164
void setColorArray(const fvec4 &color)
Fills the color array with the given color.
Definition: Geometry.hpp:108
fvec3 getNormal() const
Definition: ioPLY.hpp:211
int mVertexIndex
Definition: ioPLY.hpp:258
const String & name() const
Definition: ioPLY.hpp:187
int toInt(bool hex=false) const
Returns the int number represented by the string. The conversion is done using the standard atoi() fu...
Definition: String.cpp:1352
String & trim(wchar_t ch)
Removes the specified character ch from the beginning and the end of the String.
Definition: String.cpp:322
float readFloat(bool little_endian_data=true)
Reads single entry.
void setInputFile(VirtualFile *file)
fvec3 getVertex() const
Definition: ioPLY.hpp:203
virtual void close()=0
Closes the file.
EType translateType(const String &type)
Definition: ioPLY.cpp:248
ubvec4 getColor() const
Definition: ioPLY.hpp:219
The Geometry class is a Renderable that implements a polygonal mesh made of polygons, lines and points.
Definition: Geometry.hpp:66
const std::vector< ref< PlyElement > > & elements() const
Definition: ioPLY.hpp:242
Visualization Library main namespace.
const String & name() const
Definition: ioPLY.hpp:110
const unsigned char * ptr() const
Returns the pointer to the first element of the local buffer. Equivalent to bufferObject()->ptr() ...
Definition: Array.hpp:103
void newElement(PlyElement *el)
Definition: ioPLY.cpp:212
The TextStream class can be used to conveniently read or parse utf8-encoded text files.
Definition: TextStream.hpp:46
EType scalarType() const
Definition: ioPLY.hpp:123
bool readHeader(TextStream *line_reader)
Definition: ioPLY.cpp:306
bool binary() const
Definition: ioPLY.hpp:244
const std::vector< ref< Object > > & resources() const
bool readDouble(double &d)
Definition: TextStream.cpp:50
std::vector< ref< PlyElement > > mElements
Definition: ioPLY.hpp:253
void analyzeHeader()
Definition: ioPLY.cpp:272
See DrawElements.
Loads a PLY file.
Definition: ioPLY.hpp:91
union vl::PlyLoader::PlyScalar::@12 mData
unsigned char readUInt8()
Reads single entry.
ref< ResourceDatabase > loadPly(VirtualFile *file)
Loads a PLY file.
Definition: ioPLY.cpp:393
bool mLittleEndian
Definition: ioPLY.hpp:260
bool empty() const
Returns true if length() == 0.
Definition: String.hpp:136
bool littleEndian() const
Definition: ioPLY.hpp:245
bool startsWith(const String &str) const
Returns true if a String starts with the specified String str.
Definition: String.cpp:720
ref< ArrayUByte4 > mColors
Definition: ioPLY.hpp:256
Used by PlyLoader.
Definition: ioPLY.hpp:143
int getAsInt() const
Definition: ioPLY.cpp:116
#define NULL
Definition: OpenGLDefs.hpp:81
arr_type * indexBuffer()
The BufferObject containing the indices used to render.
Shader * shader(int lodi=0, int pass=0)
Utility function, same as &#39;lod(lodi)->at(pass);&#39;.
Definition: Effect.hpp:178
bool seekSet(long long offset)
Changes the current read/write position of a file.
Defines the sequence of Shader objects used to render an Actor.
Definition: Effect.hpp:91
void readElements(VirtualFile *file)
Definition: ioPLY.cpp:178
An array of vl::ubvec4.
Definition: Array.hpp:461
unsigned short readUInt16(bool little_endian_data=true)
Reads single entry.
char readSInt8()
Reads single entry.
unsigned int readUInt32(bool little_endian_data=true)
Reads single entry.
VLGRAPHICS_EXPORT ref< ResourceDatabase > loadPLY(VirtualFile *file)
Definition: ioPLY.cpp:58
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
An array of vl::fvec3.
Definition: Array.hpp:414
#define VL_CHECK(expr)
Definition: checks.hpp:73
void enable(EEnable capability)
Definition: Shader.hpp:2158
const std::vector< ref< PlyPropertyAbstract > > & properties() const
Definition: ioPLY.hpp:189
ref< ArrayFloat3 > mVerts
Definition: ioPLY.hpp:254
String field(wchar_t separator, int field_index) const
Splits a String into a set of fields based on the specified separator and returns the filed at positi...
Definition: String.cpp:453
bool readLineLF(String &line)
Reads a LF terminated line.
Definition: TextStream.hpp:146
The ResourceDatabase class contains and manipulates a set of resources.
double readDouble(bool little_endian_data=true)
Reads single entry.
Collection< DrawCall > & drawCalls()
Returns the list of DrawCall objects bound to a Geometry.
Definition: Geometry.hpp:102
bool readInt(int &i, bool hex=false)
Definition: TextStream.cpp:38