20 "SCALAR",
"VEC2",
"VEC3",
"VEC4",
"MAT2",
"MAT3",
"MAT4"
26 buffers.resize(buffers.size() + 1);
27 auto &buf = buffers.back();
28 buf.uri.value = file_prefix +
"." + bufferName +
".bin";
30 buf.byteLength.value = 0;
31 buf.byteLength.valid =
true;
32 buf.file.reset(
new ofstream(buf.uri.value, ios::out | ios::binary));
34 return {(unsigned)buffers.size() - 1};
45 if (buffer.
id >= buffers.size()) {
return {INVALID_ID}; }
47 buffer_views.resize(buffer_views.size() + 1);
48 auto &buf_view = buffer_views.back();
49 auto &buf = buffers[buffer.
id];
51 buf_view.buffer.value = buffer.
id;
52 buf_view.buffer.valid =
true;
54 const unsigned buf_offset = buf.byteLength.value;
55 const unsigned new_offset = byteAlign*((buf_offset+byteAlign-1)/byteAlign);
56 buf_view.byteOffset.value = new_offset;
57 buf_view.byteOffset.valid =
true;
59 buf_view.byteLength.value = byteLength;
60 buf_view.byteLength.valid =
true;
62 if (target == target_type::ARRAY_BUFFER)
64 buf_view.byteStride.value = byteStride;
65 buf_view.byteStride.valid =
true;
68 buf_view.target.value = (unsigned)target;
69 buf_view.target.valid =
true;
72 for (
unsigned i = buf_offset; i != new_offset; ++i) { buf.file->put(
'\0'); }
74 buf.file->write(reinterpret_cast<const char *>(data), byteLength);
76 buf.byteLength.value = new_offset + byteLength;
78 return {(unsigned)buffer_views.size() - 1};
85 if (bufferView.
id >= buffer_views.size()) {
return; }
87 auto &buf_view = buffer_views[bufferView.
id];
88 auto &buf = buffers[buf_view.buffer.value];
90 buf_view.byteLength.value += byteLength;
92 buf.file->write(reinterpret_cast<const char *>(data), byteLength);
93 buf.byteLength.value += byteLength;
103 if (bufferView.
id >= buffer_views.size() || count == 0)
108 accessors.resize(accessors.size() + 1);
109 auto &acc = accessors.back();
111 acc.bufferView.value = bufferView.
id;
112 acc.bufferView.valid =
true;
114 acc.byteOffset.value = byteOffset;
115 acc.byteOffset.valid =
true;
117 acc.componentType.value = (unsigned)componentType;
118 acc.componentType.valid =
true;
120 acc.count.value = count;
121 acc.count.valid =
true;
123 acc.type.value = tensorTypes[(unsigned)tensorType];
124 acc.type.valid =
true;
128 if (componentType != component_type::FLOAT &&
129 buffer_views[bufferView.
id].target.value !=
130 (
unsigned)target_type::ELEMENT_ARRAY_BUFFER)
132 acc.normalized.value =
true;
133 acc.normalized.valid =
true;
136 return {(unsigned)accessors.size() - 1};
146 auto id = addAccessor(bufferView,
148 component_type::FLOAT,
152 if (
id.
id != INVALID_ID)
154 auto &acc = accessors[
id.id];
155 acc.min.value.assign(min.begin(), min.end());
156 acc.min.valid =
true;
157 acc.max.value.assign(max.begin(), max.end());
158 acc.max.valid =
true;
171 auto id = addAccessor(bufferView,
173 component_type::FLOAT,
177 if (
id.
id != INVALID_ID)
179 auto &acc = accessors[
id.id];
180 acc.min.value.assign(min.begin(), min.end());
181 acc.min.valid =
true;
182 acc.max.value.assign(max.begin(), max.end());
183 acc.max.valid =
true;
195 #ifndef GLVIS_USE_LIBPNG
201 images.resize(images.size() + 1);
202 auto &img = images.back();
204 img.uri.value = file_prefix +
"." + imageName +
".png";
205 img.uri.valid =
true;
207 img.name.value = imageName;
208 img.name.valid =
true;
211 auto get_row = [&](
int row,
void *pxls)
213 auto pxls_out =
reinterpret_cast<array<uint8_t,4>*
>(pxls);
214 auto pxls_in = pixels + row*width;
215 for (
int i = 0; i < width; ++i)
217 for (
int j = 0; j < 4; ++j)
219 pxls_out[i][j] = std::min(
int(pxls_in[i][j]*256), 255);
223 SaveAsPNG(img.uri.value.c_str(), width, height,
224 false,
true, get_row);
226 return {(unsigned)images.size() - 1};
228 #endif // GLVIS_USE_LIBPNG
237 samplers.resize(samplers.size() + 1);
238 auto &sampler = samplers.back();
240 sampler.magFilter.value = (unsigned)magFilter;
241 sampler.magFilter.valid =
true;
243 sampler.minFilter.value = (unsigned)minFilter;
244 sampler.minFilter.valid=
true;
246 sampler.wrapS.value = (unsigned)wrapS;
247 sampler.wrapS.valid =
true;
249 sampler.wrapT.value = (unsigned)wrapT;
250 sampler.wrapT.valid =
true;
252 return {(unsigned)samplers.size() - 1};
258 if (sampler.
id >= samplers.size() || source.
id >= images.size())
263 textures.resize(textures.size() + 1);
264 auto &tex = textures.back();
266 tex.sampler.value = sampler.
id;
267 tex.sampler.valid =
true;
269 tex.source.value = source.
id;
270 tex.source.valid =
true;
272 return {(unsigned)textures.size() - 1};
289 mat.name.value = materialName;
290 mat.name.valid =
true;
292 auto &pbr = mat.pbrMetallicRoughness.value;
295 pbr.baseColorFactor.valid =
true;
297 auto &tex_info = pbr.baseColorTexture.value;
300 tex_info.index.valid =
true;
302 tex_info.texCoord.value = 0;
303 tex_info.texCoord.valid =
true;
305 pbr.baseColorTexture.valid = pbrMetallicRoughness.
haveTexture;
308 pbr.metallicFactor.valid =
true;
311 pbr.roughnessFactor.valid =
true;
313 mat.pbrMetallicRoughness.valid =
true;
315 mat.doubleSided.value = doubleSided;
316 mat.doubleSided.valid =
true;
324 meshes.resize(meshes.size() + 1);
325 auto &mesh = meshes.back();
327 mesh.name.value = meshName;
328 mesh.name.valid =
true;
330 return {(unsigned)meshes.size() - 1};
340 if (mesh.
id >= meshes.size() || vertexPositions.
id >= accessors.size())
343 auto &primitives = meshes[mesh.
id].primitives;
344 primitives.resize(primitives.size() + 1);
345 auto &pri = primitives.back();
347 pri.attributes.value.POSITION.value = vertexPositions.
id;
348 pri.attributes.value.POSITION.valid =
true;
350 if (vertexNormals.
id < accessors.size())
352 pri.attributes.value.NORMAL.value = vertexNormals.
id;
353 pri.attributes.value.NORMAL.valid =
true;
356 if (vertexTexCoords0.
id < accessors.size())
358 pri.attributes.value.TEXCOORD_0.value = vertexTexCoords0.
id;
359 pri.attributes.value.TEXCOORD_0.valid =
true;
362 pri.attributes.valid =
true;
364 if (vertexIndices.
id < accessors.size())
366 pri.indices.value = vertexIndices.
id;
367 pri.indices.valid =
true;
372 pri.material.value = material.
id;
373 pri.material.valid =
true;
385 if (mesh.
id >= meshes.size()) {
return; }
387 auto &primitives = meshes[mesh.
id].primitives;
388 primitives.resize(primitives.size() + 1);
389 auto &pri = primitives.back();
391 pri.attributes.value.POSITION.value = vertexPositions.
id;
392 pri.attributes.value.POSITION.valid =
true;
394 if (vertexTexcoords0.
id < accessors.size())
396 pri.attributes.value.TEXCOORD_0.value = vertexTexcoords0.
id;
397 pri.attributes.value.TEXCOORD_0.valid =
true;
399 else if (vertexColors0.
id < accessors.size())
401 pri.attributes.value.COLOR_0.value = vertexColors0.
id;
402 pri.attributes.value.COLOR_0.valid =
true;
407 pri.attributes.valid =
true;
413 pri.material.value = material.
id;
414 pri.material.valid =
true;
418 pri.mode.valid =
true;
424 nodes.resize(nodes.size() + 1);
425 auto &node = nodes.back();
427 node.name.value = nodeName;
428 node.name.valid =
true;
430 return {(unsigned)nodes.size() - 1};
435 if (node.
id >= nodes.size()) {
return; }
437 nodes[node.
id].mesh.value = mesh.
id;
438 nodes[node.
id].mesh.valid =
true;
443 if (node.
id >= nodes.size()) {
return; }
445 nodes[node.
id].scale.value = scale;
446 nodes[node.
id].scale.valid =
true;
451 if (node.
id >= nodes.size()) {
return; }
453 nodes[node.
id].translation.value = translation;
454 nodes[node.
id].translation.valid =
true;
463 auto &pbr = mat.pbrMetallicRoughness.value;
465 pbr_mr_copy.
haveTexture = pbr.baseColorTexture.valid;
474 if (nodes.size() == 0)
479 ofstream gltf(file_prefix +
".gltf");
481 gltf.setf(ios::boolalpha);
490 " \"scenes\" : [ {\n"
492 for (
size_t i = 0; i != nodes.size(); ++i) { gltf << sep(i) <<
' ' << i; }
498 gltf <<
" \"nodes\" : [";
499 for (
size_t i = 0; i != nodes.size(); ++i)
501 gltf << sep(i) <<
" {";
503 print_node(gltf, pos,
"\n ", nodes[i].name);
504 print_node(gltf, pos,
"\n ", nodes[i].mesh);
505 print_node(gltf, pos,
"\n ", nodes[i].scale);
506 print_node(gltf, pos,
"\n ", nodes[i].translation);
512 gltf <<
" \"meshes\" : [";
513 for (
size_t i = 0; i != meshes.size(); ++i)
515 gltf << sep(i) <<
" {";
517 print_node(gltf, pos,
"\n ", meshes[i].name);
518 gltf << sep(pos++) <<
"\n \"primitives\" : [";
519 auto &primitives = meshes[i].primitives;
520 for (
size_t j = 0; j != primitives.size(); ++j)
522 gltf << sep(j) <<
" {";
524 print_node(gltf, pos2,
"\n ", primitives[j].attributes);
525 print_node(gltf, pos2,
"\n ", primitives[j].indices);
526 print_node(gltf, pos2,
"\n ", primitives[j].material);
527 print_node(gltf, pos2,
"\n ", primitives[j].mode);
535 gltf <<
" \"materials\" : [";
536 for (
size_t i = 0; i !=
materials.size(); ++i)
538 gltf << sep(i) <<
" {";
540 print_node(gltf, pos,
"\n ",
materials[i].name);
541 print_node(gltf, pos,
"\n ",
materials[i].pbrMetallicRoughness);
542 print_node(gltf, pos,
"\n ",
materials[i].doubleSided);
547 gltf <<
" \"textures\" : [";
548 for (
size_t i = 0; i != textures.size(); ++i)
550 gltf << sep(i) <<
" {";
552 print_node(gltf, pos,
"\n ", textures[i].sampler);
553 print_node(gltf, pos,
"\n ", textures[i].source);
558 gltf <<
" \"images\" : [";
559 for (
size_t i = 0; i != images.size(); ++i)
561 gltf << sep(i) <<
" {";
563 print_node(gltf, pos,
"\n ", images[i].name);
564 print_node(gltf, pos,
"\n ", images[i].uri);
571 gltf <<
" \"samplers\" : [";
572 for (
size_t i = 0; i != samplers.size(); ++i)
574 gltf << sep(i) <<
" {";
576 print_node(gltf, pos,
"\n ", samplers[i].magFilter);
577 print_node(gltf, pos,
"\n ", samplers[i].minFilter);
578 print_node(gltf, pos,
"\n ", samplers[i].wrapS);
579 print_node(gltf, pos,
"\n ", samplers[i].wrapT);
585 gltf <<
" \"buffers\" : [";
586 for (
size_t i = 0; i != buffers.size(); ++i)
588 gltf << sep(i) <<
" {";
590 print_node(gltf, pos,
"\n ", buffers[i].uri);
591 print_node(gltf, pos,
"\n ", buffers[i].byteLength);
597 gltf <<
" \"bufferViews\" : [";
598 for (
size_t i = 0; i != buffer_views.size(); ++i)
600 gltf << sep(i) <<
" {";
602 print_node(gltf, pos,
"\n ", buffer_views[i].buffer);
603 print_node(gltf, pos,
"\n ", buffer_views[i].byteOffset);
604 print_node(gltf, pos,
"\n ", buffer_views[i].byteLength);
605 print_node(gltf, pos,
"\n ", buffer_views[i].byteStride);
606 print_node(gltf, pos,
"\n ", buffer_views[i].target);
612 gltf <<
" \"accessors\" : [";
613 for (
size_t i = 0; i != accessors.size(); ++i)
615 gltf << sep(i) <<
" {";
617 print_node(gltf, pos,
"\n ", accessors[i].bufferView);
618 print_node(gltf, pos,
"\n ", accessors[i].byteOffset);
619 print_node(gltf, pos,
"\n ", accessors[i].componentType);
620 print_node(gltf, pos,
"\n ", accessors[i].count);
621 print_node(gltf, pos,
"\n ", accessors[i].type);
622 print_node(gltf, pos,
"\n ", accessors[i].min);
623 print_node(gltf, pos,
"\n ", accessors[i].max);
624 print_node(gltf, pos,
"\n ", accessors[i].normalized);
632 " \"version\" : \"2.0\",\n"
633 " \"generator\" : \"GLVis\"\n"
material_id addMaterial(const std::string &materialName, const pbr_matallic_roughness &pbrMetallicRoughness, bool doubleSided=false)
void addNodeScale(node_id node, vec3f scale)
accessor_id addAccessorVec3f(buffer_view_id bufferView, size_t byteOffset, size_t count, vec3f min, vec3f max)
buffer_view_id addBufferView(buffer_id buffer, const void *data, size_t byteLength, size_t byteStride, size_t byteAlign, target_type target)
sampler_id addSampler(mag_filter magFilter=mag_filter::NEAREST, min_filter minFilter=min_filter::NEAREST, wrap_type wrapS=wrap_type::CLAMP_TO_EDGE, wrap_type wrapT=wrap_type::CLAMP_TO_EDGE)
void appendToBufferView(buffer_view_id bufferView, const void *data, size_t byteLength)
void addMeshLines(mesh_id mesh, accessor_id vertexPositions, accessor_id vertexTexcoords0, accessor_id vertexColors0, material_id material)
void addNodeTranslation(node_id node, vec3f translation)
void addMeshTriangles(mesh_id mesh, accessor_id vertexPositions, accessor_id vertexNormals, accessor_id vertexTexCoords0, accessor_id vertexIndices, material_id material)
buffer_id addBuffer(const std::string &bufferName)
std::array< float, 3 > vec3f
texture_id addTexture(sampler_id sampler, image_id source)
mesh_id addMesh(const std::string &meshName)
texture_id baseColorTexture
int SaveAsPNG(const char *fname, int w, int h, bool is_hidpi, bool with_alpha, std::function< void(int, void *)> get_row)
node_id addNode(const std::string &nodeName)
image_id addImage(const std::string &imageName, int width, int height, const color4f *pixels)
accessor_id addAccessor(buffer_view_id bufferView, size_t byteOffset, component_type componentType, size_t count, tensor_type tensorType)
std::array< float, 4 > color4f
void getMaterialPBRMR(material_id material, pbr_matallic_roughness &pbr_mr_copy)
void addNodeMesh(node_id node, mesh_id mesh)
std::array< float, 2 > vec2f
static const char * tensorTypes[]
accessor_id addAccessorVec2f(buffer_view_id bufferView, size_t byteOffset, size_t count, vec2f min, vec2f max)