Visual Computing Library  devel
Loading...
Searching...
No Matches
header.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2026 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_IO_MESH_PLY_DETAIL_HEADER_H
24#define VCL_IO_MESH_PLY_DETAIL_HEADER_H
25
26#include "ply.h"
27
28#include <vclib/io/file_info.h>
29#include <vclib/io/mesh/settings.h>
30#include <vclib/io/read.h>
31
32#include <vclib/space/complex.h>
33
34#include <clocale>
35#include <string>
36#include <vector>
37
38namespace vcl::detail {
39
45class PlyHeader
46{
47 bool mValid = false;
48
49 ply::Format mFormat = ply::UNKNOWN;
50
51 std::vector<PlyElement> mElements;
52 std::vector<std::string> mTextureFiles;
53
54 // for each element, its position in the mElements vector
55 uint mVertElemPos = UINT_NULL;
56 uint mFaceElemPos = UINT_NULL;
57 uint mEdgeElemPos = UINT_NULL;
58 uint mTriStripElemPos = UINT_NULL;
59 uint mMaterialElemPos = UINT_NULL;
60
61public:
62 using iterator = std::vector<PlyElement>::const_iterator;
63
64 PlyHeader() = default;
65
66 PlyHeader(ply::Format format, const MeshInfo& info) :
67 mValid(true), mFormat(format)
68 {
69 setInfo(info, format);
70 }
71
72 PlyHeader(std::istream& file, const std::string& filename = "")
73 {
74 clear();
75
76 std::string line;
77 std::getline(file, line);
78 removeCarriageReturn(line);
79 if (line.compare(0, 3, "ply") == 0) {
80 bool error = false;
81 bool firstElement = true;
82 std::string headerLine;
83 PlyElement element;
84 do {
85 Tokenizer spaceTokenizer =
86 readAndTokenizeNextNonEmptyLine(file);
87 if (!error) {
88 Tokenizer::iterator token = spaceTokenizer.begin();
89 headerLine = *token;
90 if (headerLine == "format") {
91 token++;
92 if (*token == "ascii")
93 mFormat = ply::ASCII;
94 else if (
95 *token == "binary_little_endian" ||
96 *token == "binary")
97 mFormat = ply::BINARY_LITTLE_ENDIAN;
98 else if (*token == "binary_big_endian")
99 mFormat = ply::BINARY_BIG_ENDIAN;
100 }
101 // reading a comment, may be a texture file...
102 else if (headerLine == "comment") {
103 token++;
104 if (token != spaceTokenizer.end()) {
105 if (containsCaseInsensitive(*token, "texture")) {
106 ++token;
107 if (token != spaceTokenizer.end()) {
108 std::string textName = *token;
109 auto it =
110 findCaseInsensitive(textName, "<this>");
111 if (it != textName.end()) {
112 uint pos = it - textName.begin();
113 std::string fn =
115 filename);
116 textName =
117 textName.substr(0, pos) + fn +
118 textName.substr(
119 pos + 6, textName.size());
120 }
121 mTextureFiles.push_back(textName);
122 }
123 }
124 }
125 }
126 // I am reading a new element
127 else if (headerLine == "element") {
128 // if it is not the first element to read, it means that
129 // the previous one needs to be saved
130 if (!firstElement) {
131 // index of each element type in elements vector
132 if (element.type == ply::VERTEX)
133 mVertElemPos = mElements.size();
134 if (element.type == ply::FACE)
135 mFaceElemPos = mElements.size();
136 if (element.type == ply::EDGE)
137 mEdgeElemPos = mElements.size();
138 if (element.type == ply::TRISTRIP)
139 mTriStripElemPos = mElements.size();
140 if (element.type == ply::MATERIAL)
141 mMaterialElemPos = mElements.size();
142 mElements.push_back(element);
143 element = PlyElement();
144 }
145 element = readElement(spaceTokenizer);
146 firstElement = false;
147 }
148 else if (headerLine == "property") {
149 PlyProperty p = readProperty(spaceTokenizer);
150 element.properties.push_back(p);
151 }
152 // save the last element
153 else if (headerLine == "end_header") {
154 if (element.type == ply::VERTEX)
155 mVertElemPos = mElements.size();
156 if (element.type == ply::FACE)
157 mFaceElemPos = mElements.size();
158 if (element.type == ply::EDGE)
159 mEdgeElemPos = mElements.size();
160 if (element.type == ply::TRISTRIP)
161 mTriStripElemPos = mElements.size();
162 if (element.type == ply::MATERIAL)
163 mMaterialElemPos = mElements.size();
164 mElements.push_back(element);
165 }
166 }
167 } while (!error && headerLine != "end_header");
168 mValid = !error && hasVertices();
169 }
170 }
171
172 void clear()
173 {
174 mFormat = ply::UNKNOWN;
175 mElements.clear();
176 mTextureFiles.clear();
177 mValid = false;
178
179 mVertElemPos = UINT_NULL;
180 mFaceElemPos = UINT_NULL;
181 mEdgeElemPos = UINT_NULL;
182 mTriStripElemPos = UINT_NULL;
183 }
184
185 bool isValid() const { return mValid; }
186
187 ply::Format format() const { return mFormat; }
188
189 MeshInfo getInfo() const
190 {
191 MeshInfo mod;
192 // x, y, z, nx, ny, nz, red, green, blue, alpha, vertex_indices
193
194 if (mVertElemPos != UINT_NULL) {
195 mod.setVertices();
196 for (const PlyProperty& p : mElements[mVertElemPos].properties) {
197 switch (p.name) {
198 case ply::x:
199 case ply::y:
200 case ply::z: mod.setPerVertexPosition(); break;
201 case ply::nx:
202 case ply::ny:
203 case ply::nz: mod.setPerVertexNormal(); break;
204 case ply::red:
205 case ply::green:
206 case ply::blue:
207 case ply::alpha: mod.setPerVertexColor(); break;
208 case ply::quality: mod.setPerVertexQuality(); break;
209 case ply::texture_u: mod.setPerVertexTexCoord(); break;
210 case ply::material_index:
211 mod.setPerVertexMaterialIndex();
212 break;
213 case ply::unknown:
214 if (p.type <= ply::PropertyType::DOUBLE) {
215 mod.addPerVertexCustomComponent(
216 p.unknownPropertyName, (MeshInfo::DataType) p.type);
217 }
218 default: break;
219 }
220 }
221 }
222 if (mFaceElemPos != UINT_NULL) {
223 mod.setFaces();
224 for (const PlyProperty& p : mElements[mFaceElemPos].properties) {
225 switch (p.name) {
226 case ply::vertex_indices:
227 mod.setPerFaceVertexReferences();
228 break;
229 case ply::nx:
230 case ply::ny:
231 case ply::nz: mod.setPerFaceNormal(); break;
232 case ply::red:
233 case ply::green:
234 case ply::blue:
235 case ply::alpha: mod.setPerFaceColor(); break;
236 case ply::quality: mod.setPerFaceQuality(); break;
237 case ply::material_index: mod.setPerFaceMaterialIndex(); break;
238 case ply::texcoord: mod.setPerFaceWedgeTexCoords(); break;
239 case ply::unknown:
240 if (p.type <= ply::PropertyType::DOUBLE) {
241 mod.addPerFaceCustomComponent(
242 p.unknownPropertyName, (MeshInfo::DataType) p.type);
243 }
244 default: break;
245 }
246 }
247 }
248 if (mTriStripElemPos != UINT_NULL) {
249 mod.setFaces();
250 for (const PlyProperty& p :
251 mElements[mTriStripElemPos].properties) {
252 switch (p.name) {
253 case ply::vertex_indices:
254 mod.setPerFaceVertexReferences();
255 break;
256 case ply::nx:
257 case ply::ny:
258 case ply::nz: mod.setPerFaceNormal(); break;
259 case ply::red:
260 case ply::green:
261 case ply::blue:
262 case ply::alpha: mod.setPerFaceColor(); break;
263 case ply::quality: mod.setPerFaceQuality(); break;
264 case ply::texcoord: mod.setPerFaceWedgeTexCoords(); break;
265 default: break;
266 }
267 }
268 }
269 if (mEdgeElemPos != UINT_NULL) {
270 mod.setEdges();
271 for (const PlyProperty& p : mElements[mEdgeElemPos].properties) {
272 switch (p.name) {
273 case ply::vertex_indices:
274 mod.setPerEdgeVertexReferences();
275 break;
276 case ply::nx:
277 case ply::ny:
278 case ply::nz: mod.setPerEdgeNormal(); break;
279 case ply::red:
280 case ply::green:
281 case ply::blue:
282 case ply::alpha: mod.setPerEdgeColor(); break;
283 case ply::quality: mod.setPerEdgeQuality(); break;
284 default: break;
285 }
286 }
287 }
288 if (mMaterialElemPos != UINT_NULL || mTextureFiles.size() > 0) {
289 mod.setMaterials();
290 }
291 return mod;
292 }
293
294 bool hasVertices() const { return mVertElemPos != UINT_NULL; }
295
296 bool hasFaces() const { return mFaceElemPos != UINT_NULL; }
297
298 bool hasEdges() const { return mEdgeElemPos != UINT_NULL; }
299
300 bool hasTriStrips() const { return mTriStripElemPos != UINT_NULL; }
301
302 bool hasMaterials() const { return mMaterialElemPos != UINT_NULL; }
303
304 uint vertexCount() const
305 {
306 assert(hasVertices());
307 return mElements[mVertElemPos].elementCount;
308 }
309
310 uint faceCount() const
311 {
312 assert(hasFaces());
313 return mElements[mFaceElemPos].elementCount;
314 }
315
316 uint edgeCount() const
317 {
318 assert(hasEdges());
319 return mElements[mEdgeElemPos].elementCount;
320 }
321
322 uint triStripCount() const
323 {
324 assert(hasTriStrips());
325 return mElements[mTriStripElemPos].elementCount;
326 }
327
328 uint materialCount() const
329 {
330 assert(hasMaterials());
331 return mElements[mMaterialElemPos].elementCount;
332 }
333
334 uint textureFileNameCount() const { return mTextureFiles.size(); }
335
336 const std::list<PlyProperty>& vertexProperties() const
337 {
338 assert(hasVertices());
339 return mElements[mVertElemPos].properties;
340 }
341
342 const std::list<PlyProperty>& faceProperties() const
343 {
344 assert(hasFaces());
345 return mElements[mFaceElemPos].properties;
346 }
347
348 const std::list<PlyProperty>& edgeProperties() const
349 {
350 assert(hasEdges());
351 return mElements[mEdgeElemPos].properties;
352 }
353
354 const std::list<PlyProperty>& triStripsProperties() const
355 {
356 assert(hasTriStrips());
357 return mElements[mTriStripElemPos].properties;
358 }
359
360 const std::list<PlyProperty>& materialProperties() const
361 {
362 assert(hasMaterials());
363 return mElements[mMaterialElemPos].properties;
364 }
365
366 const std::vector<std::string>& textureFileNames() const
367 {
368 return mTextureFiles;
369 }
370
371 bool errorWhileLoading() const { return !mValid; }
372
373 void setVertexCount(unsigned long int nV)
374 {
375 assert(hasVertices());
376 mElements[mVertElemPos].elementCount = nV;
377 }
378
379 void setFaceCount(unsigned long int nF)
380 {
381 assert(hasFaces());
382 mElements[mFaceElemPos].elementCount = nF;
383 }
384
385 void setEdgeCount(unsigned long int nE)
386 {
387 assert(hasEdges());
388 mElements[mEdgeElemPos].elementCount = nE;
389 }
390
391 void setMaterialCount(unsigned long int nM)
392 {
393 assert(hasMaterials());
394 mElements[mMaterialElemPos].elementCount = nM;
395 }
396
397 void pushTextureFileName(const std::string& tn)
398 {
399 mTextureFiles.push_back(tn);
400 }
401
402 void setInfo(
403 const MeshInfo& info,
404 ply::Format format = ply::BINARY_LITTLE_ENDIAN)
405 {
406 clear();
407 mFormat = format;
408 mValid = true;
409 if (info.hasVertices()) {
410 mVertElemPos = mElements.size();
411 PlyElement vElem;
412 vElem.type = ply::VERTEX;
413 if (info.hasPerVertexPosition()) {
414 PlyProperty px, py, pz;
415 px.name = ply::x;
416 px.type = info.perVertexPositionType();
417 py.name = ply::y;
418 py.type = info.perVertexPositionType();
419 pz.name = ply::z;
420 pz.type = info.perVertexPositionType();
421 vElem.properties.push_back(px);
422 vElem.properties.push_back(py);
423 vElem.properties.push_back(pz);
424 }
425 if (info.hasPerVertexNormal()) {
426 PlyProperty vnx, vny, vnz;
427 vnx.name = ply::nx;
428 vnx.type = info.perVertexNormalType();
429 vny.name = ply::ny;
430 vny.type = info.perVertexNormalType();
431 vnz.name = ply::nz;
432 vnz.type = info.perVertexNormalType();
433 vElem.properties.push_back(vnx);
434 vElem.properties.push_back(vny);
435 vElem.properties.push_back(vnz);
436 }
437 if (info.hasPerVertexColor()) {
438 PlyProperty vcr, vcg, vcb, vca;
439 vcr.name = ply::red;
440 vcr.type = info.perVertexColorType();
441 vcg.name = ply::green;
442 vcg.type = info.perVertexColorType();
443 vcb.name = ply::blue;
444 vcb.type = info.perVertexColorType();
445 vca.name = ply::alpha;
446 vca.type = info.perVertexColorType();
447 vElem.properties.push_back(vcr);
448 vElem.properties.push_back(vcg);
449 vElem.properties.push_back(vcb);
450 vElem.properties.push_back(vca);
451 }
452 if (info.hasPerVertexQuality()) {
453 PlyProperty vs;
454 vs.name = ply::quality;
455 vs.type = info.perVertexQualityType();
456 vElem.properties.push_back(vs);
457 }
458 if (info.hasPerVertexTexCoord()) {
459 PlyProperty tcu, tcv;
460 tcu.name = ply::texture_u;
461 tcu.type = info.perVertexTexCoordType();
462 tcv.name = ply::texture_v;
463 tcv.type = info.perVertexTexCoordType();
464 vElem.properties.push_back(tcu);
465 vElem.properties.push_back(tcv);
466 }
467 if (info.hasPerVertexMaterialIndex()) {
468 PlyProperty tcn;
469 tcn.name = ply::material_index;
470 tcn.type = info.perVertexMaterialIndexType();
471 vElem.properties.push_back(tcn);
472 }
473 if (info.hasPerVertexCustomComponents()) {
474 for (const auto& cc : info.perVertexCustomComponents()) {
475 if (cc.type <= PrimitiveType::DOUBLE) {
476 PlyProperty pp;
477 pp.name = ply::unknown;
478 pp.unknownPropertyName = cc.name;
479 pp.type = cc.type;
480 vElem.properties.push_back(pp);
481 }
482 }
483 }
484 mElements.push_back(vElem);
485 }
486 if (info.hasFaces()) {
487 mFaceElemPos = mElements.size();
488 PlyElement fElem;
489 fElem.type = ply::FACE;
490 if (info.hasPerFaceVertexReferences()) {
491 PlyProperty vids;
492 vids.list = true;
493 vids.name = ply::vertex_indices;
494 vids.type = PrimitiveType::UINT;
495 vids.listSizeType = PrimitiveType::UCHAR;
496 fElem.properties.push_back(vids);
497 }
498 if (info.hasPerFaceNormal()) {
499 PlyProperty fnx, fny, fnz;
500 fnx.name = ply::nx;
501 fnx.type = info.perFaceNormalType();
502 fny.name = ply::ny;
503 fny.type = info.perFaceNormalType();
504 fnz.name = ply::nz;
505 fnz.type = info.perFaceNormalType();
506 fElem.properties.push_back(fnx);
507 fElem.properties.push_back(fny);
508 fElem.properties.push_back(fnz);
509 }
510 if (info.hasPerFaceColor()) {
511 PlyProperty fcr, fcg, fcb, fca;
512 fcr.name = ply::red;
513 fcr.type = info.perFaceColorType();
514 fcg.name = ply::green;
515 fcg.type = info.perFaceColorType();
516 fcb.name = ply::blue;
517 fcb.type = info.perFaceColorType();
518 fca.name = ply::alpha;
519 fca.type = info.perFaceColorType();
520 fElem.properties.push_back(fcr);
521 fElem.properties.push_back(fcg);
522 fElem.properties.push_back(fcb);
523 fElem.properties.push_back(fca);
524 }
525 if (info.hasPerFaceQuality()) {
526 PlyProperty fs;
527 fs.name = ply::quality;
528 fs.type = info.perFaceQualityType();
529 fElem.properties.push_back(fs);
530 }
531 if (info.hasPerFaceWedgeTexCoords()) {
532 PlyProperty tc;
533 tc.list = true;
534 tc.listSizeType = PrimitiveType::UCHAR;
535 tc.name = ply::texcoord;
536 tc.type = info.perFaceWedgeTexCoordsType();
537 fElem.properties.push_back(tc);
538 }
539 if (info.hasPerFaceMaterialIndex()) {
540 PlyProperty tn;
541 tn.name = ply::material_index;
542 tn.type = info.perFaceMaterialIndexType();
543 fElem.properties.push_back(tn);
544 }
545 if (info.hasPerFaceCustomComponents()) {
546 for (const auto& cc : info.perFaceCustomComponents()) {
547 if (cc.type <= PrimitiveType::DOUBLE) {
548 PlyProperty pp;
549 pp.name = ply::unknown;
550 pp.unknownPropertyName = cc.name;
551 pp.type = cc.type;
552 fElem.properties.push_back(pp);
553 }
554 }
555 }
556 mElements.push_back(fElem);
557 }
558 if (info.hasEdges()) {
559 mEdgeElemPos = mElements.size();
560 PlyElement eElem;
561 eElem.type = ply::EDGE;
562 if (info.hasPerEdgeVertexReferences()) {
563 PlyProperty v1;
564 v1.name = ply::vertex1;
565 v1.type = PrimitiveType::UINT;
566 eElem.properties.push_back(v1);
567 PlyProperty v2;
568 v2.name = ply::vertex2;
569 v2.type = PrimitiveType::UINT;
570 eElem.properties.push_back(v2);
571 }
572 mElements.push_back(eElem);
573 }
574 if (info.hasMaterials()) {
575 mMaterialElemPos = mElements.size();
576 PlyElement matElem;
577 matElem.type = ply::MATERIAL;
578 // base color
579 PlyProperty bcr, bcg, bcb, bca;
580 bcr.name = ply::red;
581 bcr.type = PrimitiveType::UCHAR;
582 bcg.name = ply::green;
583 bcg.type = PrimitiveType::UCHAR;
584 bcb.name = ply::blue;
585 bcb.type = PrimitiveType::UCHAR;
586 bca.name = ply::alpha;
587 bca.type = PrimitiveType::UCHAR;
588 matElem.properties.push_back(bcr);
589 matElem.properties.push_back(bcg);
590 matElem.properties.push_back(bcb);
591 matElem.properties.push_back(bca);
592 // metallic, roughness
593 PlyProperty pm, pr;
594 pm.name = ply::metallic;
595 pm.type = PrimitiveType::FLOAT;
596 pr.name = ply::roughness;
597 pr.type = PrimitiveType::FLOAT;
598 matElem.properties.push_back(pm);
599 matElem.properties.push_back(pr);
600 // emissive color
601 PlyProperty ecr, ecg, ecb;
602 ecr.name = ply::emissive_red;
603 ecr.type = PrimitiveType::UCHAR;
604 ecg.name = ply::emissive_green;
605 ecg.type = PrimitiveType::UCHAR;
606 ecb.name = ply::emissive_blue;
607 ecb.type = PrimitiveType::UCHAR;
608 matElem.properties.push_back(ecr);
609 matElem.properties.push_back(ecg);
610 matElem.properties.push_back(ecb);
611 // alpha mode, alpha cutoff
612 PlyProperty pam, pac;
613 pam.name = ply::alpha_mode;
614 pam.type = PrimitiveType::UINT;
615 pac.name = ply::alpha_cutoff;
616 pac.type = PrimitiveType::FLOAT;
617 matElem.properties.push_back(pam);
618 matElem.properties.push_back(pac);
619 // normal scale, occlusion strength
620 PlyProperty pns, pos;
621 pns.name = ply::normal_scale;
622 pns.type = PrimitiveType::FLOAT;
623 pos.name = ply::occlusion_strength;
624 pos.type = PrimitiveType::FLOAT;
625 matElem.properties.push_back(pns);
626 matElem.properties.push_back(pos);
627 // double sided
628 PlyProperty pds;
629 pds.name = ply::double_sided;
630 pds.type = PrimitiveType::UINT;
631 matElem.properties.push_back(pds);
632 // textures
633 PlyProperty pt;
634 pt.name = ply::base_color_texture;
635 pt.list = true;
636 pt.listSizeType =
637 PrimitiveType::UCHAR; // keep list-size as UCHAR because MeshLab
638 // expects an 8-bit length for char/string
639 // lists in PLY; using a wider type (e.g.
640 // UINT) causes MeshLab to misinterpret
641 // these texture filename properties
642 pt.type = PrimitiveType::CHAR;
643 matElem.properties.push_back(pt);
644 pt.name = ply::metallic_roughness_texture;
645 matElem.properties.push_back(pt);
646 pt.name = ply::normal_texture;
647 matElem.properties.push_back(pt);
648 pt.name = ply::occlusion_texture;
649 matElem.properties.push_back(pt);
650 pt.name = ply::emissive_texture;
651 matElem.properties.push_back(pt);
652 // material name
653 pt.name = ply::name;
654 matElem.properties.push_back(pt);
655
656 mElements.push_back(matElem);
657 }
658 }
659
660 std::string toString(const SaveSettings& settings) const
661 {
662 std::string s;
663
664 s += "ply\nformat ";
665
666 switch (mFormat) {
667 case ply::ASCII: s += "ascii 1.0\n"; break;
668 case ply::BINARY_BIG_ENDIAN: s += "binary_big_endian 1.0\n"; break;
669 default: s += "binary_little_endian 1.0\n"; break;
670 }
671
672 s += "comment Generated by vclib\n";
673 if (settings.meshlabCompatibility) {
674 for (const std::string& str : mTextureFiles) {
675 s += "comment TextureFile " + str + "\n";
676 }
677 }
678 for (const PlyElement& e : mElements) {
679 s += "element ";
680 switch (e.type) {
681 case ply::VERTEX:
682 s += "vertex " + std::to_string(e.elementCount) + "\n";
683 break;
684 case ply::FACE:
685 s += "face " + std::to_string(e.elementCount) + "\n";
686 break;
687 case ply::EDGE:
688 s += "edge " + std::to_string(e.elementCount) + "\n";
689 break;
690 case ply::TRISTRIP:
691 s += "tristrips " + std::to_string(e.elementCount) + "\n";
692 break;
693 case ply::MATERIAL:
694 s += "material " + std::to_string(e.elementCount) + "\n";
695 break;
696 case ply::OTHER:
697 s += e.unknownElementType + " " +
698 std::to_string(e.elementCount) + "\n";
699 break;
700 }
701 for (const PlyProperty& p : e.properties) {
702 s += "property ";
703 if (p.list) {
704 s += "list ";
705 s += typeToString(p.listSizeType) + " ";
706 }
707 s += typeToString(p.type) + " ";
708 if (p.name == ply::unknown)
709 s += p.unknownPropertyName + "\n";
710 else
711 s += nameToString(p.name, settings.meshlabCompatibility) +
712 "\n";
713 }
714 }
715 s += "end_header\n";
716
717 return s;
718 }
719
720 void setFormat(ply::Format f) { mFormat = f; }
721
722 iterator begin() const { return mElements.begin(); }
723
724 iterator end() const { return mElements.end(); }
725
726private:
727 static PlyElement readElement(const Tokenizer& lineTokenizer)
728 {
729 PlyElement e;
730 Tokenizer::iterator token = lineTokenizer.begin();
731 std::string s = *(++token);
732 if (s == "vertex") {
733 e.type = ply::VERTEX;
734 e.elementCount = std::stoi(*(++token));
735 }
736 else if (s == "face") {
737 e.type = ply::FACE;
738 e.elementCount = std::stoi(*(++token));
739 }
740 else if (s == "edge") {
741 e.type = ply::EDGE;
742 e.elementCount = std::stoi(*(++token));
743 }
744 else if (s == "tristrips") {
745 e.type = ply::TRISTRIP;
746 e.elementCount = std::stoi(*(++token));
747 }
748 else if (s == "material") {
749 e.type = ply::MATERIAL;
750 e.elementCount = std::stoi(*(++token));
751 }
752 else {
753 e.type = ply::OTHER;
754 e.elementCount = std::stoi(*(++token));
755 e.unknownElementType = s;
756 }
757 return e;
758 }
759
760 static PlyProperty readProperty(const Tokenizer& lineTokenizer)
761 {
762 PlyProperty p;
763 Tokenizer::iterator token = lineTokenizer.begin();
764 std::string type = *(++token);
765 if (type == "list") {
766 p.list = true;
767 std::string typeSize = *(++token);
768 std::string typeData = *(++token);
769 std::string name = *(++token);
770 p.listSizeType = stringToType(typeSize);
771 p.type = stringToType(typeData);
772 p.name = stringToName(name);
773 if (p.name == ply::unknown)
774 p.unknownPropertyName = name;
775 }
776 else {
777 p.list = false;
778 std::string name = *(++token);
779 p.type = stringToType(type);
780 p.name = stringToName(name);
781 if (p.name == ply::unknown)
782 p.unknownPropertyName = name;
783 }
784
785 return p;
786 }
787
788 static ply::PropertyName stringToName(const std::string& name)
789 {
790 ply::PropertyName pn = ply::unknown;
791 if (name == "x")
792 pn = ply::x;
793 if (name == "y")
794 pn = ply::y;
795 if (name == "z")
796 pn = ply::z;
797 if (name == "nx")
798 pn = ply::nx;
799 if (name == "ny")
800 pn = ply::ny;
801 if (name == "nz")
802 pn = ply::nz;
803 if (name == "red")
804 pn = ply::red;
805 if (name == "green")
806 pn = ply::green;
807 if (name == "blue")
808 pn = ply::blue;
809 if (name == "alpha")
810 pn = ply::alpha;
811 if (name == "quality" || name == "scalar")
812 pn = ply::quality;
813 if (name == "texture_u" || name == "s" || name == "u")
814 pn = ply::texture_u;
815 if (name == "texture_v" || name == "t" || name == "v")
816 pn = ply::texture_v;
817 if (name == "material_index" || name == "texnumber")
818 pn = ply::material_index;
819 if (name == "vertex_indices")
820 pn = ply::vertex_indices;
821 if (name == "texcoord")
822 pn = ply::texcoord;
823 if (name == "vertex1")
824 pn = ply::vertex1;
825 if (name == "vertex2")
826 pn = ply::vertex2;
827 if (name == "name")
828 pn = ply::name;
829 if (name == "metallic")
830 pn = ply::metallic;
831 if (name == "roughness")
832 pn = ply::roughness;
833 if (name == "emissive_red")
834 pn = ply::emissive_red;
835 if (name == "emissive_green")
836 pn = ply::emissive_green;
837 if (name == "emissive_blue")
838 pn = ply::emissive_blue;
839 if (name == "alpha_mode")
840 pn = ply::alpha_mode;
841 if (name == "alpha_cutoff")
842 pn = ply::alpha_cutoff;
843 if (name == "normal_scale")
844 pn = ply::normal_scale;
845 if (name == "occlusion_strength")
846 pn = ply::occlusion_strength;
847 if (name == "double_sided")
848 pn = ply::double_sided;
849 if (name == "base_color_texture")
850 pn = ply::base_color_texture;
851 if (name == "metallic_roughness_texture")
852 pn = ply::metallic_roughness_texture;
853 if (name == "normal_texture")
854 pn = ply::normal_texture;
855 if (name == "occlusion_texture")
856 pn = ply::occlusion_texture;
857 if (name == "emissive_texture")
858 pn = ply::emissive_texture;
859
860 return pn;
861 }
862
863 static ply::PropertyType stringToType(const std::string& type)
864 {
865 ply::PropertyType pt = ply::PropertyType::UCHAR;
866 if (type == "char")
867 pt = ply::PropertyType::CHAR;
868 if (type == "uchar")
869 pt = ply::PropertyType::UCHAR;
870 if (type == "short")
871 pt = ply::PropertyType::SHORT;
872 if (type == "ushort")
873 pt = ply::PropertyType::USHORT;
874 if (type == "int")
875 pt = ply::PropertyType::INT;
876 if (type == "uint")
877 pt = ply::PropertyType::UINT;
878 if (type == "float")
879 pt = ply::PropertyType::FLOAT;
880 if (type == "double")
881 pt = ply::PropertyType::DOUBLE;
882 return pt;
883 }
884
885 static std::string nameToString(
886 ply::PropertyName n,
887 bool meshlabCompatibility = false)
888 {
889 switch (n) {
890 case ply::x: return "x";
891 case ply::y: return "y";
892 case ply::z: return "z";
893 case ply::nx: return "nx";
894 case ply::ny: return "ny";
895 case ply::nz: return "nz";
896 case ply::red: return "red";
897 case ply::green: return "green";
898 case ply::blue: return "blue";
899 case ply::alpha: return "alpha";
900 case ply::quality: return "quality";
901 case ply::texture_u: return "texture_u";
902 case ply::texture_v: return "texture_v";
903 case ply::material_index:
904 return meshlabCompatibility ? "texnumber" : "material_index";
905 case ply::vertex_indices: return "vertex_indices";
906 case ply::texcoord: return "texcoord";
907 case ply::vertex1: return "vertex1";
908 case ply::vertex2: return "vertex2";
909 case ply::name: return "name";
910 case ply::metallic: return "metallic";
911 case ply::roughness: return "roughness";
912 case ply::emissive_red: return "emissive_red";
913 case ply::emissive_green: return "emissive_green";
914 case ply::emissive_blue: return "emissive_blue";
915 case ply::alpha_mode: return "alpha_mode";
916 case ply::alpha_cutoff: return "alpha_cutoff";
917 case ply::normal_scale: return "normal_scale";
918 case ply::occlusion_strength: return "occlusion_strength";
919 case ply::double_sided: return "double_sided";
920 case ply::base_color_texture: return "base_color_texture";
921 case ply::metallic_roughness_texture:
922 return "metallic_roughness_texture";
923 case ply::normal_texture: return "normal_texture";
924 case ply::occlusion_texture: return "occlusion_texture";
925 case ply::emissive_texture: return "emissive_texture";
926 default: return "unknown";
927 }
928 }
929
930 static std::string typeToString(ply::PropertyType t)
931 {
932 switch (t) {
933 case ply::PropertyType::CHAR: return "char";
934 case ply::PropertyType::UCHAR: return "uchar";
935 case ply::PropertyType::SHORT: return "short";
936 case ply::PropertyType::USHORT: return "ushort";
937 case ply::PropertyType::INT: return "int";
938 case ply::PropertyType::UINT: return "uint";
939 case ply::PropertyType::FLOAT: return "float";
940 case ply::PropertyType::DOUBLE: return "double";
941 case ply::PropertyType::NONE: return "";
942 }
943 return "";
944 }
945};
946
947} // namespace vcl::detail
948
949#endif // VCL_IO_MESH_PLY_DETAIL_HEADER_H
static std::string fileNameWithoutExtension(const std::string &fullpath)
Get the file name without extension of a file.
Definition file_info.h:220
PrimitiveType DataType
Enum used to describe the type of Data stored in a component.
Definition mesh_info.h:114
constexpr uint UINT_NULL
The UINT_NULL value represent a null value of uint that is the maximum value that can be represented ...
Definition base.h:49