Visual Computing Library
Loading...
Searching...
No Matches
load.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
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_LOAD_SAVE_OFF_LOAD_H
24#define VCL_LOAD_SAVE_OFF_LOAD_H
25
26#include <vclib/algorithms/mesh/face_topology.h>
27#include <vclib/exceptions/io.h>
28#include <vclib/io/file_info.h>
29#include <vclib/io/read.h>
30#include <vclib/load_save/settings.h>
31#include <vclib/misc/logger.h>
32#include <vclib/misc/tokenizer.h>
33#include <vclib/space/complex/mesh_info.h>
34
35namespace vcl {
36
37namespace detail {
38
39constexpr float OFF_GEOMVIEW_COLOR_MAP[148][4] = {
40 {1.0f, 1.0f, 1.0f, 1.0f },
41 {1.0f, 1.0f, 1.0f, 1.0f },
42 {1.0f, 1.0f, 1.0f, 1.0f },
43 {1.0f, 1.0f, 1.0f, 1.0f },
44
45 {1.0f, 1.0f, 1.0f, 1.0f },
46 {1.0f, 1.0f, 1.0f, 1.0f },
47 {0.7f, 0.7f, 0.7f, 0.7f },
48 {0.2f, 0.2f, 0.2f, 0.2f },
49
50 {0.9f, 0.9f, 0.9f, 0.9f },
51 {0.1f, 0.1f, 0.1f, 0.1f },
52 {0.1f, 0.1f, 0.1f, 0.1f },
53 {0.8f, 0.8f, 0.8f, 0.8f },
54
55 {0.7f, 0.7f, 0.7f, 0.7f },
56 {0.7f, 0.7f, 0.7f, 0.7f },
57 {0.0f, 0.0f, 0.0f, 0.0f },
58 {0.9f, 0.9f, 0.9f, 0.9f },
59
60 {0.2f, 0.2f, 0.2f, 0.2f },
61 {0.0f, 0.0f, 0.0f, 0.0f },
62 {0.75f, 0.75f, 0.75f, 0.75f},
63 {0.8f, 0.8f, 0.8f, 0.8f },
64
65 {0.8f, 0.8f, 0.8f, 0.8f },
66 {0.0f, 0.0f, 0.0f, 0.0f },
67 {0.0f, 0.0f, 0.0f, 0.0f },
68 {0.0f, 0.0f, 0.0f, 0.0f },
69
70 {0.0f, 0.0f, 0.0f, 0.0f },
71 {0.4f, 0.4f, 0.4f, 0.4f },
72 {0.4f, 0.4f, 0.4f, 0.4f },
73 {0.8f, 0.8f, 0.8f, 0.8f },
74
75 {0.8f, 0.8f, 0.8f, 0.8f },
76 {0.7f, 0.7f, 0.7f, 0.7f },
77 {0.7f, 0.7f, 0.7f, 0.7f },
78 {0.7f, 0.7f, 0.7f, 0.7f },
79
80 {0.7f, 0.7f, 0.7f, 0.7f },
81 {0.0f, 0.0f, 0.0f, 0.0f },
82 {0.9f, 0.9f, 0.9f, 0.9f },
83 {0.0f, 0.0f, 0.0f, 0.0f },
84
85 {0.0f, 0.0f, 0.0f, 0.0f },
86 {0.75f, 0.75f, 0.75f, 0.75f},
87 {0.8f, 0.8f, 0.8f, 0.8f },
88 {0.4f, 0.4f, 0.4f, 0.4f },
89
90 {0.0f, 0.0f, 0.0f, 0.0f },
91 {0.0f, 0.0f, 0.0f, 0.0f },
92 {0.4f, 0.4f, 0.4f, 0.4f },
93 {0.8f, 0.8f, 0.8f, 0.8f },
94
95 {0.7f, 0.7f, 0.7f, 0.7f },
96 {0.7f, 0.7f, 0.7f, 0.7f },
97 {0.0f, 0.0f, 0.0f, 0.0f },
98 {0.9f, 0.9f, 0.9f, 0.9f },
99
100 {0.0f, 0.0f, 0.0f, 0.0f },
101 {0.0f, 0.0f, 0.0f, 0.0f },
102 {0.75f, 0.75f, 0.75f, 0.75f},
103 {0.8f, 0.8f, 0.8f, 0.8f },
104
105 {0.4f, 0.4f, 0.4f, 0.4f },
106 {0.0f, 0.0f, 0.0f, 0.0f },
107 {0.0f, 0.0f, 0.0f, 0.0f },
108 {0.4f, 0.4f, 0.4f, 0.4f },
109
110 {0.8f, 0.8f, 0.8f, 0.8f },
111 {0.7f, 0.7f, 0.7f, 0.7f },
112 {0.7f, 0.7f, 0.7f, 0.7f },
113 {0.0f, 0.0f, 0.0f, 0.0f },
114
115 {0.9f, 0.9f, 0.9f, 0.9f },
116 {0.0f, 0.0f, 0.0f, 0.0f },
117 {0.0f, 0.0f, 0.0f, 0.0f },
118 {0.75f, 0.75f, 0.75f, 0.75f},
119
120 {0.8f, 0.8f, 0.8f, 0.8f },
121 {0.4f, 0.4f, 0.4f, 0.4f },
122 {0.0f, 0.0f, 0.0f, 0.0f },
123 {0.0f, 0.0f, 0.0f, 0.0f },
124
125 {0.4f, 0.4f, 0.4f, 0.4f },
126 {0.8f, 0.8f, 0.8f, 0.8f },
127 {1.0f, 1.0f, 1.0f, 1.0f },
128 {1.0f, 1.0f, 1.0f, 1.0f },
129
130 {1.0f, 1.0f, 1.0f, 1.0f },
131 {1.0f, 1.0f, 1.0f, 1.0f },
132 {1.0f, 1.0f, 1.0f, 1.0f },
133 {1.0f, 1.0f, 1.0f, 1.0f },
134
135 {0.05f, 0.05f, 0.05f, 0.05f},
136 {0.7f, 0.7f, 0.7f, 0.7f },
137 {0.2f, 0.2f, 0.2f, 0.2f },
138 {0.9f, 0.9f, 0.9f, 0.9f },
139
140 {0.0f, 0.0f, 0.0f, 0.0f },
141 {0.1f, 0.1f, 0.1f, 0.1f },
142 {0.8f, 0.8f, 0.8f, 0.8f },
143 {0.7f, 0.7f, 0.7f, 0.7f },
144
145 {0.7f, 0.7f, 0.7f, 0.7f },
146 {0.7f, 0.7f, 0.7f, 0.7f },
147 {0.7f, 0.7f, 0.7f, 0.7f },
148 {0.0f, 0.0f, 0.0f, 0.0f },
149
150 {0.0f, 0.0f, 0.0f, 0.0f },
151 {0.9f, 0.9f, 0.9f, 0.9f },
152 {0.9f, 0.9f, 0.9f, 0.9f },
153 {0.0f, 0.0f, 0.0f, 0.0f },
154
155 {0.0f, 0.0f, 0.0f, 0.0f },
156 {0.0f, 0.0f, 0.0f, 0.0f },
157 {0.0f, 0.0f, 0.0f, 0.0f },
158 {0.75f, 0.75f, 0.75f, 0.75f},
159
160 {0.75f, 0.75f, 0.75f, 0.75f},
161 {0.8f, 0.8f, 0.8f, 0.8f },
162 {0.8f, 0.8f, 0.8f, 0.8f },
163 {0.0f, 0.0f, 0.0f, 0.0f },
164
165 {0.0f, 0.0f, 0.0f, 0.0f },
166 {0.0f, 0.0f, 0.0f, 0.0f },
167 {0.0f, 0.0f, 0.0f, 0.0f },
168 {0.4f, 0.4f, 0.4f, 0.4f },
169
170 {0.4f, 0.4f, 0.4f, 0.4f },
171 {0.8f, 0.8f, 0.8f, 0.8f },
172 {0.8f, 0.8f, 0.8f, 0.8f },
173 {0.7f, 0.7f, 0.7f, 0.7f },
174
175 {0.7f, 0.7f, 0.7f, 0.7f },
176 {0.7f, 0.7f, 0.7f, 0.7f },
177 {0.7f, 0.7f, 0.7f, 0.7f },
178 {0.0f, 0.0f, 0.0f, 0.0f },
179
180 {0.9f, 0.9f, 0.9f, 0.9f },
181 {0.0f, 0.0f, 0.0f, 0.0f },
182 {0.0f, 0.0f, 0.0f, 0.0f },
183 {0.75f, 0.75f, 0.75f, 0.75f},
184
185 {0.8f, 0.8f, 0.8f, 0.8f },
186 {0.4f, 0.4f, 0.4f, 0.4f },
187 {0.0f, 0.0f, 0.0f, 0.0f },
188 {0.0f, 0.0f, 0.0f, 0.0f },
189
190 {0.4f, 0.4f, 0.4f, 0.4f },
191 {0.8f, 0.8f, 0.8f, 0.8f },
192 {0.7f, 0.7f, 0.7f, 0.7f },
193 {0.7f, 0.7f, 0.7f, 0.7f },
194
195 {0.0f, 0.0f, 0.0f, 0.0f },
196 {0.9f, 0.9f, 0.9f, 0.9f },
197 {0.0f, 0.0f, 0.0f, 0.0f },
198 {0.0f, 0.0f, 0.0f, 0.0f },
199
200 {0.75f, 0.75f, 0.75f, 0.75f},
201 {0.8f, 0.8f, 0.8f, 0.8f },
202 {0.4f, 0.4f, 0.4f, 0.4f },
203 {0.0f, 0.0f, 0.0f, 0.0f },
204
205 {0.0f, 0.0f, 0.0f, 0.0f },
206 {0.4f, 0.4f, 0.4f, 0.4f },
207 {0.8f, 0.8f, 0.8f, 0.8f },
208 {0.7f, 0.7f, 0.7f, 0.7f },
209
210 {0.7f, 0.7f, 0.7f, 0.7f },
211 {0.0f, 0.0f, 0.0f, 0.0f },
212 {0.9f, 0.9f, 0.9f, 0.9f },
213 {0.0f, 0.0f, 0.0f, 0.0f },
214
215 {0.0f, 0.0f, 0.0f, 0.0f },
216 {0.75f, 0.75f, 0.75f, 0.75f},
217 {0.8f, 0.8f, 0.8f, 0.8f },
218 {0.4f, 0.4f, 0.4f, 0.4f },
219
220 {0.0f, 0.0f, 0.0f, 0.0f },
221 {0.0f, 0.0f, 0.0f, 0.0f },
222 {0.4f, 0.4f, 0.4f, 0.4f },
223 {0.8f, 0.8f, 0.8f, 0.8f }
224};
225
226inline void readOffHeader(
227 std::istream& file,
228 MeshInfo& fileInfo,
229 uint& nv,
230 uint& nf,
231 uint& ne)
232{
233 fileInfo.clear();
234 Tokenizer tokens = readAndTokenizeNextNonEmptyLine(file);
235 Tokenizer::iterator token = tokens.begin();
236 std::string header = *token;
237
238 // the OFF string is in the header go on parsing it.
239 if (header.rfind("OFF") != std::basic_string<char>::npos) {
240 for (int u = header.rfind("OFF") - 1; u >= 0; u--) {
241 if (header[u] == 'C')
242 fileInfo.setVertexColors();
243 else if (header[u] == 'N')
244 fileInfo.setVertexNormals();
245 else if (u > 0 && header[u - 1] == 'S' && header[u] == 'T')
246 fileInfo.setVertexTexCoords();
247 else if (header[u] == '4')
248 throw MalformedFileException(
249 "Unsupported Homogeneus components in OFF.");
250 else if (header[u] == 'n')
251 throw MalformedFileException("Unsupported High Dimension OFF.");
252 }
253 }
254 else
255 throw MalformedFileException("Missing OFF header in file.");
256
257 // If the file is slightly malformed and it has nvert and nface AFTER the
258 // OFF string instead of in the next line we manage it here...
259 if (tokens.size() == 1) {
260 tokens = readAndTokenizeNextNonEmptyLine(file);
261 token = tokens.begin();
262 }
263 else
264 ++token;
265
266 nv = io::readUInt<uint>(token);
267 nf = io::readUInt<uint>(token);
268 ne = io::readUInt<uint>(token);
269 if (nv > 0)
270 fileInfo.setVertices();
271 if (nf > 0)
272 fileInfo.setFaces();
273 // if (ne > 0)
274 // loadedInfo.setEdges();
275}
276
277inline Color readOffColor(Tokenizer::iterator& token, int nColorComponents)
278{
279 uint red, green, blue, alpha = 255;
280
281 if (nColorComponents == 1) {
282 uint k = io::readUInt<uint>(token);
283
284 red = OFF_GEOMVIEW_COLOR_MAP[k][0] * 255;
285 green = OFF_GEOMVIEW_COLOR_MAP[k][1] * 255;
286 blue = OFF_GEOMVIEW_COLOR_MAP[k][2] * 255;
287 alpha = OFF_GEOMVIEW_COLOR_MAP[k][3] * 255;
288 }
289 else {
290 double r = io::readDouble<double>(token);
291 double g = io::readDouble<double>(token);
292 double b = io::readDouble<double>(token);
293 double a = -1;
294 if (nColorComponents == 4) {
295 a = io::readDouble<double>(token);
296 }
297 if (r > 1 || g > 1 || b > 1) {
298 red = r;
299 green = g;
300 blue = b;
301 alpha = a != -1 ? a : alpha;
302 }
303 else {
304 red = r * 255;
305 green = g * 255;
306 blue = b * 255;
307 alpha = a != -1 ? a * 255 : alpha;
308 }
309 }
310 return Color(red, green, blue, alpha);
311}
312
313template<MeshConcept MeshType, LoggerConcept LogType>
314void readOffVertices(
315 MeshType& mesh,
316 std::istream& file,
317 const MeshInfo& fileInfo,
318 uint nv,
319 LogType& log)
320{
321 using VertexType = MeshType::VertexType;
322
323 const uint nTexCoords = fileInfo.hasVertexTexCoords() ? 2 : 0;
324
325 log.startProgress("Reading vertices", nv);
326 mesh.addVertices(nv);
327 for (uint i = 0; i < nv; i++) {
328 VertexType& v = mesh.vertex(i);
329
330 Tokenizer tokens = readAndTokenizeNextNonEmptyLine(file);
331 Tokenizer::iterator token = tokens.begin();
332
333 // Read 3 vertex coordinates
334 for (unsigned int j = 0; j < 3; j++) {
335 // Read vertex coordinate
336 v.coord()[j] = io::readDouble<double>(token);
337 }
338
339 if constexpr (HasPerVertexNormal<MeshType>) {
340 if (isPerVertexNormalAvailable(mesh) &&
341 fileInfo.hasVertexNormals()) {
342 // Read 3 normal coordinates
343 for (unsigned int j = 0; j < 3; j++) {
344 v.normal()[j] = io::readDouble<double>(token);
345 }
346 }
347 }
348 // need to read and throw away data
349 else if (fileInfo.hasVertexNormals()) {
350 for (unsigned int j = 0; j < 3; j++) {
351 io::readDouble<double>(token);
352 }
353 }
354
355 const uint nReadComponents = token - tokens.begin();
356 const int nColorComponents =
357 (int) tokens.size() - nReadComponents - nTexCoords;
358
359 if constexpr (HasPerVertexColor<MeshType>) {
360 if (isPerVertexColorAvailable(mesh) && fileInfo.hasVertexColors()) {
361 if (nColorComponents != 1 && nColorComponents != 3 &&
362 nColorComponents != 4)
363 throw MalformedFileException(
364 "Wrong number of components in line.");
365 v.color() = readOffColor(token, nColorComponents);
366 }
367 }
368 // need to read and throw away data
369 else if (fileInfo.hasVertexColors()) {
370 if (nColorComponents != 1 && nColorComponents != 3 &&
371 nColorComponents != 4)
372 throw MalformedFileException(
373 "Wrong number of components in line.");
374 readOffColor(token, nColorComponents);
375 }
376
377 if constexpr (HasPerVertexTexCoord<MeshType>) {
378 if (isPerVertexTexCoordAvailable(mesh) &&
379 fileInfo.hasVertexTexCoords()) {
380 // Read 2 tex coordinates
381 for (unsigned int j = 0; j < 2; j++) {
382 v.texCoord()[j] = io::readDouble<double>(token);
383 }
384 }
385 }
386 // need to read and throw away data
387 else if (fileInfo.hasVertexTexCoords()) {
388 for (unsigned int j = 0; j < 2; j++) {
389 io::readDouble<double>(token);
390 }
391 }
392
393 log.progress(i);
394 }
395 log.endProgress();
396}
397
398template<FaceMeshConcept MeshType, LoggerConcept LogType>
399void readOffFaces(
400 MeshType& mesh,
401 std::istream& file,
402 MeshInfo& loadedInfo,
403 uint nf,
404 const LoadSettings& settings,
405 LogType& log)
406{
407 if constexpr (HasFaces<MeshType>) {
408 using FaceType = MeshType::FaceType;
409
410 mesh.reserveFaces(nf);
411 log.startProgress("Reading faces", nf);
412
413 for (uint fid = 0; fid < nf; ++fid) {
414 Tokenizer tokens = readAndTokenizeNextNonEmptyLine(file);
415 Tokenizer::iterator token = tokens.begin();
416 mesh.addFace();
417 FaceType& f = mesh.face(mesh.faceNumber() - 1);
418
419 // read vertex indices
420 uint fSize = io::readUInt<uint>(token);
421 loadedInfo.updateMeshType(fSize);
422 // contains the vertex ids of the actual face
423 std::vector<uint> vids;
424 vids.resize(fSize);
425 // read vertex indices
426 for (uint i = 0; i < fSize; ++i) {
427 vids[i] = io::readUInt<uint>(token);
428 }
429
430 // load vertex indices into face
431 bool splitFace = false;
432 // we have a polygonal mesh
433 if constexpr (FaceType::VERTEX_NUMBER < 0) {
434 // need to resize to the right number of verts
435 f.resizeVertices(vids.size());
436 }
437 else if (FaceType::VERTEX_NUMBER != vids.size()) {
438 // we have faces with static sizes (triangles), but we are
439 // loading faces with number of verts > 3. Need to split the
440 // face we are loading in n faces!
441 splitFace = true;
442 }
443 if (!splitFace) { // classic load, no split needed
444 for (uint i = 0; i < vids.size(); ++i) {
445 if (vids[i] >= mesh.vertexNumber()) {
446 throw MalformedFileException(
447 "Bad vertex index for face " + std::to_string(i));
448 }
449 f.setVertex(i, vids[i]);
450 }
451 }
452 else { // split needed
453 addTriangleFacesFromPolygon(mesh, f, vids);
454 }
455
456 // read face color
457 if (token != tokens.end()) { // there are colors to read
458 if constexpr (HasPerFaceColor<MeshType>) {
459 if (isPerFaceColorAvailable(mesh) ||
460 (settings.enableOptionalComponents &&
462 loadedInfo.setFaceColors();
463 f.color() = readOffColor(
464 token, tokens.size() - (token - tokens.begin()));
465 // in case the loaded polygon has been triangulated in
466 // the last n triangles
467 for (uint ff = mesh.index(f); ff < mesh.faceNumber();
468 ++ff) {
469 mesh.face(ff).color() = f.color();
470 }
471 }
472 }
473 }
474 log.progress(fid);
475 }
476 log.endProgress();
477 }
478 else { // mesh does not have face, read nf lines and throw them away
479 for (uint i = 0; i < nf; ++i)
480 readAndTokenizeNextNonEmptyLine(file);
481 }
482}
483
484} // namespace detail
485
510template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
512 MeshType& m,
513 std::istream& inputOffStream,
515 LogType& log = nullLogger,
516 const LoadSettings& settings = LoadSettings())
517{
518 uint nVertices, nFaces, nEdges;
519
520 MeshInfo fileInfo; // data that needs to be read from the file
521
522 detail::readOffHeader(inputOffStream, fileInfo, nVertices, nFaces, nEdges);
523 loadedInfo = fileInfo; // data that will be stored in the mesh!
524 if (settings.enableOptionalComponents)
525 enableOptionalComponentsFromInfo(loadedInfo, m);
526
527 if (nVertices == 0) {
528 log.log("The file has no vertices", LogType::WARNING_LOG);
529 return;
530 }
531
532 int percVertices = nVertices / (nVertices + nFaces) * 100;
533 int percFaces = 100 - percVertices;
534
535 log.startNewTask(0, percVertices, "Reading vertices");
536 detail::readOffVertices(m, inputOffStream, fileInfo, nVertices, log);
537 log.endTask("Reading vertices");
538 if constexpr (HasFaces<MeshType>) {
539 log.startNewTask(percVertices, 100, "Reading faces");
540 detail::readOffFaces(
541 m, inputOffStream, fileInfo, nFaces, settings, log);
542 log.endTask("Reading faces");
543 }
544 else {
545 log.log(100, "Ignored faces reading");
546 }
547 if (settings.enableOptionalComponents)
549}
550
570template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
572 MeshType& m,
573 std::istream& inputOffStream,
574 LogType& log = nullLogger,
575 const LoadSettings& settings = LoadSettings())
576{
578 loadOff(m, inputOffStream, loadedInfo, log, settings);
579}
580
605template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
606MeshType loadOff(
607 std::istream& inputOffStream,
609 LogType& log = nullLogger,
610 const LoadSettings& settings = LoadSettings())
611{
612 MeshType m;
613 loadOff(m, inputOffStream, loadedInfo, log, settings);
614 return m;
615}
616
636template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
637MeshType loadOff(
638 std::istream& inputOffStream,
639 LogType& log = nullLogger,
640 const LoadSettings& settings = LoadSettings())
641{
643 return loadOff<MeshType>(inputOffStream, loadedInfo, log, settings);
644}
645
670template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
672 MeshType& m,
673 const std::string& filename,
675 LogType& log = nullLogger,
676 const LoadSettings& settings = LoadSettings())
677{
678 std::ifstream file = openInputFileStream(filename);
679
680 if constexpr (HasName<MeshType>) {
682 }
683
684 loadOff(m, file, loadedInfo, log, settings);
685}
686
706template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
708 MeshType& m,
709 const std::string& filename,
710 LogType& log = nullLogger,
711 const LoadSettings& settings = LoadSettings())
712{
714 loadOff(m, filename, loadedInfo, log, settings);
715}
716
741template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
742MeshType loadOff(
743 const std::string& filename,
745 LogType& log = nullLogger,
746 const LoadSettings& settings = LoadSettings())
747{
748 MeshType m;
749 loadOff(m, filename, loadedInfo, log, settings);
750 return m;
751}
752
772template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
773MeshType loadOff(
774 const std::string& filename,
775 LogType& log = nullLogger,
776 const LoadSettings& settings = LoadSettings())
777{
779 return loadOff<MeshType>(filename, loadedInfo, log, settings);
780}
781
782} // namespace vcl
783
784#endif // VCL_LOAD_SAVE_OFF_LOAD_H
static std::string fileNameWithoutExtension(const std::string &fullpath)
Get the file name without extension of a file.
Definition file_info.h:217
A simple class that allows to store which elements and their components have been imported/loaded or ...
Definition mesh_info.h:76
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:43
HasFaces concepts is satisfied when at least one of its template types is (or inherits from) a vcl::m...
Definition face_container.h:133
Concept that checks if a Mesh has the Name component.
Definition per_mesh.h:95
bool isPerFaceColorAvailable(const MeshType &m)
Returns true if the Color component is available (enabled) in the Face element of the input mesh m.
Definition face_requirements.h:214
bool enableIfPerFaceColorOptional(MeshType &m)
If the input mesh has a FaceContainer, and the Face Element has a Color Component,...
Definition face_requirements.h:238
void loadOff(MeshType &m, std::istream &inputOffStream, MeshInfo &loadedInfo, LogType &log=nullLogger, const LoadSettings &settings=LoadSettings())
Loads from the given input off stream and puts the content into the mesh m.
Definition load.h:511
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:125
The LoadSettings structure contains the settings that can be used to load a mesh from a stream/file.
Definition settings.h:35