parser.hpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. /*
  2. * Copyright (C) 2022 - 2023 spnda
  3. * This file is part of fastgltf <https://github.com/spnda/fastgltf>.
  4. *
  5. * Permission is hereby granted, free of charge, to any person
  6. * obtaining a copy of this software and associated documentation
  7. * files (the "Software"), to deal in the Software without
  8. * restriction, including without limitation the rights to use,
  9. * copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the
  11. * Software is furnished to do so, subject to the following
  12. * conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  19. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  24. * OTHER DEALINGS IN THE SOFTWARE.
  25. */
  26. #pragma once
  27. #include <memory>
  28. #include <tuple>
  29. #include "types.hpp"
  30. #ifdef _MSC_VER
  31. #pragma warning(push)
  32. #pragma warning(disable : 5030) // attribute 'x' is not recognized
  33. #pragma warning(disable : 4514) // unreferenced inline function has been removed
  34. #endif
  35. // fwd
  36. #if defined(__ANDROID__)
  37. struct AAssetManager;
  38. #endif
  39. namespace simdjson::dom {
  40. class array;
  41. class object;
  42. class parser;
  43. } // namespace simdjson::dom
  44. namespace fastgltf {
  45. enum class Error : std::uint64_t;
  46. template <typename T>
  47. class Expected;
  48. } // namespace fastgltf
  49. namespace std {
  50. template <typename T>
  51. struct tuple_size<fastgltf::Expected<T>> : std::integral_constant<std::size_t, 2> {};
  52. template <typename T>
  53. struct tuple_element<0, fastgltf::Expected<T>> { using type = fastgltf::Error; };
  54. template <typename T>
  55. struct tuple_element<1, fastgltf::Expected<T>> { using type = T; };
  56. } // namespace std
  57. namespace fastgltf {
  58. struct BinaryGltfChunk;
  59. class GltfDataBuffer;
  60. enum class Error : std::uint64_t {
  61. None = 0,
  62. InvalidPath = 1, ///< The glTF directory passed to load*GLTF is invalid.
  63. MissingExtensions = 2, ///< One or more extensions are required by the glTF but not enabled in the Parser.
  64. UnknownRequiredExtension = 3, ///< An extension required by the glTF is not supported by fastgltf.
  65. InvalidJson = 4, ///< An error occurred while parsing the JSON.
  66. InvalidGltf = 5, ///< The glTF is either missing something or has invalid data.
  67. InvalidOrMissingAssetField = 6, ///< The glTF asset object is missing or invalid.
  68. InvalidGLB = 7, ///< The GLB container is invalid.
  69. /**
  70. * A field is missing in the JSON.
  71. * @note This is only used internally.
  72. */
  73. MissingField = 8,
  74. MissingExternalBuffer = 9, ///< With Options::LoadExternalBuffers, an external buffer was not found.
  75. UnsupportedVersion = 10, ///< The glTF version is not supported by fastgltf.
  76. InvalidURI = 11, ///< A URI from a buffer or image failed to be parsed.
  77. };
  78. inline std::string_view getErrorName(Error error) {
  79. switch (error) {
  80. case Error::None: return "None";
  81. case Error::InvalidPath: return "InvalidPath";
  82. case Error::MissingExtensions: return "MissingExtensions";
  83. case Error::UnknownRequiredExtension: return "UnknownRequiredExtension";
  84. case Error::InvalidJson: return "InvalidJson";
  85. case Error::InvalidGltf: return "InvalidGltf";
  86. case Error::InvalidOrMissingAssetField: return "InvalidOrMissingAssetField";
  87. case Error::InvalidGLB: return "InvalidGLB";
  88. case Error::MissingField: return "MissingField";
  89. case Error::MissingExternalBuffer: return "MissingExternalBuffer";
  90. case Error::UnsupportedVersion: return "UnsupportedVersion";
  91. case Error::InvalidURI: return "InvalidURI";
  92. default: FASTGLTF_UNREACHABLE
  93. }
  94. }
  95. inline std::string_view getErrorMessage(Error error) {
  96. switch (error) {
  97. case Error::None: return "";
  98. case Error::InvalidPath: return "The glTF directory passed to load*GLTF is invalid";
  99. case Error::MissingExtensions: return "One or more extensions are required by the glTF but not enabled in the Parser.";
  100. case Error::UnknownRequiredExtension: return "An extension required by the glTF is not supported by fastgltf.";
  101. case Error::InvalidJson: return "An error occurred while parsing the JSON.";
  102. case Error::InvalidGltf: return "The glTF is either missing something or has invalid data.";
  103. case Error::InvalidOrMissingAssetField: return "The glTF asset object is missing or invalid.";
  104. case Error::InvalidGLB: return "The GLB container is invalid.";
  105. case Error::MissingField: return "";
  106. case Error::MissingExternalBuffer: return "An external buffer was not found.";
  107. case Error::UnsupportedVersion: return "The glTF version is not supported by fastgltf.";
  108. case Error::InvalidURI: return "A URI from a buffer or image failed to be parsed.";
  109. default: FASTGLTF_UNREACHABLE
  110. }
  111. }
  112. // clang-format off
  113. enum class Extensions : std::uint64_t {
  114. None = 0,
  115. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_texture_transform/README.md
  116. KHR_texture_transform = 1 << 1,
  117. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_texture_basisu/README.md
  118. KHR_texture_basisu = 1 << 2,
  119. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Vendor/MSFT_texture_dds/README.md
  120. MSFT_texture_dds = 1 << 3,
  121. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization/README.md
  122. KHR_mesh_quantization = 1 << 4,
  123. // See https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_meshopt_compression/README.md
  124. EXT_meshopt_compression = 1 << 5,
  125. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/README.md
  126. KHR_lights_punctual = 1 << 6,
  127. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Vendor/EXT_texture_webp/README.md
  128. EXT_texture_webp = 1 << 8,
  129. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_specular/README.md
  130. KHR_materials_specular = 1 << 9,
  131. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_ior/README.md
  132. KHR_materials_ior = 1 << 10,
  133. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_iridescence/README.md
  134. KHR_materials_iridescence = 1 << 11,
  135. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md
  136. KHR_materials_volume = 1 << 12,
  137. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_transmission/README.md
  138. KHR_materials_transmission = 1 << 13,
  139. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md
  140. KHR_materials_clearcoat = 1 << 14,
  141. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md
  142. KHR_materials_emissive_strength = 1 << 15,
  143. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_sheen/README.md
  144. KHR_materials_sheen = 1 << 16,
  145. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_unlit/README.md
  146. KHR_materials_unlit = 1 << 17,
  147. // See https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md
  148. KHR_materials_anisotropy = 1 << 18,
  149. // See https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_mesh_gpu_instancing/README.md
  150. EXT_mesh_gpu_instancing = 1 << 19,
  151. #if FASTGLTF_ENABLE_DEPRECATED_EXT
  152. // See https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness/README.md
  153. KHR_materials_pbrSpecularGlossiness = 1 << 20,
  154. #endif
  155. };
  156. // clang-format on
  157. FASTGLTF_ARITHMETIC_OP_TEMPLATE_MACRO(Extensions, Extensions, |)
  158. FASTGLTF_ARITHMETIC_OP_TEMPLATE_MACRO(Extensions, Extensions, &)
  159. FASTGLTF_ASSIGNMENT_OP_TEMPLATE_MACRO(Extensions, Extensions, |)
  160. FASTGLTF_ASSIGNMENT_OP_TEMPLATE_MACRO(Extensions, Extensions, &)
  161. FASTGLTF_UNARY_OP_TEMPLATE_MACRO(Extensions, ~)
  162. // clang-format off
  163. enum class Options : std::uint64_t {
  164. None = 0,
  165. /**
  166. * This allows 5130 as an accessor component type. 5130 is the OpenGL constant GL_DOUBLE,
  167. * which is by default not listed as an allowed component type in the glTF spec.
  168. *
  169. * The glTF normally only allows these component types:
  170. * https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#accessor-data-types
  171. */
  172. AllowDouble = 1 << 0,
  173. /**
  174. * This skips validating the asset field, as it is usually there and not used anyway.
  175. */
  176. DontRequireValidAssetMember = 1 << 1,
  177. /**
  178. * Loads all the GLB buffers into CPU memory. If disabled, fastgltf will only provide
  179. * a byte offset and length into the GLB file, which can be useful when using APIs like
  180. * DirectStorage or Metal IO.
  181. */
  182. LoadGLBBuffers = 1 << 3,
  183. /**
  184. * Loads all external buffers into CPU memory. If disabled, fastgltf will only provide
  185. * a full file path to the file holding the buffer, which can be useful when using APIs
  186. * like DirectStorage or Metal IO. For images, LoadExternalImages has to be explicitly
  187. * specified, too, if required.
  188. */
  189. LoadExternalBuffers = 1 << 4,
  190. /**
  191. * This option makes fastgltf automatically decompose the transformation matrices of nodes
  192. * into the translation, rotation, and scale components. This might be useful to have only
  193. * TRS components, instead of matrices or TRS, which should simplify working with nodes,
  194. * especially with animations.
  195. */
  196. DecomposeNodeMatrices = 1 << 5,
  197. /**
  198. * This option makes fastgltf minimise the JSON file before parsing. In most cases,
  199. * minimising it beforehand actually reduces the time spent. However, there are plenty
  200. * of cases where this option slows down parsing drastically, which from my testing seem
  201. * to all be glTFs which contain embedded buffers and/or are already minimised. Note that
  202. * fastgltf only minimises the string if the data was loaded using GltfDataBuffer::loadFromFile
  203. * or GltfDataBuffer::copyBytes, and that the bytes will also be overwritten.
  204. */
  205. MinimiseJsonBeforeParsing = 1 << 6,
  206. /**
  207. * Loads all external images into CPU memory. It does not decode any texture data. Complementary
  208. * to LoadExternalBuffers.
  209. */
  210. LoadExternalImages = 1 << 7,
  211. };
  212. // clang-format on
  213. FASTGLTF_ARITHMETIC_OP_TEMPLATE_MACRO(Options, Options, |)
  214. FASTGLTF_ARITHMETIC_OP_TEMPLATE_MACRO(Options, Options, &)
  215. FASTGLTF_ASSIGNMENT_OP_TEMPLATE_MACRO(Options, Options, |)
  216. FASTGLTF_ASSIGNMENT_OP_TEMPLATE_MACRO(Options, Options, &)
  217. FASTGLTF_UNARY_OP_TEMPLATE_MACRO(Options, ~)
  218. // String representations of glTF 2.0 extension identifiers.
  219. namespace extensions {
  220. constexpr std::string_view EXT_mesh_gpu_instancing = "EXT_mesh_gpu_instancing";
  221. constexpr std::string_view EXT_meshopt_compression = "EXT_meshopt_compression";
  222. constexpr std::string_view EXT_texture_webp = "EXT_texture_webp";
  223. constexpr std::string_view KHR_lights_punctual = "KHR_lights_punctual";
  224. constexpr std::string_view KHR_materials_anisotropy = "KHR_materials_anisotropy";
  225. constexpr std::string_view KHR_materials_clearcoat = "KHR_materials_clearcoat";
  226. constexpr std::string_view KHR_materials_emissive_strength = "KHR_materials_emissive_strength";
  227. constexpr std::string_view KHR_materials_ior = "KHR_materials_ior";
  228. constexpr std::string_view KHR_materials_iridescence = "KHR_materials_iridescence";
  229. constexpr std::string_view KHR_materials_sheen = "KHR_materials_sheen";
  230. constexpr std::string_view KHR_materials_specular = "KHR_materials_specular";
  231. constexpr std::string_view KHR_materials_transmission = "KHR_materials_transmission";
  232. constexpr std::string_view KHR_materials_unlit = "KHR_materials_unlit";
  233. constexpr std::string_view KHR_materials_volume = "KHR_materials_volume";
  234. constexpr std::string_view KHR_mesh_quantization = "KHR_mesh_quantization";
  235. constexpr std::string_view KHR_texture_basisu = "KHR_texture_basisu";
  236. constexpr std::string_view KHR_texture_transform = "KHR_texture_transform";
  237. constexpr std::string_view MSFT_texture_dds = "MSFT_texture_dds";
  238. #if FASTGLTF_ENABLE_DEPRECATED_EXT
  239. constexpr std::string_view KHR_materials_pbrSpecularGlossiness = "KHR_materials_pbrSpecularGlossiness";
  240. #endif
  241. } // namespace extensions
  242. // clang-format off
  243. // An array of pairs of string representations of extension identifiers and their respective enum
  244. // value used for enabling/disabling the loading of it. This also represents all extensions that
  245. // fastgltf supports and understands.
  246. #if FASTGLTF_ENABLE_DEPRECATED_EXT
  247. static constexpr size_t SUPPORTED_EXTENSION_COUNT = 19;
  248. #else
  249. static constexpr size_t SUPPORTED_EXTENSION_COUNT = 18;
  250. #endif
  251. static constexpr std::array<std::pair<std::string_view, Extensions>, SUPPORTED_EXTENSION_COUNT> extensionStrings = {{
  252. { extensions::EXT_mesh_gpu_instancing, Extensions::EXT_mesh_gpu_instancing },
  253. { extensions::EXT_meshopt_compression, Extensions::EXT_meshopt_compression },
  254. { extensions::EXT_texture_webp, Extensions::EXT_texture_webp },
  255. { extensions::KHR_lights_punctual, Extensions::KHR_lights_punctual },
  256. { extensions::KHR_materials_anisotropy, Extensions::KHR_materials_anisotropy },
  257. { extensions::KHR_materials_clearcoat, Extensions::KHR_materials_clearcoat },
  258. { extensions::KHR_materials_emissive_strength, Extensions::KHR_materials_emissive_strength },
  259. { extensions::KHR_materials_ior, Extensions::KHR_materials_ior },
  260. { extensions::KHR_materials_iridescence, Extensions::KHR_materials_iridescence },
  261. { extensions::KHR_materials_sheen, Extensions::KHR_materials_sheen },
  262. { extensions::KHR_materials_specular, Extensions::KHR_materials_specular },
  263. { extensions::KHR_materials_transmission, Extensions::KHR_materials_transmission },
  264. { extensions::KHR_materials_unlit, Extensions::KHR_materials_unlit },
  265. { extensions::KHR_materials_volume, Extensions::KHR_materials_volume },
  266. { extensions::KHR_mesh_quantization, Extensions::KHR_mesh_quantization },
  267. { extensions::KHR_texture_basisu, Extensions::KHR_texture_basisu },
  268. { extensions::KHR_texture_transform, Extensions::KHR_texture_transform },
  269. { extensions::MSFT_texture_dds, Extensions::MSFT_texture_dds },
  270. #if FASTGLTF_ENABLE_DEPRECATED_EXT
  271. { extensions::KHR_materials_pbrSpecularGlossiness,Extensions::KHR_materials_pbrSpecularGlossiness },
  272. #endif
  273. }};
  274. // clang-format on
  275. /**
  276. * Returns the name of the passed glTF extension.
  277. *
  278. * @note If \p extensions has more than one bit set (multiple extensions), this
  279. * will return the name of the first set bit.
  280. */
  281. #if FASTGLTF_CPP_20
  282. constexpr
  283. #else
  284. inline
  285. #endif
  286. std::string_view stringifyExtension(Extensions extensions) {
  287. // Find the first set bit and mask the value to that
  288. std::uint8_t position = 0;
  289. while (position < std::numeric_limits<std::underlying_type_t<Extensions>>::digits) {
  290. if (((to_underlying(extensions) >> position) & 1) != 0) {
  291. extensions &= static_cast<Extensions>(1 << position);
  292. break;
  293. }
  294. ++position;
  295. }
  296. for (const auto& extensionString : extensionStrings)
  297. if (extensionString.second == extensions)
  298. return extensionString.first;
  299. return "";
  300. }
  301. class ChunkMemoryResource : public std::pmr::memory_resource {
  302. /**
  303. * The default size of the individual blocks we allocate.
  304. */
  305. constexpr static std::size_t blockSize = 2048;
  306. struct Block {
  307. std::unique_ptr<std::byte[]> data;
  308. std::size_t size;
  309. std::byte* dataPointer;
  310. };
  311. SmallVector<Block, 4> blocks;
  312. std::size_t blockIdx = 0;
  313. public:
  314. explicit ChunkMemoryResource() {
  315. allocateNewBlock();
  316. }
  317. void allocateNewBlock() {
  318. auto& block = blocks.emplace_back();
  319. block.data = std::unique_ptr<std::byte[]>(new std::byte[blockSize]);
  320. block.dataPointer = block.data.get();
  321. block.size = blockSize;
  322. }
  323. [[nodiscard]] void* do_allocate(std::size_t bytes, std::size_t alignment) override {
  324. auto& block = blocks[blockIdx];
  325. auto availableSize = static_cast<std::size_t>(block.dataPointer - block.data.get());
  326. if ((availableSize + bytes) > block.size) {
  327. // The block can't fit the new allocation. We'll just create a new block and use that.
  328. allocateNewBlock();
  329. ++blockIdx;
  330. return do_allocate(bytes, alignment);
  331. }
  332. void* alloc = block.dataPointer;
  333. std::size_t space = availableSize;
  334. if (std::align(alignment, availableSize, alloc, space) == nullptr) {
  335. // Not enough space after alignment
  336. allocateNewBlock();
  337. ++blockIdx;
  338. return do_allocate(bytes, alignment);
  339. }
  340. // Get the number of bytes used for padding, and calculate the new offset using that
  341. block.dataPointer = block.dataPointer + (availableSize - space) + bytes;
  342. return alloc;
  343. }
  344. void do_deallocate([[maybe_unused]] void* p, [[maybe_unused]] std::size_t bytes, [[maybe_unused]] std::size_t alignment) override {
  345. // We currently do nothing, as we don't keep track of what portions of the blocks are still used.
  346. // Therefore, we keep all blocks alive until the destruction of this resource (parser).
  347. }
  348. [[nodiscard]] bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
  349. return this == std::addressof(other);
  350. }
  351. };
  352. /**
  353. * A type that stores an error together with an expected value.
  354. * To use this type, first call error() to inspect if any errors have occurred.
  355. * If error() is not fastgltf::Error::None,
  356. * calling get(), operator->(), and operator*() is undefined behaviour.
  357. */
  358. template <typename T>
  359. class Expected {
  360. static_assert(std::is_default_constructible_v<T>);
  361. static_assert(!std::is_same_v<Error, T>);
  362. Error err;
  363. T value;
  364. public:
  365. explicit Expected(Error error) : err(error) {}
  366. explicit Expected(T&& value) : err(Error::None), value(std::move(value)) {}
  367. Expected(const Expected<T>& other) = delete;
  368. Expected(Expected<T>&& other) noexcept : err(other.err), value(std::move(other.value)) {}
  369. Expected<T>& operator=(const Expected<T>& other) = delete;
  370. Expected<T>& operator=(Expected<T>&& other) noexcept {
  371. err = other.err;
  372. value = std::move(other.value);
  373. return *this;
  374. }
  375. [[nodiscard]] Error error() const noexcept {
  376. return err;
  377. }
  378. /**
  379. * Returns a reference to the value of T.
  380. * When error() returns anything but Error::None, the returned value is undefined.
  381. */
  382. [[nodiscard]] T& get() noexcept {
  383. assert(err == Error::None);
  384. return value;
  385. }
  386. /**
  387. * Returns the address of the value of T, or nullptr if error() returns anything but Error::None.
  388. */
  389. [[nodiscard]] T* get_if() noexcept {
  390. if (err != Error::None)
  391. return nullptr;
  392. return std::addressof(value);
  393. }
  394. template <std::size_t I>
  395. auto& get() noexcept {
  396. if constexpr (I == 0) return err;
  397. else if constexpr (I == 1) return value;
  398. }
  399. template <std::size_t I>
  400. const auto& get() const noexcept {
  401. if constexpr (I == 0) return err;
  402. else if constexpr (I == 1) return value;
  403. }
  404. /**
  405. * Returns the address of the value of T.
  406. * When error() returns anything but Error::None, the returned value is undefined.
  407. */
  408. T* operator->() noexcept {
  409. assert(err == Error::None);
  410. return std::addressof(value);
  411. }
  412. /**
  413. * Returns the address of the const value of T.
  414. * When error() returns anything but Error::None, the returned value is undefined.
  415. */
  416. const T* operator->() const noexcept {
  417. assert(err == Error::None);
  418. return std::addressof(value);
  419. }
  420. T&& operator*() && noexcept {
  421. assert(err == Error::None);
  422. return std::move(value);
  423. }
  424. operator bool() const noexcept {
  425. return err == Error::None;
  426. }
  427. };
  428. struct BufferInfo {
  429. void* mappedMemory;
  430. CustomBufferId customId;
  431. };
  432. using BufferMapCallback = BufferInfo(std::uint64_t bufferSize, void* userPointer);
  433. using BufferUnmapCallback = void(BufferInfo* bufferInfo, void* userPointer);
  434. using Base64DecodeCallback = void(std::string_view base64, std::uint8_t* dataOutput, std::size_t padding, std::size_t dataOutputSize, void* userPointer);
  435. /**
  436. * Enum to represent the type of a glTF file. glTFs can either be the standard JSON file with
  437. * paths to buffers or with a base64 embedded buffers, or they can be in a so called GLB
  438. * container format which has two or more chunks of binary data, where one represents buffers
  439. * and the other contains the JSON string.
  440. */
  441. enum class GltfType {
  442. glTF,
  443. GLB,
  444. Invalid,
  445. };
  446. /**
  447. * This function starts reading into the buffer and tries to determine what type of glTF container it is.
  448. * This should be used to know whether to call Parser::loadGLTF or Parser::loadBinaryGLTF.
  449. *
  450. * @return The type of the glTF file, either glTF, GLB, or Invalid if it was not determinable. If this function
  451. * returns Invalid it is highly likely that the buffer does not actually represent a valid glTF file.
  452. */
  453. GltfType determineGltfFileType(GltfDataBuffer* buffer);
  454. /**
  455. * Gets the amount of byte padding required on the GltfDataBuffer, as simdjson requires to be
  456. * able to overflow as it uses SIMD to load N bytes at a time.
  457. */
  458. std::size_t getGltfBufferPadding() noexcept;
  459. /**
  460. * This class holds a chunk of data that makes up a JSON string that the glTF parser will use
  461. * and read from.
  462. */
  463. class GltfDataBuffer {
  464. friend class Parser;
  465. friend GltfType determineGltfFileType(GltfDataBuffer* buffer);
  466. protected:
  467. std::size_t allocatedSize = 0;
  468. std::size_t dataSize = 0;
  469. std::byte* bufferPointer = nullptr;
  470. std::unique_ptr<std::byte[]> buffer;
  471. std::filesystem::path filePath = {};
  472. public:
  473. explicit GltfDataBuffer() noexcept;
  474. /**
  475. * Constructs a new GltfDataBuffer from a span object, copying its data as there
  476. * is no guarantee for the allocation size to have the adequate padding.
  477. */
  478. explicit GltfDataBuffer(span<std::byte> data) noexcept;
  479. virtual ~GltfDataBuffer() noexcept;
  480. /**
  481. * Saves the pointer including its range. Does not copy any data. This requires the
  482. * original allocation to outlive the parsing of the glTF, so after the last relevant
  483. * call to fastgltf::Parser::loadGLTF. However, this function asks for a capacity size, as
  484. * the JSON parsing requires some padding. See fastgltf::getGltfBufferPadding for more information.
  485. * If the capacity does not have enough padding, the function will instead copy the bytes
  486. * with the copyBytes method. Also, it will set the padding bytes all to 0, so be sure to
  487. * not use that for any other data.
  488. */
  489. bool fromByteView(std::uint8_t* bytes, std::size_t byteCount, std::size_t capacity) noexcept;
  490. /**
  491. * This will create a copy of the passed bytes and allocate an adequately sized buffer.
  492. */
  493. bool copyBytes(const std::uint8_t* bytes, std::size_t byteCount) noexcept;
  494. /**
  495. * Loads the file with a optional byte offset into a memory buffer.
  496. */
  497. bool loadFromFile(const std::filesystem::path& path, std::uint64_t byteOffset = 0) noexcept;
  498. /**
  499. * Returns the size, in bytes,
  500. * @return
  501. */
  502. [[nodiscard]] inline std::size_t getBufferSize() const noexcept;
  503. [[nodiscard]] explicit operator span<std::byte>() {
  504. return span<std::byte>(bufferPointer, dataSize);
  505. }
  506. };
  507. #if defined(__ANDROID__)
  508. class AndroidGltfDataBuffer : public GltfDataBuffer {
  509. AAssetManager* assetManager;
  510. public:
  511. explicit AndroidGltfDataBuffer(AAssetManager* assetManager) noexcept;
  512. ~AndroidGltfDataBuffer() noexcept = default;
  513. /**
  514. * Loads a file from within an Android APK
  515. */
  516. bool loadFromAndroidAsset(const std::filesystem::path& path, std::uint64_t byteOffset = 0) noexcept;
  517. };
  518. #endif
  519. /**
  520. * This function further validates all the input more strictly that is parsed from the glTF.
  521. * Realistically, this should not be necessary in Release applications, but could be helpful
  522. * when debugging an asset related issue.
  523. */
  524. [[nodiscard]] Error validate(const Asset& asset);
  525. /**
  526. * Some internals the parser passes on to each glTF instance.
  527. */
  528. struct ParserInternalConfig {
  529. BufferMapCallback* mapCallback = nullptr;
  530. BufferUnmapCallback* unmapCallback = nullptr;
  531. Base64DecodeCallback* decodeCallback = nullptr;
  532. void* userPointer = nullptr;
  533. Extensions extensions = Extensions::None;
  534. };
  535. /**
  536. * A parser for one or more glTF files. It uses a SIMD based JSON parser to maximize efficiency
  537. * and performance at runtime.
  538. *
  539. * @note This class is not thread-safe.
  540. */
  541. class Parser {
  542. // The simdjson parser object. We want to share it between runs, so it does not need to
  543. // reallocate over and over again. We're hiding it here to not leak the simdjson header.
  544. std::unique_ptr<simdjson::dom::parser> jsonParser;
  545. ParserInternalConfig config = {};
  546. DataSource glbBuffer;
  547. std::shared_ptr<ChunkMemoryResource> resourceAllocator;
  548. std::filesystem::path directory;
  549. Options options;
  550. static auto getMimeTypeFromString(std::string_view mime) -> MimeType;
  551. static void fillCategories(Category& inputCategories) noexcept;
  552. [[nodiscard]] auto decodeDataUri(URIView& uri) const noexcept -> Expected<DataSource>;
  553. [[nodiscard]] auto loadFileFromUri(URIView& uri) const noexcept -> Expected<DataSource>;
  554. Error parseAccessors(simdjson::dom::array& array, Asset& asset);
  555. Error parseAnimations(simdjson::dom::array& array, Asset& asset);
  556. Error parseBuffers(simdjson::dom::array& array, Asset& asset);
  557. Error parseBufferViews(simdjson::dom::array& array, Asset& asset);
  558. Error parseCameras(simdjson::dom::array& array, Asset& asset);
  559. Error parseExtensions(simdjson::dom::object& extensionsObject, Asset& asset);
  560. Error parseImages(simdjson::dom::array& array, Asset& asset);
  561. Error parseLights(simdjson::dom::array& array, Asset& asset);
  562. Error parseMaterials(simdjson::dom::array& array, Asset& asset);
  563. Error parseMeshes(simdjson::dom::array& array, Asset& asset);
  564. Error parseNodes(simdjson::dom::array& array, Asset& asset);
  565. Error parseSamplers(simdjson::dom::array& array, Asset& asset);
  566. Error parseScenes(simdjson::dom::array& array, Asset& asset);
  567. Error parseSkins(simdjson::dom::array& array, Asset& asset);
  568. Error parseTextures(simdjson::dom::array& array, Asset& asset);
  569. Expected<Asset> parse(simdjson::dom::object root, Category categories);
  570. public:
  571. explicit Parser(Extensions extensionsToLoad = Extensions::None) noexcept;
  572. explicit Parser(const Parser& parser) = delete;
  573. Parser(Parser&& parser) noexcept;
  574. Parser& operator=(const Parser& parser) = delete;
  575. Parser& operator=(Parser&& other) noexcept;
  576. ~Parser();
  577. /**
  578. * Loads a glTF file from pre-loaded bytes representing a JSON file.
  579. *
  580. * @return An Asset wrapped in an Expected type, which may contain an error if one occurred.
  581. */
  582. [[nodiscard]] Expected<Asset> loadGLTF(GltfDataBuffer* buffer, std::filesystem::path directory, Options options = Options::None, Category categories = Category::All);
  583. /**
  584. * Loads a glTF file embedded within a GLB container, which may contain the first buffer of the glTF asset.
  585. *
  586. * @return An Asset wrapped in an Expected type, which may contain an error if one occurred.
  587. */
  588. [[nodiscard]] Expected<Asset> loadBinaryGLTF(GltfDataBuffer* buffer, std::filesystem::path directory, Options options = Options::None, Category categories = Category::All);
  589. /**
  590. * This function can be used to set callbacks so that you can control memory allocation for
  591. * large buffers and images that are loaded from a glTF file. For example, one could use
  592. * the callbacks to map a GPU buffer through Vulkan or DirectX so that fastgltf can write
  593. * the buffer directly to the GPU to avoid a copy into RAM first. To remove the callbacks
  594. * for a specific load, call this method with both parameters as nullptr before load*GLTF.
  595. * Using Parser::setUserPointer you can also set a user pointer to access your
  596. * own class or other data you may need.
  597. *
  598. * @param mapCallback function called when the parser requires a buffer to write data
  599. * embedded in a GLB file or decoded from a base64 URI, cannot be nullptr.
  600. * @param unmapCallback function called when the parser is done with writing into a
  601. * buffer, can be nullptr.
  602. * @note This is likely only useful for advanced users who know what they're doing.
  603. */
  604. void setBufferAllocationCallback(BufferMapCallback* mapCallback, BufferUnmapCallback* unmapCallback = nullptr) noexcept;
  605. /**
  606. * Allows setting callbacks for base64 decoding.
  607. * This can be useful if you have another base64 decoder optimised for a certain platform or architecture,
  608. * or want to use your own scheduler to schedule multiple threads for working on decoding individual chunks of the data.
  609. * Using Parser::setUserPointer you can also set a user pointer to access your own class or other data you may need.
  610. *
  611. * It is still recommended to use fastgltf's base64 decoding features as they're highly optimised
  612. * for SSE4, AVX2, and ARM Neon.
  613. *
  614. * @param decodeCallback function called when the parser tries to decode a base64 buffer
  615. */
  616. void setBase64DecodeCallback(Base64DecodeCallback* decodeCallback) noexcept;
  617. void setUserPointer(void* pointer) noexcept;
  618. };
  619. } // namespace fastgltf
  620. #ifdef _MSC_VER
  621. #pragma warning(pop)
  622. #endif