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