This is a major release with many breaking API changes. Most importantly, the library now requires C++20. Please read the entries marked "Change" below when upgrading.
As a quick overview, the most important changes are:
- Rewritten the
Exporterusing simdjson's newstring_builderAPI. It is now roughly 4x faster. - Significant memory optimizations reducing the average asset (measured on the glTF-Sample-Assets repository) by 37% and reducing the average allocation count by 59%.
- For example, on Intel's NewSponza the Asset is 31.4% smaller (581KB vs 846KB) with 51.5% less allocations (812 vs 1674) compared to v0.9.1 (on arm64 macOS with Clang 23).
- Switched to
simdutffor base64 decoding for a ~30% performance improvement as well as better error detection & handling. - Added a
boxandboxed_optionaltype for better ergonomics working with optional glTF data. - Rewritten all supporting containers such as
small_vector,optional, andstatic_vector, fixing a lot of unexpected behavior and memory and exception safety issues. - Implemented fuzzing for the parser, exporter, and URI parser, fixing an incredible amount of issues and edge cases.
- Updated the library to C++20
This is a major milestone as fastgltf has now hit v1.0. However, I want to be clear that there's still a lot of things that I plan on changing in the future. v1.0 was more focused on fixing as many existing issues as possible while laying the groundwork in terms of API changes and supporting functionality to have a better base to expand upon.
I also wanted to finally ditch the 0-based versioning and stick to proper semantic versioning. Previous version numbers were always loosely based on "how much has changed" (see v0.8 vs v0.9, there's no actual reason to bump the minor version since they're completely compatible).
Also, this is the first major version of fastgltf to require C++20 instead of C++17. This was done because I think nearing the end of 2026 there should be enough support for C++20 and the amount of things I had to workaround or implement myself which are features of the language or standard library with C++20 was surprisingly large.
With this release the library recognizes glTF 2.1 assets. This does not mean that it can load all of them: assets requiring 2.1 through minVersion and GLB version 3 files are rejected, while 2.1 assets compatible with 2.0 load as usual.
- Add: Support for more extensions
KHR_accessor_float16EXT_texture_avif
- Add: Support for 16-bit floats and 64-bit integers in accessors
ComponentTypenow hasHalfFloat,Int64, andUnsignedInt64.std::float16_tis also supported on supporting compilers. Otherwisefastgltf::HalfFloatcan be used as a storage type. See the documentation for more details.
- Add:
GltfDataStringto easily pass strings or literals to the parser - Add:
validateAccessorBoundsto validate a single accessor against its buffer view and buffer - Add:
box(a conformant implementation ofstd::indirect(C++26)) andboxed_optionalcontainers- This type is essentially a fancy wrapper around a
std::unique_ptrbut with value-like semantics boxed_optionalprovides thestd::optionalinterface but uses aboxinternally withnullptrbeing the valueless state.- Members data such as
Accessor::sparse,Material::clearcoatandBufferView::meshoptCompressionare now aboxed_optionalinstead of astd::unique_ptrfor a better usage API
- This type is essentially a fancy wrapper around a
- Add: Fuzzing targets, which can be enabled with the
FASTGLTF_ENABLE_FUZZINGCMake option (#158)- Fix #160: Guard against invalid accessor indices when generating mesh indices
- Fix: Integer underflow when generating mesh indices causing large allocations
- Fix: Malformed data URIs could read out of bounds or overflow the output (@tim-tim707)
- Fix: GLB JSON chunk total length check
- Fix: Always reset the GLB buffer when reusing a parser
- Fix: Avoid NaNs when decomposing a matrix with zero scale
- Fix: Catch out-of-range and non-finite numbers, and use
numin all remaining types - Fix: Guard against large and out-of-bounds material variants
- Fix: Check glTF indices against the sentinel values used by
flagged_optional - Fix: Check invalid sparse accessor buffer views and animation channel accessors in
validate - Change: Reject duplicated root JSON objects, meshes with no primitives, non-finite node transforms, accessor bounds that don't fit into 2^63, and unknown enumeration values
- Add: CMake options
FASTGLTF_DOWNLOAD_SIMDJSONandFASTGLTF_DOWNLOAD_SIMDUTF- Downloaded dependencies are now checked against their SHA256, and are installed alongside fastgltf.
- Disabling these options makes fastgltf fail if
find_packagecannot resolve either library.
- Add:
std::ostreamoverload andstd::formatterspecialization forError - Change: Completely rewrite
fastgltf::small_vector,fastgltf::static_vector, and addfastgltf::inplace_vectorfastgltf::small_vectoris now completely compatible withstd::vector- The containers now all offer the same exception guarantees that comparable
stdcontainers do. - The containers are now completely allocator compliant
- Fixed a significant amount of memory and exception safety issues
- Renamed the containers and all of their member functions to snake_case to match the C++ standard containers
- Support for C++23's
std::from_range,assign_range, andappend_range
- Change: Rename
OptionaltooptionalandOptionalWithFlagValuetoflagged_optional- Flag traits now also allow complex types in
flagged_optional. flagged_optionalandboxed_optionalnow share a genericbasic_optionalinterface
- Flag traits now also allow complex types in
- Change: Replace the custom base64 implementations with simdutf (#159)
- fastgltf now depends on simdutf, which is downloaded by default.
base64::decodenow returns anExpected, andbase64::decode_inplacereturns a bool. Both now report malformed input.- The custom NEON/SSE/AVX decode functions have been removed in favor of the simdutf functions since benchmarks showed them to be more performant while being stricter.
Parser::setBase64DecodeCallbackandBase64DecodeCallbackwere removed.
- Change: Rewrite
Expectedas a tagged union, which also allows any error type- Using
Expectedas a tuple with structured bindings is not possible anymore since it has become a union. - New errors:
InvalidVersion,ValueOutOfRange,UnexpectedJsonType,MissingExternalFile, andUnknown. Error::MissingExternalBufferandError::InvalidOrMissingAssetFieldare now deprecated aliases forError::MissingExternalFileandError::InvalidGltf.
- Using
- Change: Harden version parsing and checks (#165)
- This was done to reject assets that advertise minVersion as 2.1.
AssetInfo::gltfVersionis nowAssetInfo::versionand uses the newVersiontype.AssetInfo::minVersionis now anoptional<Version>.Asset::assetInfois no longer optional, andOptions::DontRequireValidAssetMemberwas removed.- Version strings are now parsed using the stricter syntax defined by glTF 2.1.
- Change: Remove all usage of polymorphic allocators and the custom memory pool
- Nearly all strings and vectors in the glTF types are now
std::stringandstd::vector. Primitive::findAttributeand similar functions now returnstd::vectoriterators instead of pointers.- The CMake options
FASTGLTF_DISABLE_CUSTOM_MEMORY_POOLandFASTGLTF_USE_CUSTOM_SMALLVECTORwere removed. - Removed
MaybeSmallVector.
- Nearly all strings and vectors in the glTF types are now
- Change:
sources::URI::uriis now boxed to reduce the size ofDataSource - Change:
Shapeis now a struct holding the variant inShape::data, and also has anamefor better future compatibility with glTF 2.1 - Change:
KHR_implicit_shapesandKHR_physics_rigid_bodiesare now always available- The CMake options
FASTGLTF_ENABLE_KHR_IMPLICIT_SHAPESandFASTGLTF_ENABLE_KHR_PHYSICS_RIGID_BODIESwere removed. Enable the extensions through theParserlike any other extension.
- The CMake options
- Change: Split
core.hppintoparser.hppandexporter.hppcore.hppcontinues to exist and holds the validation functionality
- Change: Deprecate
fastgltf::spanandfastgltf::dynamic_extent. Use thestdtypes instead. - Change: Removed
math::piin favor ofstd::numbers::pi. - Removed macros: FASTGLTF_CPP_17, FASTGLTF_CPP_20, FASTGLTF_HAS_BIT, FASTGLTF_HAS_CONCEPTS, FASTGLTF_CONSTEXPR_BITCAST, FASTGLTF_LIKELY / FASTGLTF_UNLIKELY
- Removed CMake option: FASTGLTF_COMPILE_AS_CPP20.
- Various fixes and improvements to the URI parser
- The parser was rewritten.
URI::decodePercentsis now the free functiondecodePercents, which returns the decoded string.- Fix: A
%without two hex digits read out of bounds (@tim-tim707) - Fix: Treat
?after#as part of the URI fragment (@Shaisolaris, #161)
- Various fixes and improvements to the Exporter interface
- Fix: Percent-encode file paths written as URIs (@khiner)
- Fix: Add missing
Colormeshopt compression filter
- Fix #86: Move ordinary includes before the module purview
- Fix: Keep scenes that omit nodes (@khiner)
- Fix:
GenerateMeshIndicesnow generates correct indices for strip, fan, and loop topologies - Fix:
copyComponentsFromAccessorused the wrong destination address when converting components - Fix: Wrong accessor element trait type for signed 32-bit vectors
- Fix: Don't throw an error when
visible,selectable, orhoverableis missing - Fix #164: Check the correct error for a missing
KHR_lights_punctualobject - Fix: Check errors returned from parsing material extensions
- Fix: Skip the directory check in
loadGltfBinaryon Android to matchloadGltfJson(@1runeberg, #155) - Fix: Don't leak the file descriptor in
MappedGltfFilewhenfstatfails - Fix: Compile with more warnings enabled and
/W4on MSVC, and fix all of them accordingly - Docs: Clarify the external buffer and image loading options (@snowyukitty, #162)
- Bump builtin simdjson version from 4.6.0 to 5.1.0
... and a significant amount of various minor improvements and fixes!