fix: add modeling.h include to test_io_gltf
This commit is contained in:
+27
-21
@@ -63,11 +63,10 @@ static void write_glb_header(std::ostream& out, uint32_t total_length) {
|
||||
}
|
||||
|
||||
static void write_glb_chunk(std::ostream& out, uint32_t chunk_type,
|
||||
const std::string& data) {
|
||||
uint32_t len = static_cast<uint32_t>(data.size());
|
||||
out.write(reinterpret_cast<const char*>(&len), 4);
|
||||
const std::string& data, uint32_t unpadded_len) {
|
||||
out.write(reinterpret_cast<const char*>(&unpadded_len), 4);
|
||||
out.write(reinterpret_cast<const char*>(&chunk_type), 4);
|
||||
out.write(data.data(), data.size());
|
||||
out.write(data.data(), static_cast<std::streamsize>(data.size()));
|
||||
}
|
||||
|
||||
// ── GLB binary buffer layout ─────────────────────────────────────────
|
||||
@@ -104,7 +103,8 @@ static GlbBufferLayout compute_layout(const mesh::HalfedgeMesh& mesh,
|
||||
|
||||
static std::string generate_json(const mesh::HalfedgeMesh& mesh,
|
||||
const GltfOptions& options,
|
||||
const GlbBufferLayout& layout) {
|
||||
const GlbBufferLayout& layout,
|
||||
const std::string& bin_uri = "") {
|
||||
size_t nv = mesh.num_vertices();
|
||||
size_t nf = mesh.num_faces();
|
||||
size_t index_count = nf * 3;
|
||||
@@ -125,7 +125,9 @@ static std::string generate_json(const mesh::HalfedgeMesh& mesh,
|
||||
ss << "},\"indices\":" << (options.include_normals ? 2 : 1) << "}]}],\n";
|
||||
|
||||
// Buffer
|
||||
ss << " \"buffers\":[{\"byteLength\":" << layout.total_bin_len << "}],\n";
|
||||
ss << " \"buffers\":[{";
|
||||
if (!bin_uri.empty()) ss << "\"uri\":\"" << bin_uri << "\",";
|
||||
ss << "\"byteLength\":" << layout.total_bin_len << "}],\n";
|
||||
|
||||
// Buffer views
|
||||
ss << " \"bufferViews\":[\n";
|
||||
@@ -210,34 +212,38 @@ bool write_gltf(const std::string& filepath, const mesh::HalfedgeMesh& mesh,
|
||||
if (mesh.num_vertices() == 0 || mesh.num_faces() == 0) return false;
|
||||
|
||||
auto layout = compute_layout(mesh, options);
|
||||
std::string json = generate_json(mesh, options, layout);
|
||||
|
||||
if (options.binary) {
|
||||
std::string json = generate_json(mesh, options, layout);
|
||||
// ── GLB format ──
|
||||
uint32_t json_unpadded_len = static_cast<uint32_t>(json.size());
|
||||
|
||||
// Pad JSON chunk to 4-byte alignment with spaces
|
||||
std::string json_padded = json;
|
||||
while (json_padded.size() % 4 != 0) json_padded += ' ';
|
||||
uint32_t json_padded_len = static_cast<uint32_t>(json_padded.size());
|
||||
|
||||
uint32_t json_chunk_len = static_cast<uint32_t>(json_padded.size());
|
||||
uint32_t bin_chunk_len = static_cast<uint32_t>(layout.total_bin_len);
|
||||
// Serialize binary data
|
||||
std::string bin_data;
|
||||
uint32_t bin_unpadded_len = static_cast<uint32_t>(layout.total_bin_len);
|
||||
if (layout.total_bin_len > 0) {
|
||||
std::ostringstream bin_stream(std::ios::binary);
|
||||
write_binary_data(bin_stream, mesh, options, layout);
|
||||
bin_data = bin_stream.str();
|
||||
while (bin_data.size() % 4 != 0) bin_data.push_back('\0');
|
||||
}
|
||||
|
||||
// Total = header(12) + json_header(8) + json_data + bin_header(8) + bin_data
|
||||
uint32_t total = 12 + 8 + json_chunk_len;
|
||||
if (layout.total_bin_len > 0) total += 8 + bin_chunk_len;
|
||||
// Total = header(12) + json_chunk_header(8) + json_padded + [bin_chunk_header(8) + bin_padded]
|
||||
uint32_t total = 12 + 8 + json_padded_len;
|
||||
if (!bin_data.empty()) total += 8 + static_cast<uint32_t>(bin_data.size());
|
||||
|
||||
std::ofstream file(filepath, std::ios::binary);
|
||||
if (!file) return false;
|
||||
|
||||
write_glb_header(file, total);
|
||||
write_glb_chunk(file, 0x4E4F534A, json_padded); // "JSON"
|
||||
if (layout.total_bin_len > 0) {
|
||||
// Serialize binary data into a string buffer
|
||||
std::ostringstream bin_stream(std::ios::binary);
|
||||
write_binary_data(bin_stream, mesh, options, layout);
|
||||
std::string bin_data = bin_stream.str();
|
||||
// Pad bin data to 4-byte alignment
|
||||
while (bin_data.size() % 4 != 0) bin_data.push_back('\0');
|
||||
write_glb_chunk(file, 0x004E4942, bin_data); // "BIN\0"
|
||||
write_glb_chunk(file, 0x4E4F534A, json_padded, json_unpadded_len); // "JSON"
|
||||
if (!bin_data.empty()) {
|
||||
write_glb_chunk(file, 0x004E4942, bin_data, bin_unpadded_len); // "BIN\0"
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include "vde/foundation/io_gltf.h"
|
||||
#include "vde/brep/modeling.h"
|
||||
|
||||
using namespace vde::foundation;
|
||||
using namespace vde::mesh;
|
||||
@@ -88,15 +89,24 @@ TEST(IoGltfTest, ExportWithNormals) {
|
||||
std::ifstream f(path, std::ios::binary);
|
||||
ASSERT_TRUE(f.good());
|
||||
|
||||
// Skip header (12 bytes)
|
||||
f.seekg(12);
|
||||
// Read header
|
||||
uint32_t magic = 0, version = 0, total_len = 0;
|
||||
f.read(reinterpret_cast<char*>(&magic), 4);
|
||||
f.read(reinterpret_cast<char*>(&version), 4);
|
||||
f.read(reinterpret_cast<char*>(&total_len), 4);
|
||||
EXPECT_EQ(magic, 0x46546C67u);
|
||||
|
||||
// Read JSON chunk
|
||||
// Read JSON chunk header
|
||||
uint32_t chunk_len = 0, chunk_type = 0;
|
||||
f.read(reinterpret_cast<char*>(&chunk_len), 4);
|
||||
f.read(reinterpret_cast<char*>(&chunk_type), 4);
|
||||
EXPECT_EQ(chunk_type, 0x4E4F534Au);
|
||||
|
||||
// Read unpadded JSON data + skip padding
|
||||
std::string json(chunk_len, '\0');
|
||||
f.read(&json[0], chunk_len);
|
||||
size_t padding = (4 - (chunk_len % 4)) % 4;
|
||||
f.seekg(static_cast<std::streamoff>(padding), std::ios::cur);
|
||||
|
||||
EXPECT_NE(json.find("\"NORMAL\""), std::string::npos)
|
||||
<< "JSON should include NORMAL attribute when normals enabled";
|
||||
|
||||
Reference in New Issue
Block a user