1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #include "ply_loader.h"
5 #include <list>
6 
7 namespace embree
8 {
9   namespace SceneGraph
10   {
11     /*! PLY type */
12     struct Type {
13       enum Tag { PTY_CHAR, PTY_UCHAR, PTY_SHORT, PTY_USHORT, PTY_INT, PTY_UINT, PTY_FLOAT, PTY_DOUBLE, PTY_LIST, PTY_NONE } ty, index, data;
Typeembree::SceneGraph::Type14       Type() : ty(PTY_NONE), index(PTY_NONE), data(PTY_NONE) {}
Typeembree::SceneGraph::Type15       Type(Tag ty) : ty(ty), index(PTY_NONE), data(PTY_NONE) {}
Typeembree::SceneGraph::Type16       Type(Tag ty, Tag index, Tag data) : ty(ty), index(index), data(data) {}
17     };
18 
19     /*! an element stored in the PLY file, such as vertex, face, etc. */
20     struct Element {
21       std::string name;
22       size_t size;                             /// number of data items of the element
23       std::vector<std::string> properties;     /// list of all properties of the element (e.g. x, y, z) (not strictly necessary)
24       std::map<std::string,Type> type;         /// mapping of property name to type
25       std::map<std::string,std::vector<float> > data;                /// data array properties (all represented as floats)
26       std::map<std::string,std::vector<std::vector<size_t> > > list; /// list properties (integer lists supported only)
27     };
28 
29     /*! mesh structure that reflects the PLY file format */
30     struct Mesh {
31       std::vector<std::string> order;           /// order of all elements in file (not strictly necessary)
32       std::map<std::string,Element> elements;   /// all elements of the file, e.g. vertex, face, ...
33     };
34 
35     /* returns the size of a type in bytes */
sizeOfType(Type::Tag ty)36     size_t sizeOfType(Type::Tag ty)
37     {
38       switch (ty) {
39       case Type::PTY_CHAR : return 1;
40       case Type::PTY_UCHAR : return 1;
41       case Type::PTY_SHORT : return 2;
42       case Type::PTY_USHORT : return 2;
43       case Type::PTY_INT : return 4;
44       case Type::PTY_UINT : return 4;
45       case Type::PTY_FLOAT : return 4;
46       case Type::PTY_DOUBLE : return 8;
47       default : throw std::runtime_error("invalid type");
48       }
49     }
50 
51     /* compute the type of a string */
typeTagOfString(const std::string & ty)52     Type::Tag typeTagOfString(const std::string& ty) {
53       if (ty == "char") return Type::PTY_CHAR;
54       if (ty == "int8") return Type::PTY_CHAR;
55       if (ty == "uchar") return Type::PTY_UCHAR;
56       if (ty == "uint8") return Type::PTY_UCHAR;
57       if (ty == "short") return Type::PTY_SHORT;
58       if (ty == "int16") return Type::PTY_SHORT;
59       if (ty == "ushort") return Type::PTY_USHORT;
60       if (ty == "uint16") return Type::PTY_USHORT;
61       if (ty == "int") return Type::PTY_INT;
62       if (ty == "int32") return Type::PTY_INT;
63       if (ty == "uint") return Type::PTY_UINT;
64       if (ty == "uint32") return Type::PTY_UINT;
65       if (ty == "float") return Type::PTY_FLOAT;
66       if (ty == "float32") return Type::PTY_FLOAT;
67       if (ty == "double") return Type::PTY_DOUBLE;
68       throw std::runtime_error("invalid type " + ty);
69       return Type::PTY_NONE;
70     }
71 
72     /* compute the type of a string */
stringOfTypeTag(Type::Tag ty)73     std::string stringOfTypeTag(Type::Tag ty) {
74       if (ty == Type::PTY_CHAR) return "char";
75       if (ty == Type::PTY_UCHAR) return "uchar";
76       if (ty == Type::PTY_SHORT) return "short";
77       if (ty == Type::PTY_USHORT) return "ushort";
78       if (ty == Type::PTY_INT) return "int";
79       if (ty == Type::PTY_UINT) return "uint";
80       if (ty == Type::PTY_FLOAT) return "float";
81       if (ty == Type::PTY_DOUBLE) return "double";
82       if (ty == Type::PTY_LIST) return "list";
83       throw std::runtime_error("invalid type");
84       return "";
85     }
86 
87     /* compute the type of a string */
stringOfType(Type ty)88     std::string stringOfType(Type ty) {
89       if (ty.ty == Type::PTY_LIST) return "list " + stringOfTypeTag(ty.index) + " " + stringOfTypeTag(ty.data);
90       else return stringOfTypeTag(ty.ty);
91     }
92 
93     /* PLY parser class */
94     struct PlyParser
95     {
96       std::fstream fs;
97       Mesh mesh;
98       Ref<SceneGraph::Node> scene;
99 
100       /* storage format of data in file */
101       enum Format { ASCII, BINARY_BIG_ENDIAN, BINARY_LITTLE_ENDIAN } format;
102 
103       /* constructor parses the input stream */
PlyParserembree::SceneGraph::PlyParser104       PlyParser(const FileName& fileName) : format(ASCII)
105       {
106         /* open file */
107         fs.open (fileName.c_str(), std::fstream::in | std::fstream::binary);
108         if (!fs.is_open()) throw std::runtime_error("cannot open file : " + fileName.str());
109 
110         /* check for file signature */
111         std::string signature; getline(fs,signature);
112         if (signature != "ply") throw std::runtime_error("invalid PLY file signature: " + signature);
113 
114         /* read header */
115         std::list<std::string> header;
116         while (true) {
117           std::string line; getline(fs,line);
118           if (line == "end_header") break;
119           if (line.find_first_of('#') == 0) continue;
120           if (line == "") continue;
121           header.push_back(line);
122         }
123 
124         /* parse header */
125         parseHeader(header);
126 
127         /* now parse all elements */
128         for (std::vector<std::string>::iterator i = mesh.order.begin(); i!=mesh.order.end(); i++)
129           parseElementData(mesh.elements[*i]);
130 
131         /* create triangle mesh */
132         scene = import();
133       }
134 
135       /* parse the PLY header */
parseHeaderembree::SceneGraph::PlyParser136       void parseHeader(std::list<std::string>& header)
137       {
138         while (!header.empty())
139         {
140           std::stringstream line(header.front());
141           header.pop_front();
142 
143           std::string tag; line >> tag;
144 
145           /* ignore comments */
146           if (tag == "comment") {
147           }
148 
149           /* parse format */
150           else if (tag == "format")
151           {
152             std::string fmt; line >> fmt;
153             if (fmt == "ascii") format = ASCII;
154             else if (fmt == "binary_big_endian") format = BINARY_BIG_ENDIAN;
155             else if (fmt == "binary_little_endian") format = BINARY_LITTLE_ENDIAN;
156             else throw std::runtime_error("invalid PLY file format: " + fmt);
157             std::string  version; line >> version;
158             if (version != "1.0") throw std::runtime_error("invalid PLY file version: " + version);
159           }
160 
161           /* parse end of header tag */
162           else if (tag == "end_header")
163             break;
164 
165           /* parse elements */
166           else if (tag == "element") parseElementDescr(line,header);
167 
168           /* report unknown tags */
169           else throw std::runtime_error("unknown tag in PLY file: " + tag);
170         }
171       }
172 
173       /* parses a PLY element description */
parseElementDescrembree::SceneGraph::PlyParser174       void parseElementDescr(std::stringstream& cin, std::list<std::string>& header)
175       {
176         Element elt;
177         std::string name; cin >> name;
178         size_t num; cin >> num;
179         mesh.order.push_back(name);
180         elt.name = name;
181         elt.size = num;
182 
183         /* parse all properties */
184         while (!header.empty())
185         {
186           std::stringstream line(header.front());
187           std::string tag; line >> tag;
188           if (tag != "property") break;
189           header.pop_front();
190 
191           Type ty = parseType(line);
192           std::string name; line >> name;
193           elt.type[name] = ty;
194           elt.properties.push_back(name);
195         }
196 
197         mesh.elements[name] = elt;
198       }
199 
200       /* parses a PLY type */
parseTypeembree::SceneGraph::PlyParser201       Type parseType(std::stringstream& cin)
202       {
203         std::string ty; cin >> ty;
204         if (ty == "list") {
205           std::string ty0; cin >> ty0;
206           std::string ty1; cin >> ty1;
207           return Type(Type::PTY_LIST,typeTagOfString(ty0),typeTagOfString(ty1));
208         } else return Type(typeTagOfString(ty));
209       }
210 
211       /* parses data of a PLY element */
parseElementDataembree::SceneGraph::PlyParser212       void parseElementData(Element& elt)
213       {
214         /* allocate data for all properties */
215         for (std::vector<std::string>::iterator i=elt.properties.begin(); i!=elt.properties.end(); i++) {
216           if (elt.type[*i].ty == Type::PTY_LIST) elt.list[*i] = std::vector<std::vector<size_t> >();
217           else elt.data[*i] = std::vector<float>();
218         }
219 
220         /* parse all elements */
221         for (size_t e=0; e<elt.size; e++)
222         {
223           /* load all properties of the element */
224           for (std::vector<std::string>::iterator i=elt.properties.begin(); i!=elt.properties.end(); i++) {
225             Type ty = elt.type[*i];
226             if (ty.ty == Type::PTY_LIST) loadPropertyList(elt.list[*i],ty.index,ty.data);
227             else loadPropertyData(elt.data[*i],ty.ty);
228           }
229         }
230       }
231 
232       /* load bytes from file and take care of little and big endian encoding */
readBytesembree::SceneGraph::PlyParser233       void readBytes(void* dst, int num) {
234         if (format == BINARY_LITTLE_ENDIAN) fs.read((char*)dst,num);
235         else if (format == BINARY_BIG_ENDIAN) for (int i=0; i<num; i++) fs.read((char*)dst+num-i-1,1);
236         else throw std::runtime_error("internal error on PLY loader");
237       }
238 
read_ascii_intembree::SceneGraph::PlyParser239       int            read_ascii_int  () { int i;   fs >> i; return i; }
read_ascii_floatembree::SceneGraph::PlyParser240       float          read_ascii_float() { float f; fs >> f; return f; }
read_charembree::SceneGraph::PlyParser241       signed char    read_char  () { if (format == ASCII) return read_ascii_int();   signed char r = 0;    readBytes(&r,1); return r; }
read_ucharembree::SceneGraph::PlyParser242       unsigned char  read_uchar () { if (format == ASCII) return read_ascii_int();   unsigned char r = 0;  readBytes(&r,1); return r; }
read_shortembree::SceneGraph::PlyParser243       signed short   read_short () { if (format == ASCII) return read_ascii_int();   signed short r = 0;   readBytes(&r,2); return r; }
read_ushortembree::SceneGraph::PlyParser244       unsigned short read_ushort() { if (format == ASCII) return read_ascii_int();   unsigned short r = 0; readBytes(&r,2); return r; }
read_intembree::SceneGraph::PlyParser245       signed int     read_int   () { if (format == ASCII) return read_ascii_int();   signed int r = 0;     readBytes(&r,4); return r; }
read_uintembree::SceneGraph::PlyParser246       unsigned int   read_uint  () { if (format == ASCII) return read_ascii_int();   unsigned int r = 0;   readBytes(&r,4); return r; }
read_floatembree::SceneGraph::PlyParser247       float          read_float () { if (format == ASCII) return read_ascii_float(); float r = 0;          readBytes(&r,4); return r; }
read_doubleembree::SceneGraph::PlyParser248       double         read_double() { if (format == ASCII) return read_ascii_float(); double r = 0;         readBytes(&r,8); return r; }
249 
250       /* load an integer type */
loadIntegerembree::SceneGraph::PlyParser251       size_t loadInteger(Type::Tag ty)
252       {
253         switch (ty) {
254         case Type::PTY_CHAR   : return read_char(); break;
255         case Type::PTY_UCHAR  : return read_uchar(); break;
256         case Type::PTY_SHORT  : return read_short(); break;
257         case Type::PTY_USHORT : return read_ushort(); break;
258         case Type::PTY_INT    : return read_int(); break;
259         case Type::PTY_UINT   : return read_uint(); break;
260         default : throw std::runtime_error("invalid type"); return 0;
261         }
262       }
263 
264       /* load a list */
loadPropertyListembree::SceneGraph::PlyParser265       void loadPropertyList(std::vector<std::vector<size_t> >& vec,Type::Tag index_ty,Type::Tag data_ty)
266       {
267         std::vector<size_t> lst;
268         size_t num = loadInteger(index_ty);
269         for (size_t i=0; i<num; i++) lst.push_back(loadInteger(data_ty));
270         vec.push_back(lst);
271       }
272 
273       /* load a data element */
loadPropertyDataembree::SceneGraph::PlyParser274       void loadPropertyData(std::vector<float>& vec, Type::Tag ty)
275       {
276         switch (ty) {
277         case Type::PTY_CHAR   : vec.push_back(float(read_char()));   break;
278         case Type::PTY_UCHAR  : vec.push_back(float(read_uchar()));  break;
279         case Type::PTY_SHORT  : vec.push_back(float(read_short()));  break;
280         case Type::PTY_USHORT : vec.push_back(float(read_ushort())); break;
281         case Type::PTY_INT    : vec.push_back(float(read_int()));    break;
282         case Type::PTY_UINT   : vec.push_back(float(read_uint()));   break;
283         case Type::PTY_FLOAT  : vec.push_back(float(read_float()));  break;
284         case Type::PTY_DOUBLE : vec.push_back(float(read_double())); break;
285         default : throw std::runtime_error("invalid type");
286         }
287       }
288 
importembree::SceneGraph::PlyParser289       Ref<SceneGraph::Node> import()
290       {
291         Ref<SceneGraph::MaterialNode> material = new OBJMaterial;
292         Ref<SceneGraph::TriangleMeshNode> mesh_o = new SceneGraph::TriangleMeshNode(material,BBox1f(0,1),1);
293 
294         /* convert all vertices */
295         const Element& vertices = mesh.elements.at("vertex");
296         const std::vector<float>& posx = vertices.data.at("x");
297         const std::vector<float>& posy = vertices.data.at("y");
298         const std::vector<float>& posz = vertices.data.at("z");
299 
300         mesh_o->positions[0].resize(vertices.size);
301         for (size_t i=0; i<vertices.size; i++) {
302           mesh_o->positions[0][i].x = posx[i];
303           mesh_o->positions[0][i].y = posy[i];
304           mesh_o->positions[0][i].z = posz[i];
305         }
306 
307         /* convert all faces */
308         const Element& faces = mesh.elements.at("face");
309         const std::vector<std::vector<size_t> >& polygons = faces.list.at("vertex_indices");
310 
311         for (size_t j=0; j<polygons.size(); j++)
312         {
313           const std::vector<size_t>& face = polygons[j];
314           if (face.size() < 3) continue;
315 
316           /* triangulate the face with a triangle fan */
317           size_t i0 = face[0], i1 = 0, i2 = face[1];
318           for (size_t k=2; k<face.size(); k++) {
319             i1 = i2; i2 = face[k];
320             mesh_o->triangles.push_back(SceneGraph::TriangleMeshNode::Triangle((unsigned int)i0, (unsigned int)i1, (unsigned int)i2));
321           }
322         }
323         return mesh_o.dynamicCast<SceneGraph::Node>();
324       }
325     };
326 
loadPLY(const FileName & fileName)327     Ref<Node> loadPLY(const FileName& fileName) {
328       return PlyParser(fileName).scene;
329     }
330   }
331 }
332 
333