2
0

tiniergltf.hpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357
  1. #pragma once
  2. #include <json/json.h>
  3. #include <functional>
  4. #include <stack>
  5. #include <string>
  6. #include <string_view>
  7. #include <variant>
  8. #include <vector>
  9. #include <array>
  10. #include <optional>
  11. #include <limits>
  12. #include <stdexcept>
  13. #include <unordered_map>
  14. #include <unordered_set>
  15. #include "util/base64.h"
  16. namespace tiniergltf {
  17. static inline void check(bool cond) {
  18. if (!cond)
  19. throw std::runtime_error("invalid glTF");
  20. }
  21. template <typename T>
  22. static inline void checkIndex(const std::optional<std::vector<T>> &vec,
  23. const std::optional<std::size_t> &i) {
  24. if (!i.has_value()) return;
  25. check(vec.has_value());
  26. check(i < vec->size());
  27. }
  28. template <typename T>
  29. static inline void checkIndex(const std::vector<T> &vec,
  30. const std::optional<std::size_t> &i) {
  31. if (!i.has_value()) return;
  32. check(i < vec.size());
  33. }
  34. template <typename T, typename F>
  35. static inline void checkForall(const std::optional<std::vector<T>> &vec, const F &cond) {
  36. if (!vec.has_value())
  37. return;
  38. for (const T &v : vec.value())
  39. cond(v);
  40. }
  41. template <typename T>
  42. static inline void checkDuplicateFree(const std::vector<T> &vec) {
  43. check(std::unordered_set<T>(vec.begin(), vec.end()).size() == vec.size());
  44. }
  45. template <typename T>
  46. static inline T as(const Json::Value &o);
  47. template<>
  48. bool as(const Json::Value &o) {
  49. check(o.isBool());
  50. return o.asBool();
  51. }
  52. template<>
  53. double as (const Json::Value &o) {
  54. check(o.isDouble());
  55. return o.asDouble();
  56. }
  57. template<>
  58. std::size_t as(const Json::Value &o) {
  59. check(o.isUInt64());
  60. auto u = o.asUInt64();
  61. check(u <= std::numeric_limits<std::size_t>::max());
  62. return u;
  63. }
  64. template<>
  65. std::string as(const Json::Value &o) {
  66. check(o.isString());
  67. return o.asString();
  68. }
  69. template<typename U>
  70. std::vector<U> asVec(const Json::Value &o) {
  71. check(o.isArray());
  72. std::vector<U> res;
  73. res.reserve(o.size());
  74. for (Json::ArrayIndex i = 0; i < o.size(); ++i) {
  75. res.push_back(as<U>(o[i]));
  76. }
  77. return res;
  78. }
  79. template<typename U, std::size_t n>
  80. std::array<U, n> asArr(const Json::Value &o) {
  81. check(o.isArray());
  82. check(o.size() == n);
  83. std::array<U, n> res;
  84. for (Json::ArrayIndex i = 0; i < n; ++i) {
  85. res[i] = as<U>(o[i]);
  86. }
  87. return res;
  88. }
  89. struct AccessorSparseIndices {
  90. std::size_t bufferView;
  91. std::size_t byteOffset;
  92. // as defined in the glTF specification
  93. enum class ComponentType {
  94. UNSIGNED_BYTE,
  95. UNSIGNED_SHORT,
  96. UNSIGNED_INT,
  97. };
  98. ComponentType componentType;
  99. std::size_t componentSize() const {
  100. switch (componentType) {
  101. case ComponentType::UNSIGNED_BYTE:
  102. return 1;
  103. case ComponentType::UNSIGNED_SHORT:
  104. return 2;
  105. case ComponentType::UNSIGNED_INT:
  106. return 4;
  107. }
  108. throw std::logic_error("invalid component type");
  109. }
  110. std::size_t elementSize() const {
  111. return componentSize();
  112. }
  113. AccessorSparseIndices(const Json::Value &o)
  114. : bufferView(as<std::size_t>(o["bufferView"]))
  115. , byteOffset(0)
  116. {
  117. check(o.isObject());
  118. if (o.isMember("byteOffset")) {
  119. byteOffset = as<std::size_t>(o["byteOffset"]);
  120. check(byteOffset >= 0);
  121. }
  122. {
  123. static std::unordered_map<Json::UInt64, ComponentType> map = {
  124. {5121, ComponentType::UNSIGNED_BYTE},
  125. {5123, ComponentType::UNSIGNED_SHORT},
  126. {5125, ComponentType::UNSIGNED_INT},
  127. };
  128. const auto &v = o["componentType"]; check(v.isUInt64());
  129. componentType = map.at(v.asUInt64());
  130. }
  131. }
  132. };
  133. template<> AccessorSparseIndices as(const Json::Value &o) { return o; }
  134. struct AccessorSparseValues {
  135. std::size_t bufferView;
  136. std::size_t byteOffset;
  137. AccessorSparseValues(const Json::Value &o)
  138. : bufferView(as<std::size_t>(o["bufferView"]))
  139. , byteOffset(0)
  140. {
  141. check(o.isObject());
  142. if (o.isMember("byteOffset")) {
  143. byteOffset = as<std::size_t>(o["byteOffset"]);
  144. check(byteOffset >= 0);
  145. }
  146. }
  147. };
  148. template<> AccessorSparseValues as(const Json::Value &o) { return o; }
  149. struct AccessorSparse {
  150. std::size_t count;
  151. AccessorSparseIndices indices;
  152. AccessorSparseValues values;
  153. AccessorSparse(const Json::Value &o)
  154. : count(as<std::size_t>(o["count"]))
  155. , indices(as<AccessorSparseIndices>(o["indices"]))
  156. , values(as<AccessorSparseValues>(o["values"]))
  157. {
  158. check(o.isObject());
  159. check(count >= 1);
  160. }
  161. };
  162. template<> AccessorSparse as(const Json::Value &o) { return o; }
  163. struct Accessor {
  164. std::optional<std::size_t> bufferView;
  165. std::size_t byteOffset;
  166. // as defined in the glTF specification
  167. enum class ComponentType {
  168. BYTE,
  169. UNSIGNED_BYTE,
  170. SHORT,
  171. UNSIGNED_SHORT,
  172. UNSIGNED_INT,
  173. FLOAT,
  174. };
  175. ComponentType componentType;
  176. std::size_t componentSize() const {
  177. switch (componentType) {
  178. case ComponentType::BYTE:
  179. case ComponentType::UNSIGNED_BYTE:
  180. return 1;
  181. case ComponentType::SHORT:
  182. case ComponentType::UNSIGNED_SHORT:
  183. return 2;
  184. case ComponentType::UNSIGNED_INT:
  185. case ComponentType::FLOAT:
  186. return 4;
  187. }
  188. throw std::logic_error("invalid component type");
  189. }
  190. std::size_t count;
  191. std::optional<std::vector<double>> max;
  192. std::optional<std::vector<double>> min;
  193. std::optional<std::string> name;
  194. bool normalized;
  195. std::optional<AccessorSparse> sparse;
  196. enum class Type {
  197. MAT2,
  198. MAT3,
  199. MAT4,
  200. SCALAR,
  201. VEC2,
  202. VEC3,
  203. VEC4,
  204. };
  205. std::size_t typeCount() const {
  206. switch (type) {
  207. case Type::SCALAR:
  208. return 1;
  209. case Type::VEC2:
  210. return 2;
  211. case Type::VEC3:
  212. return 3;
  213. case Type::MAT2:
  214. case Type::VEC4:
  215. return 4;
  216. case Type::MAT3:
  217. return 9;
  218. case Type::MAT4:
  219. return 16;
  220. }
  221. throw std::logic_error("invalid type");
  222. }
  223. Type type;
  224. std::size_t elementSize() const {
  225. return componentSize() * typeCount();
  226. }
  227. Accessor(const Json::Value &o)
  228. : byteOffset(0)
  229. , count(as<std::size_t>(o["count"]))
  230. , normalized(false)
  231. {
  232. check(o.isObject());
  233. if (o.isMember("bufferView")) {
  234. bufferView = as<std::size_t>(o["bufferView"]);
  235. }
  236. {
  237. static std::unordered_map<Json::UInt64, ComponentType> map = {
  238. {5120, ComponentType::BYTE},
  239. {5121, ComponentType::UNSIGNED_BYTE},
  240. {5122, ComponentType::SHORT},
  241. {5123, ComponentType::UNSIGNED_SHORT},
  242. {5125, ComponentType::UNSIGNED_INT},
  243. {5126, ComponentType::FLOAT},
  244. };
  245. const auto &v = o["componentType"]; check(v.isUInt64());
  246. componentType = map.at(v.asUInt64());
  247. }
  248. if (o.isMember("byteOffset")) {
  249. byteOffset = as<std::size_t>(o["byteOffset"]);
  250. check(byteOffset >= 0);
  251. check(byteOffset % componentSize() == 0);
  252. }
  253. check(count >= 1);
  254. if (o.isMember("name")) {
  255. name = as<std::string>(o["name"]);
  256. }
  257. if (o.isMember("normalized")) {
  258. normalized = as<bool>(o["normalized"]);
  259. }
  260. if (o.isMember("sparse")) {
  261. sparse = as<AccessorSparse>(o["sparse"]);
  262. }
  263. {
  264. static std::unordered_map<Json::String, Type> map = {
  265. {"MAT2", Type::MAT2},
  266. {"MAT3", Type::MAT3},
  267. {"MAT4", Type::MAT4},
  268. {"SCALAR", Type::SCALAR},
  269. {"VEC2", Type::VEC2},
  270. {"VEC3", Type::VEC3},
  271. {"VEC4", Type::VEC4},
  272. };
  273. const auto &v = o["type"]; check(v.isString());
  274. type = map.at(v.asString());
  275. }
  276. if (o.isMember("max")) {
  277. max = asVec<double>(o["max"]);
  278. check(max->size() == typeCount());
  279. }
  280. if (o.isMember("min")) {
  281. min = asVec<double>(o["min"]);
  282. check(min->size() == typeCount());
  283. }
  284. }
  285. };
  286. template<> Accessor as(const Json::Value &o) { return o; }
  287. struct AnimationChannelTarget {
  288. std::optional<std::size_t> node;
  289. enum class Path {
  290. ROTATION,
  291. SCALE,
  292. TRANSLATION,
  293. WEIGHTS,
  294. };
  295. Path path;
  296. AnimationChannelTarget(const Json::Value &o)
  297. {
  298. check(o.isObject());
  299. if (o.isMember("node")) {
  300. node = as<std::size_t>(o["node"]);
  301. }
  302. {
  303. static std::unordered_map<Json::String, Path> map = {
  304. {"rotation", Path::ROTATION},
  305. {"scale", Path::SCALE},
  306. {"translation", Path::TRANSLATION},
  307. {"weights", Path::WEIGHTS},
  308. };
  309. const auto &v = o["path"]; check(v.isString());
  310. path = map.at(v.asString());
  311. }
  312. }
  313. };
  314. template<> AnimationChannelTarget as(const Json::Value &o) { return o; }
  315. struct AnimationChannel {
  316. std::size_t sampler;
  317. AnimationChannelTarget target;
  318. AnimationChannel(const Json::Value &o)
  319. : sampler(as<std::size_t>(o["sampler"]))
  320. , target(as<AnimationChannelTarget>(o["target"]))
  321. {
  322. check(o.isObject());
  323. }
  324. };
  325. template<> AnimationChannel as(const Json::Value &o) { return o; }
  326. struct AnimationSampler {
  327. std::size_t input;
  328. enum class Interpolation {
  329. CUBICSPLINE,
  330. LINEAR,
  331. STEP,
  332. };
  333. Interpolation interpolation;
  334. std::size_t output;
  335. AnimationSampler(const Json::Value &o)
  336. : input(as<std::size_t>(o["input"]))
  337. , interpolation(Interpolation::LINEAR)
  338. , output(as<std::size_t>(o["output"]))
  339. {
  340. check(o.isObject());
  341. if (o.isMember("interpolation")) {
  342. static std::unordered_map<Json::String, Interpolation> map = {
  343. {"CUBICSPLINE", Interpolation::CUBICSPLINE},
  344. {"LINEAR", Interpolation::LINEAR},
  345. {"STEP", Interpolation::STEP},
  346. };
  347. const auto &v = o["interpolation"]; check(v.isString());
  348. interpolation = map.at(v.asString());
  349. }
  350. }
  351. };
  352. template<> AnimationSampler as(const Json::Value &o) { return o; }
  353. struct Animation {
  354. std::vector<AnimationChannel> channels;
  355. std::optional<std::string> name;
  356. std::vector<AnimationSampler> samplers;
  357. Animation(const Json::Value &o)
  358. : channels(asVec<AnimationChannel>(o["channels"]))
  359. , samplers(asVec<AnimationSampler>(o["samplers"]))
  360. {
  361. check(o.isObject());
  362. check(channels.size() >= 1);
  363. if (o.isMember("name")) {
  364. name = as<std::string>(o["name"]);
  365. }
  366. check(samplers.size() >= 1);
  367. }
  368. };
  369. template<> Animation as(const Json::Value &o) { return o; }
  370. struct Asset {
  371. std::optional<std::string> copyright;
  372. std::optional<std::string> generator;
  373. std::optional<std::string> minVersion;
  374. std::string version;
  375. Asset(const Json::Value &o)
  376. : version(as<std::string>(o["version"]))
  377. {
  378. check(o.isObject());
  379. if (o.isMember("copyright")) {
  380. copyright = as<std::string>(o["copyright"]);
  381. }
  382. if (o.isMember("generator")) {
  383. generator = as<std::string>(o["generator"]);
  384. }
  385. if (o.isMember("minVersion")) {
  386. minVersion = as<std::string>(o["minVersion"]);
  387. }
  388. }
  389. };
  390. template<> Asset as(const Json::Value &o) { return o; }
  391. struct BufferView {
  392. std::size_t buffer;
  393. std::size_t byteLength;
  394. std::size_t byteOffset;
  395. std::optional<std::size_t> byteStride;
  396. std::optional<std::string> name;
  397. enum class Target {
  398. ARRAY_BUFFER,
  399. ELEMENT_ARRAY_BUFFER,
  400. };
  401. std::optional<Target> target;
  402. BufferView(const Json::Value &o)
  403. : buffer(as<std::size_t>(o["buffer"]))
  404. , byteLength(as<std::size_t>(o["byteLength"]))
  405. , byteOffset(0)
  406. {
  407. check(o.isObject());
  408. check(byteLength >= 1);
  409. if (o.isMember("byteOffset")) {
  410. byteOffset = as<std::size_t>(o["byteOffset"]);
  411. check(byteOffset >= 0);
  412. }
  413. if (o.isMember("byteStride")) {
  414. byteStride = as<std::size_t>(o["byteStride"]);
  415. check(byteStride.value() >= 4);
  416. check(byteStride.value() <= 252);
  417. check(byteStride.value() % 4 == 0);
  418. }
  419. if (o.isMember("name")) {
  420. name = as<std::string>(o["name"]);
  421. }
  422. if (o.isMember("target")) {
  423. static std::unordered_map<Json::UInt64, Target> map = {
  424. {34962, Target::ARRAY_BUFFER},
  425. {34963, Target::ELEMENT_ARRAY_BUFFER},
  426. };
  427. const auto &v = o["target"]; check(v.isUInt64());
  428. target = map.at(v.asUInt64());
  429. }
  430. }
  431. };
  432. template<> BufferView as(const Json::Value &o) { return o; }
  433. struct Buffer {
  434. std::size_t byteLength;
  435. std::optional<std::string> name;
  436. std::string data;
  437. Buffer(const Json::Value &o,
  438. const std::function<std::string(const std::string &uri)> &resolveURI)
  439. : byteLength(as<std::size_t>(o["byteLength"]))
  440. {
  441. check(o.isObject());
  442. check(byteLength >= 1);
  443. if (o.isMember("name")) {
  444. name = as<std::string>(o["name"]);
  445. }
  446. check(o.isMember("uri"));
  447. bool dataURI = false;
  448. const std::string uri = as<std::string>(o["uri"]);
  449. for (auto &prefix : std::array<std::string, 2> {
  450. "data:application/octet-stream;base64,",
  451. "data:application/gltf-buffer;base64,"
  452. }) {
  453. if (std::string_view(uri).substr(0, prefix.length()) == prefix) {
  454. auto view = std::string_view(uri).substr(prefix.length());
  455. check(base64_is_valid(view));
  456. data = base64_decode(view);
  457. dataURI = true;
  458. break;
  459. }
  460. }
  461. if (!dataURI)
  462. data = resolveURI(uri);
  463. check(data.size() >= byteLength);
  464. data.resize(byteLength);
  465. }
  466. };
  467. struct CameraOrthographic {
  468. double xmag;
  469. double ymag;
  470. double zfar;
  471. double znear;
  472. CameraOrthographic(const Json::Value &o)
  473. : xmag(as<double>(o["xmag"]))
  474. , ymag(as<double>(o["ymag"]))
  475. , zfar(as<double>(o["zfar"]))
  476. , znear(as<double>(o["znear"]))
  477. {
  478. check(o.isObject());
  479. check(zfar > 0);
  480. check(znear >= 0);
  481. }
  482. };
  483. template<> CameraOrthographic as(const Json::Value &o) { return o; }
  484. struct CameraPerspective {
  485. std::optional<double> aspectRatio;
  486. double yfov;
  487. std::optional<double> zfar;
  488. double znear;
  489. CameraPerspective(const Json::Value &o)
  490. : yfov(as<double>(o["yfov"]))
  491. , znear(as<double>(o["znear"]))
  492. {
  493. check(o.isObject());
  494. if (o.isMember("aspectRatio")) {
  495. aspectRatio = as<double>(o["aspectRatio"]);
  496. check(aspectRatio.value() > 0);
  497. }
  498. check(yfov > 0);
  499. if (o.isMember("zfar")) {
  500. zfar = as<double>(o["zfar"]);
  501. check(zfar.value() > 0);
  502. }
  503. check(znear > 0);
  504. }
  505. };
  506. template<> CameraPerspective as(const Json::Value &o) { return o; }
  507. struct Camera {
  508. std::optional<std::string> name;
  509. std::optional<CameraOrthographic> orthographic;
  510. std::optional<CameraPerspective> perspective;
  511. enum class Type {
  512. ORTHOGRAPHIC,
  513. PERSPECTIVE,
  514. };
  515. Type type;
  516. Camera(const Json::Value &o)
  517. {
  518. check(o.isObject());
  519. if (o.isMember("name")) {
  520. name = as<std::string>(o["name"]);
  521. }
  522. if (o.isMember("orthographic")) {
  523. orthographic = as<CameraOrthographic>(o["orthographic"]);
  524. }
  525. if (o.isMember("perspective")) {
  526. perspective = as<CameraPerspective>(o["perspective"]);
  527. }
  528. {
  529. static std::unordered_map<Json::String, Type> map = {
  530. {"orthographic", Type::ORTHOGRAPHIC},
  531. {"perspective", Type::PERSPECTIVE},
  532. };
  533. const auto &v = o["type"]; check(v.isString());
  534. type = map.at(v.asString());
  535. }
  536. }
  537. };
  538. template<> Camera as(const Json::Value &o) { return o; }
  539. struct Image {
  540. std::optional<std::size_t> bufferView;
  541. enum class MimeType {
  542. IMAGE_JPEG,
  543. IMAGE_PNG,
  544. };
  545. std::optional<MimeType> mimeType;
  546. std::optional<std::string> name;
  547. std::optional<std::string> uri;
  548. Image(const Json::Value &o)
  549. {
  550. check(o.isObject());
  551. if (o.isMember("bufferView")) {
  552. bufferView = as<std::size_t>(o["bufferView"]);
  553. }
  554. if (o.isMember("mimeType")) {
  555. static std::unordered_map<Json::String, MimeType> map = {
  556. {"image/jpeg", MimeType::IMAGE_JPEG},
  557. {"image/png", MimeType::IMAGE_PNG},
  558. };
  559. const auto &v = o["mimeType"]; check(v.isString());
  560. mimeType = map.at(v.asString());
  561. }
  562. if (o.isMember("name")) {
  563. name = as<std::string>(o["name"]);
  564. }
  565. if (o.isMember("uri")) {
  566. uri = as<std::string>(o["uri"]);
  567. }
  568. }
  569. };
  570. template<> Image as(const Json::Value &o) { return o; }
  571. struct TextureInfo {
  572. std::size_t index;
  573. std::size_t texCoord;
  574. TextureInfo(const Json::Value &o)
  575. : index(as<std::size_t>(o["index"]))
  576. , texCoord(0)
  577. {
  578. check(o.isObject());
  579. if (o.isMember("texCoord")) {
  580. texCoord = as<std::size_t>(o["texCoord"]);
  581. check(texCoord >= 0);
  582. }
  583. }
  584. };
  585. template<> TextureInfo as(const Json::Value &o) { return o; }
  586. struct MaterialNormalTextureInfo {
  587. std::size_t index;
  588. double scale;
  589. std::size_t texCoord;
  590. MaterialNormalTextureInfo(const Json::Value &o)
  591. : index(as<std::size_t>(o["index"]))
  592. , scale(1)
  593. , texCoord(0)
  594. {
  595. check(o.isObject());
  596. if (o.isMember("scale")) {
  597. scale = as<double>(o["scale"]);
  598. }
  599. if (o.isMember("texCoord")) {
  600. texCoord = as<std::size_t>(o["texCoord"]);
  601. }
  602. }
  603. };
  604. template<> MaterialNormalTextureInfo as(const Json::Value &o) { return o; }
  605. struct MaterialOcclusionTextureInfo {
  606. std::size_t index;
  607. double strength;
  608. std::size_t texCoord;
  609. MaterialOcclusionTextureInfo(const Json::Value &o)
  610. : index(as<std::size_t>(o["index"]))
  611. , strength(1)
  612. , texCoord(0)
  613. {
  614. check(o.isObject());
  615. if (o.isMember("strength")) {
  616. strength = as<double>(o["strength"]);
  617. check(strength >= 0);
  618. check(strength <= 1);
  619. }
  620. if (o.isMember("texCoord")) {
  621. texCoord = as<std::size_t>(o["texCoord"]);
  622. }
  623. }
  624. };
  625. template<> MaterialOcclusionTextureInfo as(const Json::Value &o) { return o; }
  626. struct MaterialPbrMetallicRoughness {
  627. std::array<double, 4> baseColorFactor;
  628. std::optional<TextureInfo> baseColorTexture;
  629. double metallicFactor;
  630. std::optional<TextureInfo> metallicRoughnessTexture;
  631. double roughnessFactor;
  632. MaterialPbrMetallicRoughness(const Json::Value &o)
  633. : baseColorFactor{1, 1, 1, 1}
  634. , metallicFactor(1)
  635. , roughnessFactor(1)
  636. {
  637. check(o.isObject());
  638. if (o.isMember("baseColorFactor")) {
  639. baseColorFactor = asArr<double, 4>(o["baseColorFactor"]);
  640. for (auto v: baseColorFactor) {
  641. check(v >= 0);
  642. check(v <= 1);
  643. }
  644. }
  645. if (o.isMember("baseColorTexture")) {
  646. baseColorTexture = as<TextureInfo>(o["baseColorTexture"]);
  647. }
  648. if (o.isMember("metallicFactor")) {
  649. metallicFactor = as<double>(o["metallicFactor"]);
  650. check(metallicFactor >= 0);
  651. check(metallicFactor <= 1);
  652. }
  653. if (o.isMember("metallicRoughnessTexture")) {
  654. metallicRoughnessTexture = as<TextureInfo>(o["metallicRoughnessTexture"]);
  655. }
  656. if (o.isMember("roughnessFactor")) {
  657. roughnessFactor = as<double>(o["roughnessFactor"]);
  658. check(roughnessFactor >= 0);
  659. check(roughnessFactor <= 1);
  660. }
  661. }
  662. };
  663. template<> MaterialPbrMetallicRoughness as(const Json::Value &o) { return o; }
  664. struct Material {
  665. double alphaCutoff;
  666. enum class AlphaMode {
  667. BLEND,
  668. MASK,
  669. OPAQUE,
  670. };
  671. AlphaMode alphaMode;
  672. bool doubleSided;
  673. std::array<double, 3> emissiveFactor;
  674. std::optional<TextureInfo> emissiveTexture;
  675. std::optional<std::string> name;
  676. std::optional<MaterialNormalTextureInfo> normalTexture;
  677. std::optional<MaterialOcclusionTextureInfo> occlusionTexture;
  678. std::optional<MaterialPbrMetallicRoughness> pbrMetallicRoughness;
  679. Material(const Json::Value &o)
  680. : alphaCutoff(0.5)
  681. , alphaMode(AlphaMode::OPAQUE)
  682. , doubleSided(false)
  683. , emissiveFactor{0, 0, 0}
  684. {
  685. check(o.isObject());
  686. if (o.isMember("alphaCutoff")) {
  687. alphaCutoff = as<double>(o["alphaCutoff"]);
  688. check(alphaCutoff >= 0);
  689. }
  690. if (o.isMember("alphaMode")){
  691. static std::unordered_map<Json::String, AlphaMode> map = {
  692. {"BLEND", AlphaMode::BLEND},
  693. {"MASK", AlphaMode::MASK},
  694. {"OPAQUE", AlphaMode::OPAQUE},
  695. };
  696. const auto &v = o["alphaMode"]; check(v.isString());
  697. alphaMode = map.at(v.asString());
  698. }
  699. if (o.isMember("doubleSided")) {
  700. doubleSided = as<bool>(o["doubleSided"]);
  701. }
  702. if (o.isMember("emissiveFactor")) {
  703. emissiveFactor = asArr<double, 3>(o["emissiveFactor"]);
  704. for (const auto &v: emissiveFactor) {
  705. check(v >= 0);
  706. check(v <= 1);
  707. }
  708. }
  709. if (o.isMember("emissiveTexture")) {
  710. emissiveTexture = as<TextureInfo>(o["emissiveTexture"]);
  711. }
  712. if (o.isMember("name")) {
  713. name = as<std::string>(o["name"]);
  714. }
  715. if (o.isMember("normalTexture")) {
  716. normalTexture = as<MaterialNormalTextureInfo>(o["normalTexture"]);
  717. }
  718. if (o.isMember("occlusionTexture")) {
  719. occlusionTexture = as<MaterialOcclusionTextureInfo>(o["occlusionTexture"]);
  720. }
  721. if (o.isMember("pbrMetallicRoughness")) {
  722. pbrMetallicRoughness = as<MaterialPbrMetallicRoughness>(o["pbrMetallicRoughness"]);
  723. }
  724. }
  725. };
  726. template<> Material as(const Json::Value &o) { return o; }
  727. struct MeshPrimitive {
  728. static void enumeratedProps(const Json::Value &o, const std::string &name, std::optional<std::vector<std::size_t>> &attr) {
  729. for (std::size_t i = 0;; ++i) {
  730. const std::string s = name + "_" + std::to_string(i);
  731. if (!o.isMember(s)) break;
  732. if (i == 0) {
  733. attr = std::vector<std::size_t>();
  734. }
  735. attr->push_back(as<std::size_t>(o[s]));
  736. }
  737. }
  738. struct Attributes {
  739. std::optional<std::size_t> position, normal, tangent;
  740. std::optional<std::vector<std::size_t>> texcoord, color, joints, weights;
  741. Attributes(const Json::Value &o) {
  742. if (o.isMember("POSITION"))
  743. position = as<std::size_t>(o["POSITION"]);
  744. if (o.isMember("NORMAL"))
  745. normal = as<std::size_t>(o["NORMAL"]);
  746. if (o.isMember("TANGENT"))
  747. tangent = as<std::size_t>(o["TANGENT"]);
  748. enumeratedProps(o, "TEXCOORD", texcoord);
  749. enumeratedProps(o, "COLOR", color);
  750. enumeratedProps(o, "JOINTS", joints);
  751. enumeratedProps(o, "WEIGHTS", weights);
  752. check(joints.has_value() == weights.has_value());
  753. if (joints.has_value()) {
  754. check(joints->size() == weights->size());
  755. }
  756. check(position.has_value()
  757. || normal.has_value()
  758. || tangent.has_value()
  759. || texcoord.has_value()
  760. || color.has_value()
  761. || joints.has_value()
  762. || weights.has_value());
  763. }
  764. };
  765. Attributes attributes;
  766. std::optional<std::size_t> indices;
  767. std::optional<std::size_t> material;
  768. enum class Mode {
  769. POINTS,
  770. LINES,
  771. LINE_LOOP,
  772. LINE_STRIP,
  773. TRIANGLES,
  774. TRIANGLE_STRIP,
  775. TRIANGLE_FAN,
  776. };
  777. Mode mode;
  778. struct MorphTargets {
  779. std::optional<std::size_t> position, normal, tangent;
  780. std::optional<std::vector<std::size_t>> texcoord, color;
  781. MorphTargets(const Json::Value &o) {
  782. if (o.isMember("POSITION"))
  783. position = as<std::size_t>(o["POSITION"]);
  784. if (o.isMember("NORMAL"))
  785. normal = as<std::size_t>(o["NORMAL"]);
  786. if (o.isMember("TANGENT"))
  787. tangent = as<std::size_t>(o["TANGENT"]);
  788. enumeratedProps(o, "TEXCOORD", texcoord);
  789. enumeratedProps(o, "COLOR", color);
  790. check(position.has_value()
  791. || normal.has_value()
  792. || tangent.has_value()
  793. || texcoord.has_value()
  794. || color.has_value());
  795. }
  796. };
  797. std::optional<std::vector<MorphTargets>> targets;
  798. MeshPrimitive(const Json::Value &o)
  799. : attributes(Attributes(o["attributes"]))
  800. , mode(Mode::TRIANGLES)
  801. {
  802. check(o.isObject());
  803. if (o.isMember("indices")) {
  804. indices = as<std::size_t>(o["indices"]);
  805. }
  806. if (o.isMember("material")) {
  807. material = as<std::size_t>(o["material"]);
  808. }
  809. if (o.isMember("mode")) {
  810. static std::unordered_map<Json::UInt64, Mode> map = {
  811. {0, Mode::POINTS},
  812. {1, Mode::LINES},
  813. {2, Mode::LINE_LOOP},
  814. {3, Mode::LINE_STRIP},
  815. {4, Mode::TRIANGLES},
  816. {5, Mode::TRIANGLE_STRIP},
  817. {6, Mode::TRIANGLE_FAN},
  818. };
  819. const auto &v = o["mode"]; check(v.isUInt64());
  820. mode = map.at(v.asUInt64());
  821. }
  822. if (o.isMember("targets")) {
  823. targets = asVec<MorphTargets>(o["targets"]);
  824. check(targets->size() >= 1);
  825. }
  826. }
  827. };
  828. template<> MeshPrimitive::MorphTargets as(const Json::Value &o) { return o; }
  829. template<> MeshPrimitive as(const Json::Value &o) { return o; }
  830. struct Mesh {
  831. std::optional<std::string> name;
  832. std::vector<MeshPrimitive> primitives;
  833. std::optional<std::vector<double>> weights;
  834. Mesh(const Json::Value &o)
  835. : primitives(asVec<MeshPrimitive>(o["primitives"]))
  836. {
  837. check(o.isObject());
  838. if (o.isMember("name")) {
  839. name = as<std::string>(o["name"]);
  840. }
  841. check(primitives.size() >= 1);
  842. if (o.isMember("weights")) {
  843. weights = asVec<double>(o["weights"]);
  844. check(weights->size() >= 1);
  845. }
  846. }
  847. };
  848. template<> Mesh as(const Json::Value &o) { return o; }
  849. struct Node {
  850. std::optional<std::size_t> camera;
  851. std::optional<std::vector<std::size_t>> children;
  852. typedef std::array<double, 16> Matrix;
  853. struct TRS {
  854. std::array<double, 3> translation = {0, 0, 0};
  855. std::array<double, 4> rotation = {0, 0, 0, 1};
  856. std::array<double, 3> scale = {1, 1, 1};
  857. };
  858. std::variant<Matrix, TRS> transform;
  859. std::optional<std::size_t> mesh;
  860. std::optional<std::string> name;
  861. std::optional<std::size_t> skin;
  862. std::optional<std::vector<double>> weights;
  863. Node(const Json::Value &o)
  864. : transform(Matrix {
  865. 1, 0, 0, 0,
  866. 0, 1, 0, 0,
  867. 0, 0, 1, 0,
  868. 0, 0, 0, 1
  869. })
  870. {
  871. check(o.isObject());
  872. if (o.isMember("camera")) {
  873. camera = as<std::size_t>(o["camera"]);
  874. }
  875. if (o.isMember("children")) {
  876. children = asVec<std::size_t>(o["children"]);
  877. check(children->size() >= 1);
  878. checkDuplicateFree(*children);
  879. }
  880. bool hasTRS = o.isMember("translation") || o.isMember("rotation") || o.isMember("scale");
  881. if (o.isMember("matrix")) {
  882. check(!hasTRS);
  883. transform = asArr<double, 16>(o["matrix"]);
  884. } else if (hasTRS) {
  885. TRS trs;
  886. if (o.isMember("translation")) {
  887. trs.translation = asArr<double, 3>(o["translation"]);
  888. }
  889. if (o.isMember("rotation")) {
  890. trs.rotation = asArr<double, 4>(o["rotation"]);
  891. for (auto v: trs.rotation) {
  892. check(v >= -1);
  893. check(v <= 1);
  894. }
  895. }
  896. if (o.isMember("scale")) {
  897. trs.scale = asArr<double, 3>(o["scale"]);
  898. }
  899. transform = trs;
  900. }
  901. if (o.isMember("mesh")) {
  902. mesh = as<std::size_t>(o["mesh"]);
  903. }
  904. if (o.isMember("name")) {
  905. name = as<std::string>(o["name"]);
  906. }
  907. if (o.isMember("skin")) {
  908. check(mesh.has_value());
  909. skin = as<std::size_t>(o["skin"]);
  910. }
  911. if (o.isMember("weights")) {
  912. weights = asVec<double>(o["weights"]);
  913. check(weights->size() >= 1);
  914. }
  915. }
  916. };
  917. template<> Node as(const Json::Value &o) { return o; }
  918. struct Sampler {
  919. enum class MagFilter {
  920. NEAREST,
  921. LINEAR,
  922. };
  923. std::optional<MagFilter> magFilter;
  924. enum class MinFilter {
  925. NEAREST,
  926. LINEAR,
  927. NEAREST_MIPMAP_NEAREST,
  928. LINEAR_MIPMAP_NEAREST,
  929. NEAREST_MIPMAP_LINEAR,
  930. LINEAR_MIPMAP_LINEAR,
  931. };
  932. std::optional<MinFilter> minFilter;
  933. std::optional<std::string> name;
  934. enum class WrapS {
  935. REPEAT,
  936. CLAMP_TO_EDGE,
  937. MIRRORED_REPEAT,
  938. };
  939. WrapS wrapS;
  940. enum class WrapT {
  941. REPEAT,
  942. CLAMP_TO_EDGE,
  943. MIRRORED_REPEAT,
  944. };
  945. WrapT wrapT;
  946. Sampler(const Json::Value &o)
  947. : wrapS(WrapS::REPEAT)
  948. , wrapT(WrapT::REPEAT)
  949. {
  950. check(o.isObject());
  951. if (o.isMember("magFilter")) {
  952. static std::unordered_map<Json::UInt64, MagFilter> map = {
  953. {9728, MagFilter::NEAREST},
  954. {9729, MagFilter::LINEAR},
  955. };
  956. const auto &v = o["magFilter"]; check(v.isUInt64());
  957. magFilter = map.at(v.asUInt64());
  958. }
  959. if (o.isMember("minFilter")) {
  960. static std::unordered_map<Json::UInt64, MinFilter> map = {
  961. {9728, MinFilter::NEAREST},
  962. {9729, MinFilter::LINEAR},
  963. {9984, MinFilter::NEAREST_MIPMAP_NEAREST},
  964. {9985, MinFilter::LINEAR_MIPMAP_NEAREST},
  965. {9986, MinFilter::NEAREST_MIPMAP_LINEAR},
  966. {9987, MinFilter::LINEAR_MIPMAP_LINEAR},
  967. };
  968. const auto &v = o["minFilter"]; check(v.isUInt64());
  969. minFilter = map.at(v.asUInt64());
  970. }
  971. if (o.isMember("name")) {
  972. name = as<std::string>(o["name"]);
  973. }
  974. if (o.isMember("wrapS")) {
  975. static std::unordered_map<Json::UInt64, WrapS> map = {
  976. {10497, WrapS::REPEAT},
  977. {33071, WrapS::CLAMP_TO_EDGE},
  978. {33648, WrapS::MIRRORED_REPEAT},
  979. };
  980. const auto &v = o["wrapS"]; check(v.isUInt64());
  981. wrapS = map.at(v.asUInt64());
  982. }
  983. if (o.isMember("wrapT")) {
  984. static std::unordered_map<Json::UInt64, WrapT> map = {
  985. {10497, WrapT::REPEAT},
  986. {33071, WrapT::CLAMP_TO_EDGE},
  987. {33648, WrapT::MIRRORED_REPEAT},
  988. };
  989. const auto &v = o["wrapT"]; check(v.isUInt64());
  990. wrapT = map.at(v.asUInt64());
  991. }
  992. }
  993. };
  994. template<> Sampler as(const Json::Value &o) { return o; }
  995. struct Scene {
  996. std::optional<std::string> name;
  997. std::optional<std::vector<std::size_t>> nodes;
  998. Scene(const Json::Value &o)
  999. {
  1000. check(o.isObject());
  1001. if (o.isMember("name")) {
  1002. name = as<std::string>(o["name"]);
  1003. }
  1004. if (o.isMember("nodes")) {
  1005. nodes = asVec<std::size_t>(o["nodes"]);
  1006. check(nodes->size() >= 1);
  1007. checkDuplicateFree(*nodes);
  1008. }
  1009. }
  1010. };
  1011. template<> Scene as(const Json::Value &o) { return o; }
  1012. struct Skin {
  1013. std::optional<std::size_t> inverseBindMatrices;
  1014. std::vector<std::size_t> joints;
  1015. std::optional<std::string> name;
  1016. std::optional<std::size_t> skeleton;
  1017. Skin(const Json::Value &o)
  1018. : joints(asVec<std::size_t>(o["joints"]))
  1019. {
  1020. check(o.isObject());
  1021. if (o.isMember("inverseBindMatrices")) {
  1022. inverseBindMatrices = as<std::size_t>(o["inverseBindMatrices"]);
  1023. }
  1024. check(joints.size() >= 1);
  1025. checkDuplicateFree(joints);
  1026. if (o.isMember("name")) {
  1027. name = as<std::string>(o["name"]);
  1028. }
  1029. if (o.isMember("skeleton")) {
  1030. skeleton = as<std::size_t>(o["skeleton"]);
  1031. }
  1032. }
  1033. };
  1034. template<> Skin as(const Json::Value &o) { return o; }
  1035. struct Texture {
  1036. std::optional<std::string> name;
  1037. std::optional<std::size_t> sampler;
  1038. std::optional<std::size_t> source;
  1039. Texture(const Json::Value &o)
  1040. {
  1041. check(o.isObject());
  1042. if (o.isMember("name")) {
  1043. name = as<std::string>(o["name"]);
  1044. }
  1045. if (o.isMember("sampler")) {
  1046. sampler = as<std::size_t>(o["sampler"]);
  1047. }
  1048. if (o.isMember("source")) {
  1049. source = as<std::size_t>(o["source"]);
  1050. }
  1051. }
  1052. };
  1053. template<> Texture as(const Json::Value &o) { return o; }
  1054. struct GlTF {
  1055. std::optional<std::vector<Accessor>> accessors;
  1056. std::optional<std::vector<Animation>> animations;
  1057. Asset asset;
  1058. std::optional<std::vector<BufferView>> bufferViews;
  1059. std::optional<std::vector<Buffer>> buffers;
  1060. std::optional<std::vector<Camera>> cameras;
  1061. std::optional<std::vector<std::string>> extensionsRequired;
  1062. std::optional<std::vector<std::string>> extensionsUsed;
  1063. std::optional<std::vector<Image>> images;
  1064. std::optional<std::vector<Material>> materials;
  1065. std::optional<std::vector<Mesh>> meshes;
  1066. std::optional<std::vector<Node>> nodes;
  1067. std::optional<std::vector<Sampler>> samplers;
  1068. std::optional<std::size_t> scene;
  1069. std::optional<std::vector<Scene>> scenes;
  1070. std::optional<std::vector<Skin>> skins;
  1071. std::optional<std::vector<Texture>> textures;
  1072. static std::string uriError(const std::string &uri) {
  1073. // only base64 data URI support by default
  1074. throw std::runtime_error("unsupported URI: " + uri);
  1075. }
  1076. GlTF(const Json::Value &o,
  1077. const std::function<std::string(const std::string &uri)> &resolveURI = uriError)
  1078. : asset(as<Asset>(o["asset"]))
  1079. {
  1080. check(o.isObject());
  1081. if (o.isMember("accessors")) {
  1082. accessors = asVec<Accessor>(o["accessors"]);
  1083. check(accessors->size() >= 1);
  1084. }
  1085. if (o.isMember("animations")) {
  1086. animations = asVec<Animation>(o["animations"]);
  1087. check(animations->size() >= 1);
  1088. }
  1089. if (o.isMember("bufferViews")) {
  1090. bufferViews = asVec<BufferView>(o["bufferViews"]);
  1091. check(bufferViews->size() >= 1);
  1092. }
  1093. if (o.isMember("buffers")) {
  1094. auto b = o["buffers"];
  1095. check(b.isArray());
  1096. std::vector<Buffer> bufs;
  1097. bufs.reserve(b.size());
  1098. for (Json::ArrayIndex i = 0; i < b.size(); ++i) {
  1099. bufs.emplace_back(b[i], resolveURI);
  1100. }
  1101. check(bufs.size() >= 1);
  1102. buffers = std::move(bufs);
  1103. }
  1104. if (o.isMember("cameras")) {
  1105. cameras = asVec<Camera>(o["cameras"]);
  1106. check(cameras->size() >= 1);
  1107. }
  1108. if (o.isMember("extensionsRequired")) {
  1109. extensionsRequired = asVec<std::string>(o["extensionsRequired"]);
  1110. check(extensionsRequired->size() >= 1);
  1111. checkDuplicateFree(*extensionsRequired);
  1112. }
  1113. if (o.isMember("extensionsUsed")) {
  1114. extensionsUsed = asVec<std::string>(o["extensionsUsed"]);
  1115. check(extensionsUsed->size() >= 1);
  1116. checkDuplicateFree(*extensionsUsed);
  1117. }
  1118. if (o.isMember("images")) {
  1119. images = asVec<Image>(o["images"]);
  1120. check(images->size() >= 1);
  1121. }
  1122. if (o.isMember("materials")) {
  1123. materials = asVec<Material>(o["materials"]);
  1124. check(materials->size() >= 1);
  1125. }
  1126. if (o.isMember("meshes")) {
  1127. meshes = asVec<Mesh>(o["meshes"]);
  1128. check(meshes->size() >= 1);
  1129. }
  1130. if (o.isMember("nodes")) {
  1131. nodes = asVec<Node>(o["nodes"]);
  1132. check(nodes->size() >= 1);
  1133. // Nodes must be a forest:
  1134. // 1. Each node should have indegree 0 or 1:
  1135. std::vector<std::size_t> indeg(nodes->size());
  1136. for (std::size_t i = 0; i < nodes->size(); ++i) {
  1137. auto children = nodes->at(i).children;
  1138. if (!children.has_value()) continue;
  1139. for (auto child : children.value()) {
  1140. ++indeg.at(child);
  1141. }
  1142. }
  1143. for (const auto deg : indeg) {
  1144. check(deg <= 1);
  1145. }
  1146. // 2. There should be no cycles:
  1147. std::vector<bool> visited(nodes->size());
  1148. std::stack<std::size_t, std::vector<std::size_t>> toVisit;
  1149. for (std::size_t i = 0; i < nodes->size(); ++i) {
  1150. // Only start DFS in roots.
  1151. if (indeg[i] > 0)
  1152. continue;
  1153. toVisit.push(i);
  1154. do {
  1155. std::size_t j = toVisit.top();
  1156. check(!visited.at(j));
  1157. visited[j] = true;
  1158. toVisit.pop();
  1159. auto children = nodes->at(j).children;
  1160. if (!children.has_value())
  1161. continue;
  1162. for (auto child : *children) {
  1163. toVisit.push(child);
  1164. }
  1165. } while (!toVisit.empty());
  1166. }
  1167. }
  1168. if (o.isMember("samplers")) {
  1169. samplers = asVec<Sampler>(o["samplers"]);
  1170. check(samplers->size() >= 1);
  1171. }
  1172. if (o.isMember("scene")) {
  1173. scene = as<std::size_t>(o["scene"]);
  1174. }
  1175. if (o.isMember("scenes")) {
  1176. scenes = asVec<Scene>(o["scenes"]);
  1177. check(scenes->size() >= 1);
  1178. }
  1179. if (o.isMember("skins")) {
  1180. skins = asVec<Skin>(o["skins"]);
  1181. check(skins->size() >= 1);
  1182. }
  1183. if (o.isMember("textures")) {
  1184. textures = asVec<Texture>(o["textures"]);
  1185. check(textures->size() >= 1);
  1186. }
  1187. // Validation
  1188. checkForall(bufferViews, [&](const BufferView &view) {
  1189. check(buffers.has_value());
  1190. const Buffer &buf = buffers->at(view.buffer);
  1191. // Be careful because of possible integer overflows.
  1192. check(view.byteOffset < buf.byteLength);
  1193. check(view.byteLength <= buf.byteLength);
  1194. check(view.byteOffset <= buf.byteLength - view.byteLength);
  1195. });
  1196. const auto checkAccessor = [&](const auto &accessor,
  1197. std::size_t bufferView, std::size_t byteOffset, std::size_t count) {
  1198. const BufferView &view = bufferViews->at(bufferView);
  1199. if (view.byteStride.has_value())
  1200. check(*view.byteStride % accessor.componentSize() == 0);
  1201. check(byteOffset < view.byteLength);
  1202. // Use division to avoid overflows.
  1203. const auto effective_byte_stride = view.byteStride.value_or(accessor.elementSize());
  1204. check(count <= (view.byteLength - byteOffset) / effective_byte_stride);
  1205. };
  1206. checkForall(accessors, [&](const Accessor &accessor) {
  1207. if (accessor.bufferView.has_value())
  1208. checkAccessor(accessor, *accessor.bufferView, accessor.byteOffset, accessor.count);
  1209. if (accessor.sparse.has_value()) {
  1210. const auto &indices = accessor.sparse->indices;
  1211. checkAccessor(indices, indices.bufferView, indices.byteOffset, accessor.sparse->count);
  1212. const auto &values = accessor.sparse->values;
  1213. checkAccessor(accessor, values.bufferView, values.byteOffset, accessor.sparse->count);
  1214. }
  1215. });
  1216. checkForall(images, [&](const Image &image) {
  1217. checkIndex(bufferViews, image.bufferView);
  1218. });
  1219. checkForall(meshes, [&](const Mesh &mesh) {
  1220. for (const auto &primitive : mesh.primitives) {
  1221. checkIndex(accessors, primitive.indices);
  1222. checkIndex(materials, primitive.material);
  1223. checkIndex(accessors, primitive.attributes.normal);
  1224. checkIndex(accessors, primitive.attributes.position);
  1225. checkIndex(accessors, primitive.attributes.tangent);
  1226. checkForall(primitive.attributes.texcoord, [&](const std::size_t &i) {
  1227. checkIndex(accessors, i);
  1228. });
  1229. checkForall(primitive.attributes.color, [&](const std::size_t &i) {
  1230. checkIndex(accessors, i);
  1231. });
  1232. checkForall(primitive.attributes.joints, [&](const std::size_t &i) {
  1233. checkIndex(accessors, i);
  1234. });
  1235. checkForall(primitive.attributes.weights, [&](const std::size_t &i) {
  1236. checkIndex(accessors, i);
  1237. });
  1238. if (primitive.material.has_value()) {
  1239. const Material &material = materials->at(primitive.material.value());
  1240. if (material.emissiveTexture.has_value()) {
  1241. check(primitive.attributes.texcoord.has_value());
  1242. check(material.emissiveTexture->texCoord < primitive.attributes.texcoord->size());
  1243. }
  1244. if (material.normalTexture.has_value()) {
  1245. check(primitive.attributes.texcoord.has_value());
  1246. check(material.normalTexture->texCoord < primitive.attributes.texcoord->size());
  1247. }
  1248. if (material.occlusionTexture.has_value()) {
  1249. check(primitive.attributes.texcoord.has_value());
  1250. check(material.occlusionTexture->texCoord < primitive.attributes.texcoord->size());
  1251. }
  1252. }
  1253. checkForall(primitive.targets, [&](const MeshPrimitive::MorphTargets &target) {
  1254. checkIndex(accessors, target.normal);
  1255. checkIndex(accessors, target.position);
  1256. checkIndex(accessors, target.tangent);
  1257. checkForall(target.texcoord, [&](const std::size_t &i) {
  1258. checkIndex(accessors, i);
  1259. });
  1260. checkForall(target.color, [&](const std::size_t &i) {
  1261. checkIndex(accessors, i);
  1262. });
  1263. });
  1264. }
  1265. });
  1266. checkForall(nodes, [&](const Node &node) {
  1267. checkIndex(cameras, node.camera);
  1268. checkIndex(meshes, node.mesh);
  1269. checkIndex(skins, node.skin);
  1270. });
  1271. checkForall(scenes, [&](const Scene &scene) {
  1272. checkForall(scene.nodes, [&](const size_t &i) {
  1273. checkIndex(nodes, i);
  1274. });
  1275. });
  1276. checkForall(skins, [&](const Skin &skin) {
  1277. checkIndex(accessors, skin.inverseBindMatrices);
  1278. for (const std::size_t &i : skin.joints)
  1279. checkIndex(nodes, i);
  1280. checkIndex(nodes, skin.skeleton);
  1281. });
  1282. checkForall(textures, [&](const Texture &texture) {
  1283. checkIndex(samplers, texture.sampler);
  1284. checkIndex(images, texture.source);
  1285. });
  1286. checkForall(animations, [&](const Animation &animation) {
  1287. for (const auto &sampler : animation.samplers) {
  1288. checkIndex(accessors, sampler.input);
  1289. const auto &accessor = accessors->at(sampler.input);
  1290. check(accessor.type == Accessor::Type::SCALAR);
  1291. check(accessor.componentType == Accessor::ComponentType::FLOAT);
  1292. checkIndex(accessors, sampler.output);
  1293. }
  1294. for (const auto &channel : animation.channels) {
  1295. checkIndex(nodes, channel.target.node);
  1296. checkIndex(animation.samplers, channel.sampler);
  1297. }
  1298. });
  1299. checkIndex(scenes, scene);
  1300. }
  1301. };
  1302. }