Skip to content

Commit

Permalink
Add: glTF Exporter (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
spnda authored Jan 28, 2024
1 parent 57b8a74 commit 0272e59
Show file tree
Hide file tree
Showing 23 changed files with 1,855 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ tests/gltf/good-froge/
tests/gltf/deccer-cubes/
tests/gltf/bistro/
tests/gltf_loaders/
tests/gltf/export/
tests/gltf/export_glb/

# gltf Rust wrapper
tests/gltf-rs/target
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/compiler_flags.cmake)
# Create the library target
add_library(fastgltf
"src/fastgltf.cpp" "src/base64.cpp"
"include/fastgltf/base64.hpp" "include/fastgltf/glm_element_traits.hpp" "include/fastgltf/parser.hpp" "include/fastgltf/tools.hpp" "include/fastgltf/types.hpp" "include/fastgltf/util.hpp")
"include/fastgltf/base64.hpp" "include/fastgltf/glm_element_traits.hpp" "include/fastgltf/core.hpp" "include/fastgltf/tools.hpp" "include/fastgltf/types.hpp" "include/fastgltf/util.hpp")
add_library(fastgltf::fastgltf ALIAS fastgltf)

fastgltf_compiler_flags(fastgltf)
Expand Down Expand Up @@ -100,7 +100,7 @@ if (ANDROID)
endif()

