2026-07-23 07:33:15 +00:00
|
|
|
#include "vde/foundation/io_gltf.h"
|
2026-07-23 08:19:24 +00:00
|
|
|
#include "vde/core/aabb.h"
|
2026-07-23 07:33:15 +00:00
|
|
|
#include <fstream>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cmath>
|
2026-07-23 08:19:24 +00:00
|
|
|
#include <string>
|
2026-07-23 07:33:15 +00:00
|
|
|
|
|
|
|
|
namespace vde::foundation {
|
|
|
|
|
|
2026-07-23 08:19:24 +00:00
|
|
|
static std::string vec3_json(double x, double y, double z) {
|
2026-07-23 07:33:15 +00:00
|
|
|
return "[" + std::to_string(x) + "," + std::to_string(y) + "," + std::to_string(z) + "]";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool write_gltf(const std::string& filepath, const mesh::HalfedgeMesh& mesh) {
|
|
|
|
|
std::ofstream file(filepath);
|
|
|
|
|
if (!file) return false;
|
|
|
|
|
|
|
|
|
|
size_t nv = mesh.num_vertices();
|
|
|
|
|
size_t nf = mesh.num_faces();
|
|
|
|
|
size_t index_count = nf * 3;
|
|
|
|
|
core::AABB3D bounds = mesh.bounds();
|
|
|
|
|
|
|
|
|
|
file << "{\n";
|
|
|
|
|
file << " \"asset\": {\"version\": \"2.0\", \"generator\": \"ViewDesignEngine\"},\n";
|
|
|
|
|
file << " \"scene\": 0,\n";
|
|
|
|
|
file << " \"scenes\": [{\"nodes\": [0]}],\n";
|
|
|
|
|
file << " \"nodes\": [{\"mesh\": 0}],\n";
|
2026-07-23 08:19:24 +00:00
|
|
|
file << " \"meshes\": [{\"primitives\": [{\"attributes\": {\"POSITION\": 0},\"indices\": 1}]}],\n";
|
|
|
|
|
file << " \"buffers\": [{\"uri\": \"mesh.bin\",\"byteLength\": " << (nv*12+index_count*4) << "}],\n";
|
2026-07-23 07:33:15 +00:00
|
|
|
file << " \"bufferViews\": [\n";
|
|
|
|
|
file << " {\"buffer\": 0, \"byteOffset\": 0, \"byteLength\": " << (nv*12) << "},\n";
|
|
|
|
|
file << " {\"buffer\": 0, \"byteOffset\": " << (nv*12) << ", \"byteLength\": " << (index_count*4) << "}\n";
|
|
|
|
|
file << " ],\n";
|
|
|
|
|
file << " \"accessors\": [\n";
|
|
|
|
|
file << " {\"bufferView\": 0, \"componentType\": 5126, \"count\": " << nv
|
2026-07-23 08:19:24 +00:00
|
|
|
<< ", \"type\": \"VEC3\", \"max\": " << vec3_json(bounds.max().x(),bounds.max().y(),bounds.max().z())
|
|
|
|
|
<< ", \"min\": " << vec3_json(bounds.min().x(),bounds.min().y(),bounds.min().z()) << "},\n";
|
|
|
|
|
file << " {\"bufferView\": 1, \"componentType\": 5125, \"count\": " << index_count << ", \"type\": \"SCALAR\"}\n";
|
|
|
|
|
file << " ]\n}\n";
|
|
|
|
|
|
|
|
|
|
// Write binary data
|
|
|
|
|
std::string dot = ".";
|
|
|
|
|
std::string binpath = filepath.substr(0, filepath.rfind(dot)) + ".bin";
|
2026-07-23 07:33:15 +00:00
|
|
|
std::ofstream bin(binpath, std::ios::binary);
|
2026-07-23 08:19:24 +00:00
|
|
|
|
2026-07-23 07:33:15 +00:00
|
|
|
for (size_t i = 0; i < nv; ++i) {
|
|
|
|
|
const auto& v = mesh.vertex(i);
|
2026-07-23 08:19:24 +00:00
|
|
|
float fx = static_cast<float>(v.x());
|
|
|
|
|
float fy = static_cast<float>(v.y());
|
|
|
|
|
float fz = static_cast<float>(v.z());
|
|
|
|
|
bin.write(reinterpret_cast<const char*>(&fx), 4);
|
|
|
|
|
bin.write(reinterpret_cast<const char*>(&fy), 4);
|
|
|
|
|
bin.write(reinterpret_cast<const char*>(&fz), 4);
|
2026-07-23 07:33:15 +00:00
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < nf; ++i) {
|
|
|
|
|
auto vis = mesh.face_vertices(static_cast<int>(i));
|
|
|
|
|
for (size_t j = 0; j < std::min(vis.size(), size_t(3)); ++j) {
|
2026-07-23 08:19:24 +00:00
|
|
|
uint32_t idx = static_cast<uint32_t>(vis[j]);
|
|
|
|
|
bin.write(reinterpret_cast<const char*>(&idx), 4);
|
2026-07-23 07:33:15 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace vde::foundation
|