Skip to content

Commit

Permalink
Add pretty print option, and fix imageFolder
Browse files Browse the repository at this point in the history
  • Loading branch information
spnda committed Jan 2, 2024
1 parent b80b6bd commit b5f43e2
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 8 deletions.
14 changes: 14 additions & 0 deletions include/fastgltf/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,11 @@ namespace fastgltf {
* Calls fastgltf::validate for the passed asset before writing.
*/
ValidateAsset = 1 << 1,

/**
* Pretty-prints the outputted JSON. This option is ignored for binary glTFs.
*/
PrettyPrintJson = 1 << 2,
};
// clang-format on

Expand Down Expand Up @@ -776,6 +781,11 @@ namespace fastgltf {
void setUserPointer(void* pointer) noexcept;
};

/**
* This converts a compacted JSON string into a more readable pretty format.
*/
void prettyPrintJson(std::string& json);

template <typename T>
struct ExportResult {
T output;
Expand All @@ -786,6 +796,10 @@ namespace fastgltf {

/**
* A exporter for serializing one or more glTF files into JSON and GLB forms.
*
* @note This does not write anything to any files. This class only serializes data
* into memory structures, which can then be used to manually write them to disk.
* If you want to let fastgltf handle the file writing, too, use fastgltf::FileExporter.
*/
class Exporter {
protected:
Expand Down
1 change: 1 addition & 0 deletions include/fastgltf/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <cstdint>
#include <filesystem>
#include <optional>
#include <string>
#include <utility>
#include <variant>
#include <vector>
Expand Down
42 changes: 40 additions & 2 deletions src/fastgltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3526,6 +3526,40 @@ void fg::Parser::setUserPointer(void* pointer) noexcept {
#pragma endregion

#pragma region Exporter
void fg::prettyPrintJson(std::string& json) {
std::size_t i = 0;
std::size_t depth = 0;
auto insertNewline = [&i, &depth, &json]() {
json.insert(i, 1, '\n');
json.insert(i + 1, depth, '\t');
i += 1 + depth;
};

while (i < json.size()) {
if (json[i] == '"') {
// Skip to the end of the string
do {
++i;
} while (json[i] != '"' && json[i - 1] != '\\');
}

if (json[i] == '{' || json[i] == '[') {
++depth;
++i; // Insert \n after the character
insertNewline();
} else if (json[i] == '}' || json[i] == ']') {
--depth;
insertNewline();
++i; // Insert \n before the character
} else if (json[i] == ',') {
++i; // Insert \n after the character
insertNewline();
} else {
++i;
}
}
}

void fg::Exporter::setBufferPath(std::filesystem::path folder) {
if (!folder.is_relative()) {
return;
Expand All @@ -3537,7 +3571,7 @@ void fg::Exporter::setImagePath(std::filesystem::path folder) {
if (!folder.is_relative()) {
return;
}
bufferFolder = std::move(folder);
imageFolder = std::move(folder);
}

void fg::Exporter::writeAccessors(const Asset& asset, std::string& json) {
Expand Down Expand Up @@ -3895,7 +3929,7 @@ void fg::Exporter::writeMaterials(const Asset& asset, std::string& json) {
}
}

if (it->alphaCutoff != 0.5f) {
if (it->alphaMode == AlphaMode::Mask && it->alphaCutoff != 0.5f) {
if (json.back() != ',') json += ',';
json += R"("alphaCutoff":)" + std::to_string(it->alphaCutoff);
}
Expand Down Expand Up @@ -4313,6 +4347,10 @@ fg::Expected<fg::ExportResult<std::string>> fg::Exporter::writeGLTF(const Asset&

outputString += "}";

if (hasBit(options, ExportOptions::PrettyPrintJson)) {
prettyPrintJson(outputString);
}

if (errorCode != Error::None) {
return Expected<ExportResult<std::string>> { errorCode };
}
Expand Down
14 changes: 8 additions & 6 deletions tests/write_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <cstdint>

#include <catch2/catch_test_macros.hpp>

#include <fastgltf/core.hpp>
Expand All @@ -13,7 +15,7 @@ TEST_CASE("Test simple glTF composition", "[write-tests]") {
asset.bufferViews.emplace_back(std::move(bufferView));

fastgltf::Exporter exporter;
auto result = exporter.writeGLTF(&asset);
auto result = exporter.writeGLTF(asset);
REQUIRE(result.error() == fastgltf::Error::None);
REQUIRE(!result.get().output.empty());
}
Expand All @@ -24,18 +26,18 @@ TEST_CASE("Read glTF, write it, and then read it again and validate", "[write-te
REQUIRE(cubeJsonData->loadFromFile(cubePath / "Cube.gltf"));

fastgltf::Parser parser;
auto cube = parser.loadGLTF(cubeJsonData.get(), cubePath);
auto cube = parser.loadGltfJson(cubeJsonData.get(), cubePath);
REQUIRE(cube.error() == fastgltf::Error::None);
REQUIRE(fastgltf::validate(cube.get()) == fastgltf::Error::None);

fastgltf::Exporter exporter;
auto expected = exporter.writeGLTF(&(cube.get()));
auto expected = exporter.writeGLTF(cube.get());
REQUIRE(expected.error() == fastgltf::Error::None);

fastgltf::GltfDataBuffer cube2JsonData;
cube2JsonData.copyBytes(reinterpret_cast<const uint8_t*>(expected.get().output.data()),
expected.get().output.size());
auto cube2 = parser.loadGLTF(&cube2JsonData, cubePath);
auto cube2 = parser.loadGltfJson(&cube2JsonData, cubePath);
REQUIRE(cube2.error() == fastgltf::Error::None);
REQUIRE(fastgltf::validate(cube2.get()) == fastgltf::Error::None);
}
Expand All @@ -48,10 +50,10 @@ TEST_CASE("Try writing a glTF with all buffers and images", "[write-tests]") {

fastgltf::Parser parser;
auto options = fastgltf::Options::LoadExternalBuffers | fastgltf::Options::LoadExternalImages;
auto cube = parser.loadGLTF(&gltfDataBuffer, cubePath, options);
auto cube = parser.loadGltfJson(&gltfDataBuffer, cubePath, options);
REQUIRE(cube.error() == fastgltf::Error::None);

fastgltf::FileExporter exporter;
auto error = exporter.writeGLTF(&cube.get(), path / "export" / "cube.gltf");
auto error = exporter.writeGLTF(cube.get(), path / "export" / "cube.gltf", fastgltf::ExportOptions::PrettyPrintJson);
REQUIRE(error == fastgltf::Error::None);
}

0 comments on commit b5f43e2

Please sign in to comment.