install(
FILES "include/fastgltf/base64.hpp" "include/fastgltf/glm_element_traits.hpp" "include/fastgltf/parser.hpp" "include/fastgltf/tools.hpp" "include/fastgltf/types.hpp" "include/fastgltf/util.hpp"
FILES "include/fastgltf/base64.hpp" "include/fastgltf/glm_element_traits.hpp" "include/fastgltf/core.hpp" "include/fastgltf/tools.hpp" "include/fastgltf/types.hpp" "include/fastgltf/util.hpp"
DESTINATION include/fastgltf
)

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
[![Documentation Status](https://readthedocs.org/projects/fastgltf/badge/?version=latest)](https://fastgltf.readthedocs.io/latest/?badge=latest)


**fastgltf** is a speed and usability focused glTF 2.0 parser written in modern C++17 with minimal dependencies.
**fastgltf** is a speed and usability focused glTF 2.0 library written in modern C++17 with minimal dependencies.
It uses SIMD in various areas to decrease the time the application spends parsing and loading glTF data.
By taking advantage of modern C++17 (and optionally C++20) it also provides easy and safe access to the properties and data.

The parser supports the entirety of glTF 2.0 specification, including many extensions.
The library supports the entirety of glTF 2.0 specification, including many extensions.
By default, fastgltf will only do the absolute minimum to work with a glTF model.
However, it brings many additional features to ease working with the data,
including accessor tools, the ability to directly write to mapped GPU buffers, and decomposing transform matrices.
Expand Down
8 changes: 8 additions & 0 deletions deps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ endif()
# glm
if(EXISTS "${FASTGLTF_DEPS_DIR}/glm")
message(STATUS "fastgltf: Found glm")

# glm breaks because it apparently can't properly detect constexpr/C++ version and
# sets -Weverything which enables C++98 compatibility on Clang??
option(GLM_ENABLE_CXX_17 "" ON)

add_subdirectory("${FASTGLTF_DEPS_DIR}/glm")
add_library(glm::glm ALIAS glm)

Expand Down Expand Up @@ -51,6 +56,9 @@ if (EXISTS "${FASTGLTF_DEPS_DIR}/catch2")
option(CATCH_CONFIG_CPP17_BYTE "" ON)
option(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS "" ON)

# Make sure that exceptions are never disabled, as some other library seems to disable them.
option(CATCH_CONFIG_NO_DISABLE_EXCEPTIONS "" ON)

if (MSVC)
option(CATCH_CONFIG_WINDOWS_CRTDBG "" ON)
endif()
Expand Down
29 changes: 25 additions & 4 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ Asset
:undoc-members:


Parser
======
Reading & Writing
=================

This section contains all types that one requires to load a glTF file using fastgltf.
This includes the Parser class, options, and data buffers.
This section contains all types that one requires to read or write a glTF file using fastgltf.
This includes the Parser class, Exporter class, options, and data buffers.


Error
Expand Down Expand Up @@ -177,6 +177,14 @@ Options
.. doxygenenum:: fastgltf::Options


.. _exportoptions:

ExportOptions
-------------

.. doxygenenum:: fastgltf::ExportOptions


Expected
--------

Expand Down Expand Up @@ -208,6 +216,19 @@ Parser
:members:


Exporter
--------

.. doxygenfunction:: fastgltf::stringifyExtensionBits

.. doxygenclass:: fastgltf::Exporter
:members:
:undoc-members:

.. doxygenclass:: fastgltf::FileExporter
:members:
:undoc-members:

Utility
=======

Expand Down
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
fastgltf
========

**fastgltf** is a speed and usability focused glTF 2.0 parser written in modern C++17 with minimal dependencies.
**fastgltf** is a speed and usability focused glTF 2.0 library written in modern C++17 with minimal dependencies.
It uses SIMD in various areas to decrease the time the application spends parsing and loading glTF data.
By taking advantage of modern C++17 (and optionally C++20) it also provides easy and safe access to the properties and data.

The parser supports the entirety of glTF 2.0 specification, including many extensions.
The library supports the entirety of glTF 2.0 specification, including many extensions.
By default, fastgltf will only do the absolute minimum to work with a glTF model.
However, it brings many additional features to ease working with the data,
including accessor tools, the ability to directly write to mapped GPU buffers, and decomposing transform matrices.
Expand Down
6 changes: 6 additions & 0 deletions docs/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,9 @@ Parsing options
===============

For more information about the options when parsing a file, see :ref:`the API reference<options>`.


Exporting options
=================

For more information about the options when exporting a file, see :ref:`the API reference<exportoptions>`.
8 changes: 4 additions & 4 deletions docs/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ Overview

.. contents:: Table of Contents

**fastgltf** is a speed and usability focused glTF 2.0 parser written in modern C++17 with minimal dependencies.
**fastgltf** is a speed and usability focused glTF 2.0 library written in modern C++17 with minimal dependencies.
It uses SIMD in various areas to decrease the time the application spends parsing and loading glTF data.
By taking advantage of modern C++17 (and optionally C++20) it also provides easy and safe access to the properties and data.

The parser supports the entirety of glTF 2.0 specification, including many extensions.
The library supports the entirety of glTF 2.0 specification, including many extensions.
By default, fastgltf will only do the absolute minimum to work with a glTF model.
However, it brings many additional features to ease working with the data,
including accessor tools, the ability to directly write to mapped GPU buffers, and decomposing transform matrices.
Expand Down Expand Up @@ -42,7 +42,7 @@ glTF libraries.
* - glTF 2.0 writing
- ✔️
- ✔️
-
- ✔️
* - Extension support
- ✔️
- 🟡¹
Expand Down Expand Up @@ -118,7 +118,7 @@ The following snippet illustrates how to use fastgltf to load a glTF file.

.. code:: c++

#include <fastgltf/parser.hpp>
#include <fastgltf/core.hpp>
#include <fastgltf/types.hpp>

void load(std::filesystem::path path) {
Expand Down
6 changes: 4 additions & 2 deletions docs/tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ For example, ``glm::vec3`` would be a vector of 3 floats, which would be defined
template <>
struct fastgltf::ElementTraits<glm::vec3> : fastgltf::ElementTraitsBase<glm::vec3, AccessorType::Vec3, float> {};

Note that, for glm types, there is a header with all pre-defined types shipped with fastgltf: ``fastgltf/glm_element_traits.hpp``.
This header includes the ElementTraits definition for all relevant glm types.
.. note::

Note that, for glm types, there is a header with all pre-defined types shipped with fastgltf: ``fastgltf/glm_element_traits.hpp``.
This header includes the ElementTraits definition for all relevant glm types.


.. warning::
Expand Down
5 changes: 4 additions & 1 deletion examples/gl_viewer/gl_viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@

#include <glad/gl.h>
#include <GLFW/glfw3.h>

// All headers not in the root directory require this
#define GLM_ENABLE_EXPERIMENTAL 1
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
Expand All @@ -37,7 +40,7 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#include <fastgltf/parser.hpp>
#include <fastgltf/core.hpp>
#include <fastgltf/types.hpp>

constexpr std::string_view vertexShaderSource = R"(
Expand Down
6 changes: 3 additions & 3 deletions fetch_test_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
import zipfile

example_deps_urls = {
'glfw': "https://github.com/glfw/glfw/releases/download/3.3.8/glfw-3.3.8.zip",
'glm': "https://github.com/g-truc/glm/releases/download/0.9.9.8/glm-0.9.9.8.zip",
'glfw': "https://github.com/glfw/glfw/releases/download/3.3.9/glfw-3.3.9.zip",
'glm': "https://github.com/g-truc/glm/archive/refs/tags/1.0.0.zip",
'stb': "https://github.com/nothings/stb/archive/refs/heads/master.zip",
'glad': "https://github.com/Dav1dde/glad/archive/refs/heads/glad2.zip",
}
test_deps_urls = {
'catch2': "https://github.com/catchorg/Catch2/archive/refs/tags/v3.3.2.zip",
'catch2': "https://github.com/catchorg/Catch2/archive/refs/tags/v3.5.2.zip",
'corrosion': "https://github.com/corrosion-rs/corrosion/archive/refs/heads/master.zip",
}
deps_folder = "deps/"
Expand Down
139 changes: 139 additions & 0 deletions include/fastgltf/parser.hpp → include/fastgltf/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,32 @@ namespace fastgltf {
*/
GenerateMeshIndices = 1 << 8,
};

enum class ExportOptions : std::uint64_t {
None = 0,

/**
* 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

FASTGLTF_ARITHMETIC_OP_TEMPLATE_MACRO(Options, Options, |)
FASTGLTF_ARITHMETIC_OP_TEMPLATE_MACRO(Options, Options, &)
FASTGLTF_ASSIGNMENT_OP_TEMPLATE_MACRO(Options, Options, |)
FASTGLTF_ASSIGNMENT_OP_TEMPLATE_MACRO(Options, Options, &)
FASTGLTF_UNARY_OP_TEMPLATE_MACRO(Options, ~)
FASTGLTF_ARITHMETIC_OP_TEMPLATE_MACRO(ExportOptions, ExportOptions, |)
FASTGLTF_ARITHMETIC_OP_TEMPLATE_MACRO(ExportOptions, ExportOptions, &)
FASTGLTF_ASSIGNMENT_OP_TEMPLATE_MACRO(ExportOptions, ExportOptions, |)
FASTGLTF_ASSIGNMENT_OP_TEMPLATE_MACRO(ExportOptions, ExportOptions, &)
FASTGLTF_UNARY_OP_TEMPLATE_MACRO(ExportOptions, ~)

// String representations of glTF 2.0 extension identifiers.
namespace extensions {
Expand Down Expand Up @@ -762,6 +781,126 @@ namespace fastgltf {
void setBase64DecodeCallback(Base64DecodeCallback* decodeCallback) noexcept;
void setUserPointer(void* pointer) noexcept;
};

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

/**
* Escapes a string for use in JSON.
*/
std::string escapeString(std::string_view string);

/**
* Returns a list of extension names based on the given extension flags.
*/
auto stringifyExtensionBits(Extensions extensions) -> decltype(Asset::extensionsRequired);

template <typename T>
struct ExportResult {
T output;

std::vector<std::optional<std::filesystem::path>> bufferPaths;
std::vector<std::optional<std::filesystem::path>> imagePaths;
};

/**
* A exporter for serializing one or more glTF assets 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:
Error errorCode = Error::None;
ExportOptions options = ExportOptions::None;
bool exportingBinary = false;

std::filesystem::path bufferFolder = "";
std::filesystem::path imageFolder = "";

std::vector<std::optional<std::filesystem::path>> bufferPaths;
std::vector<std::optional<std::filesystem::path>> imagePaths;

void writeAccessors(const Asset& asset, std::string& json);
void writeBuffers(const Asset& asset, std::string& json);
void writeBufferViews(const Asset& asset, std::string& json);
void writeCameras(const Asset& asset, std::string& json);
void writeImages(const Asset& asset, std::string& json);
void writeLights(const Asset& asset, std::string& json);
void writeMaterials(const Asset& asset, std::string& json);
void writeMeshes(const Asset& asset, std::string& json);
void writeNodes(const Asset& asset, std::string& json);
void writeSamplers(const Asset& asset, std::string& json);
void writeScenes(const Asset& asset, std::string& json);
void writeSkins(const Asset& asset, std::string& json);
void writeTextures(const Asset& asset, std::string& json);
void writeExtensions(const Asset& asset, std::string& json);

std::filesystem::path getBufferFilePath(const Asset& asset, std::size_t index);
std::filesystem::path getImageFilePath(const Asset& asset, std::size_t index, MimeType mimeType);

std::string writeJson(const Asset& asset);

public:
/**
* Sets the relative base path for buffer URIs.
*
* If folder.is_relative() returns false, this has no effect.
*/
void setBufferPath(std::filesystem::path folder);
/**
* Sets the relative base path for image URIs.
*
* If folder.is_relative() returns false, this has no effect.
*/
void setImagePath(std::filesystem::path folder);

/**
* Generates a glTF JSON string from the given asset.
*/
Expected<ExportResult<std::string>> writeGltfJson(const Asset& asset, ExportOptions options = ExportOptions::None);

/**
* Generates a glTF binary (GLB) blob from the given asset.
*
* If the first buffer holds a sources::Vector or sources::ByteView and the byte length is smaller than 2^32 (4.2GB),
* it will be embedded into the binary. Note that the returned vector might therefore get quite large.
*/
Expected<ExportResult<std::vector<std::byte>>> writeGltfBinary(const Asset& asset, ExportOptions options = ExportOptions::None);
};

/**
* A exporter for serializing one or more glTF files into JSON and GLB forms.
* This exporter builds upon Exporter by writing all files automatically to the
* given paths.
*/
class FileExporter : public Exporter {
using Exporter::writeGltfJson;
using Exporter::writeGltfBinary;

public:
/**
* Writes a glTF JSON string generated from the given asset to the specified target file. This will also write
* all buffers and textures to disk using the buffer and image paths set using Exporter::setBufferPath and
* Exporter::setImagePath.
*/
Error writeGltfJson(const Asset& asset, std::filesystem::path target, ExportOptions options = ExportOptions::None);

/**
* Writes a glTF binary (GLB) blob from the given asset to the specified target file. This will also write
* all buffers and textures to disk using the buffer and image paths set using Exporter::setBufferPath and
* Exporter::setImagePath.
*
* If the first buffer holds a sources::Vector or sources::ByteView and the byte length is smaller than 2^32 (4.2GB),
* it will be embedded into the binary.
*
* \see Exporter::writeGltfBinary
*/
Error writeGltfBinary(const Asset& asset, std::filesystem::path target, ExportOptions options = ExportOptions::None);
};
} // namespace fastgltf

#ifdef _MSC_VER
Expand Down
Loading

0 comments on commit 0272e59

Please sign in to comment.