23#ifndef VCL_IO_MESH_PLY_DETAIL_MATERIAL_H
24#define VCL_IO_MESH_PLY_DETAIL_MATERIAL_H
28#include <vclib/io/read.h>
29#include <vclib/io/write.h>
31#include <vclib/mesh.h>
33namespace vcl::detail {
35template<
typename Stream>
36void readPlyMaterialProperty(
40 std::endian end = std::endian::little)
42 bool hasBeenRead =
false;
47 uint size = io::readPrimitiveType<uint>(file, p.listSizeType, end);
50 for (uint i = 0; i < size; ++i) {
51 path[i] = io::readPrimitiveType<char>(file, p.type, end);
53 mat.textureDescriptor(textureType) = TextureDescriptor(path);
57 if (p.name == ply::name) {
58 uint size = io::readPrimitiveType<uint>(file, p.listSizeType, end);
61 for (uint i = 0; i < size; ++i) {
62 name[i] = io::readPrimitiveType<char>(file, p.type, end);
67 else if (p.name >= ply::red && p.name <= ply::alpha) {
68 uint idx = p.name - ply::red;
69 mat.baseColor()[idx] =
70 io::readPrimitiveType<unsigned char>(file, p.type, end);
73 else if (p.name == ply::metallic) {
74 mat.metallic() = io::readPrimitiveType<float>(file, p.type, end);
77 else if (p.name == ply::roughness) {
78 mat.roughness() = io::readPrimitiveType<float>(file, p.type, end);
81 else if (p.name >= ply::emissive_red && p.name <= ply::emissive_blue) {
82 uint idx = p.name - ply::emissive_red;
83 mat.emissiveColor()[idx] =
84 io::readPrimitiveType<unsigned char>(file, p.type, end);
87 else if (p.name == ply::alpha_mode) {
89 io::readPrimitiveType<uint>(file, p.type, end));
92 else if (p.name == ply::alpha_cutoff) {
93 mat.alphaCutoff() = io::readPrimitiveType<float>(file, p.type, end);
96 else if (p.name == ply::normal_scale) {
97 mat.normalScale() = io::readPrimitiveType<float>(file, p.type, end);
100 else if (p.name == ply::occlusion_strength) {
101 mat.occlusionStrength() =
102 io::readPrimitiveType<float>(file, p.type, end);
105 else if (p.name == ply::double_sided) {
107 static_cast<bool>(io::readPrimitiveType<uint>(file, p.type, end));
110 else if (p.name == ply::base_color_texture) {
111 readTexturePath(BASE_COLOR);
113 else if (p.name == ply::metallic_roughness_texture) {
114 readTexturePath(METALLIC_ROUGHNESS);
116 else if (p.name == ply::normal_texture) {
117 readTexturePath(NORMAL);
119 else if (p.name == ply::occlusion_texture) {
120 readTexturePath(OCCLUSION);
122 else if (p.name == ply::emissive_texture) {
123 readTexturePath(EMISSIVE);
130 uint s = io::readPrimitiveType<uint>(file, p.listSizeType, end);
131 for (uint i = 0; i < s; ++i)
132 io::readPrimitiveType<int>(file, p.type, end);
135 io::readPrimitiveType<int>(file, p.type, end);
140inline void readPlyMaterialTxt(
143 const std::list<PlyProperty>& matProperties)
145 Tokenizer spaceTokenizer = readAndTokenizeNextNonEmptyLine(file);
146 Tokenizer::iterator token = spaceTokenizer.begin();
147 for (
const PlyProperty& p : matProperties) {
148 if (token == spaceTokenizer.end()) {
149 throw MalformedFileException(
"Unexpected end of line.");
151 readPlyMaterialProperty(token, mat, p);
155inline void readPlyMaterialBin(
158 const std::list<PlyProperty>& matProperties,
161 for (
const PlyProperty& p : matProperties) {
162 readPlyMaterialProperty(file, mat, p, end);
166template<MeshConcept MeshType>
167void writePlyMaterials(
169 const PlyHeader& header,
170 const MeshType& mesh)
173 if (header.format() == ply::ASCII) {
174 format.isBinary =
false;
176 else if (header.format() == ply::BINARY_BIG_ENDIAN) {
177 format.endian = std::endian::big;
180 for (
const Material& mat : mesh.materials()) {
182 for (
const PlyProperty& p : header.materialProperties()) {
183 bool hasBeenWritten =
false;
187 const std::string& path =
188 mat.textureDescriptor(textureType).path();
189 io::writeProperty(file, path.size(), p.listSizeType, format);
190 for (
const char& c : path) {
191 io::writeProperty(file, c, p.type, format);
193 hasBeenWritten =
true;
196 if (p.name == ply::name) {
197 const std::string& name = mat.name();
198 io::writeProperty(file, name.size(), p.listSizeType, format);
199 for (
const char& c : name) {
200 io::writeProperty(file, c, p.type, format);
202 hasBeenWritten =
true;
204 else if (p.name >= ply::red && p.name <= ply::alpha) {
206 file, mat.baseColor()[p.name - ply::red], p.type, format);
207 hasBeenWritten =
true;
209 else if (p.name == ply::metallic) {
210 io::writeProperty(file, mat.metallic(), p.type, format);
211 hasBeenWritten =
true;
213 else if (p.name == ply::roughness) {
214 io::writeProperty(file, mat.roughness(), p.type, format);
215 hasBeenWritten =
true;
218 p.name >= ply::emissive_red && p.name <= ply::emissive_blue) {
221 mat.emissiveColor()[p.name - ply::emissive_red],
224 hasBeenWritten =
true;
226 else if (p.name == ply::alpha_mode) {
228 file, toUnderlying(mat.alphaMode()), p.type, format);
229 hasBeenWritten =
true;
231 else if (p.name == ply::alpha_cutoff) {
232 io::writeProperty(file, mat.alphaCutoff(), p.type, format);
233 hasBeenWritten =
true;
235 else if (p.name == ply::normal_scale) {
236 io::writeProperty(file, mat.normalScale(), p.type, format);
237 hasBeenWritten =
true;
239 else if (p.name == ply::occlusion_strength) {
241 file, mat.occlusionStrength(), p.type, format);
242 hasBeenWritten =
true;
244 else if (p.name == ply::double_sided) {
246 file,
static_cast<uint
>(mat.doubleSided()), p.type, format);
247 hasBeenWritten =
true;
249 else if (p.name == ply::base_color_texture) {
250 writeTexturePath(BASE_COLOR);
252 else if (p.name == ply::metallic_roughness_texture) {
253 writeTexturePath(METALLIC_ROUGHNESS);
255 else if (p.name == ply::normal_texture) {
256 writeTexturePath(NORMAL);
258 else if (p.name == ply::occlusion_texture) {
259 writeTexturePath(OCCLUSION);
261 else if (p.name == ply::emissive_texture) {
262 writeTexturePath(EMISSIVE);
265 if (!hasBeenWritten) {
268 io::writeProperty(file, 0, p.type, format);
271 if (!format.isBinary)
276template<MeshConcept MeshType, LoggerConcept LogType>
277void readPlyMaterials(
279 const PlyHeader& header,
283 log.startProgress(
"Reading materials", header.materialCount());
285 for (uint mid = 0; mid < header.materialCount(); ++mid) {
287 if (header.format() == ply::ASCII) {
288 detail::readPlyMaterialTxt(file, mat, header.materialProperties());
291 std::endian end = header.format() == ply::BINARY_BIG_ENDIAN ?
294 detail::readPlyMaterialBin(
295 file, mat, header.materialProperties(), end);
297 mesh.pushMaterial(mat);
TextureType
Defines the types of textures used in the PBR material model.
Definition material.h:62
AlphaMode
Defines the alpha rendering mode of the material.
Definition material.h:50