glTF2Asset.inl 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199
  1. /*
  2. Open Asset Import Library (assimp)
  3. ----------------------------------------------------------------------
  4. Copyright (c) 2006-2021, assimp team
  5. All rights reserved.
  6. Redistribution and use of this software in source and binary forms,
  7. with or without modification, are permitted provided that the
  8. following conditions are met:
  9. * Redistributions of source code must retain the above
  10. copyright notice, this list of conditions and the
  11. following disclaimer.
  12. * Redistributions in binary form must reproduce the above
  13. copyright notice, this list of conditions and the
  14. following disclaimer in the documentation and/or other
  15. materials provided with the distribution.
  16. * Neither the name of the assimp team, nor the names of its
  17. contributors may be used to endorse or promote products
  18. derived from this software without specific prior
  19. written permission of the assimp team.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. ----------------------------------------------------------------------
  32. */
  33. #include "AssetLib/glTF/glTFCommon.h"
  34. #include <assimp/MemoryIOWrapper.h>
  35. #include <assimp/StringUtils.h>
  36. #include <assimp/DefaultLogger.hpp>
  37. #ifdef ASSIMP_ENABLE_DRACO
  38. // Google draco library headers spew many warnings. Bad Google, no cookie
  39. #if _MSC_VER
  40. #pragma warning(push)
  41. #pragma warning(disable : 4018) // Signed/unsigned mismatch
  42. #pragma warning(disable : 4804) // Unsafe use of type 'bool'
  43. #elif defined(__clang__)
  44. #pragma clang diagnostic push
  45. #pragma clang diagnostic ignored "-Wsign-compare"
  46. #elif defined(__GNUC__)
  47. #pragma GCC diagnostic push
  48. #if (__GNUC__ > 4)
  49. #pragma GCC diagnostic ignored "-Wbool-compare"
  50. #endif
  51. #pragma GCC diagnostic ignored "-Wsign-compare"
  52. #endif
  53. #include "draco/compression/decode.h"
  54. #include "draco/core/decoder_buffer.h"
  55. #if _MSC_VER
  56. #pragma warning(pop)
  57. #elif defined(__clang__)
  58. #pragma clang diagnostic pop
  59. #elif defined(__GNUC__)
  60. #pragma GCC diagnostic pop
  61. #endif
  62. #ifndef DRACO_MESH_COMPRESSION_SUPPORTED
  63. #error glTF: KHR_draco_mesh_compression: draco library must have DRACO_MESH_COMPRESSION_SUPPORTED
  64. #endif
  65. #endif
  66. using namespace Assimp;
  67. namespace glTF2 {
  68. namespace {
  69. //
  70. // JSON Value reading helpers
  71. //
  72. template <class T>
  73. struct ReadHelper {
  74. static bool Read(Value &val, T &out) {
  75. return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  76. }
  77. };
  78. template <>
  79. struct ReadHelper<bool> {
  80. static bool Read(Value &val, bool &out) {
  81. return val.IsBool() ? out = val.GetBool(), true : false;
  82. }
  83. };
  84. template <>
  85. struct ReadHelper<float> {
  86. static bool Read(Value &val, float &out) {
  87. return val.IsNumber() ? out = static_cast<float>(val.GetDouble()), true : false;
  88. }
  89. };
  90. template <unsigned int N>
  91. struct ReadHelper<float[N]> {
  92. static bool Read(Value &val, float (&out)[N]) {
  93. if (!val.IsArray() || val.Size() != N) return false;
  94. for (unsigned int i = 0; i < N; ++i) {
  95. if (val[i].IsNumber())
  96. out[i] = static_cast<float>(val[i].GetDouble());
  97. }
  98. return true;
  99. }
  100. };
  101. template <>
  102. struct ReadHelper<const char *> {
  103. static bool Read(Value &val, const char *&out) {
  104. return val.IsString() ? (out = val.GetString(), true) : false;
  105. }
  106. };
  107. template <>
  108. struct ReadHelper<std::string> {
  109. static bool Read(Value &val, std::string &out) {
  110. return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false;
  111. }
  112. };
  113. template <>
  114. struct ReadHelper<uint64_t> {
  115. static bool Read(Value &val, uint64_t &out) {
  116. return val.IsUint64() ? out = val.GetUint64(), true : false;
  117. }
  118. };
  119. template <>
  120. struct ReadHelper<int64_t> {
  121. static bool Read(Value &val, int64_t &out) {
  122. return val.IsInt64() ? out = val.GetInt64(), true : false;
  123. }
  124. };
  125. template <class T>
  126. struct ReadHelper<Nullable<T>> {
  127. static bool Read(Value &val, Nullable<T> &out) {
  128. return out.isPresent = ReadHelper<T>::Read(val, out.value);
  129. }
  130. };
  131. template <class T>
  132. inline static bool ReadValue(Value &val, T &out) {
  133. return ReadHelper<T>::Read(val, out);
  134. }
  135. template <class T>
  136. inline static bool ReadMember(Value &obj, const char *id, T &out) {
  137. if (!obj.IsObject()) {
  138. return false;
  139. }
  140. Value::MemberIterator it = obj.FindMember(id);
  141. if (it != obj.MemberEnd()) {
  142. return ReadHelper<T>::Read(it->value, out);
  143. }
  144. return false;
  145. }
  146. template <class T>
  147. inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) {
  148. T out;
  149. return ReadMember(obj, id, out) ? out : defaultValue;
  150. }
  151. inline Value *FindMember(Value &val, const char *id) {
  152. if (!val.IsObject()) {
  153. return nullptr;
  154. }
  155. Value::MemberIterator it = val.FindMember(id);
  156. return (it != val.MemberEnd()) ? &it->value : nullptr;
  157. }
  158. template<int N>
  159. inline void throwUnexpectedTypeError(const char (&expectedTypeName)[N], const char* memberId, const char* context, const char* extraContext) {
  160. std::string fullContext = context;
  161. if (extraContext && (strlen(extraContext) > 0))
  162. {
  163. fullContext = fullContext + " (" + extraContext + ")";
  164. }
  165. throw DeadlyImportError("Member \"", memberId, "\" was not of type \"", expectedTypeName, "\" when reading ", fullContext);
  166. }
  167. // Look-up functions with type checks. Context and extra context help the user identify the problem if there's an error.
  168. inline Value *FindStringInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
  169. if (!val.IsObject()) {
  170. return nullptr;
  171. }
  172. Value::MemberIterator it = val.FindMember(memberId);
  173. if (it == val.MemberEnd()) {
  174. return nullptr;
  175. }
  176. if (!it->value.IsString()) {
  177. throwUnexpectedTypeError("string", memberId, context, extraContext);
  178. }
  179. return &it->value;
  180. }
  181. inline Value *FindNumberInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
  182. if (!val.IsObject()) {
  183. return nullptr;
  184. }
  185. Value::MemberIterator it = val.FindMember(memberId);
  186. if (it == val.MemberEnd()) {
  187. return nullptr;
  188. }
  189. if (!it->value.IsNumber()) {
  190. throwUnexpectedTypeError("number", memberId, context, extraContext);
  191. }
  192. return &it->value;
  193. }
  194. inline Value *FindUIntInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
  195. if (!val.IsObject()) {
  196. return nullptr;
  197. }
  198. Value::MemberIterator it = val.FindMember(memberId);
  199. if (it == val.MemberEnd()) {
  200. return nullptr;
  201. }
  202. if (!it->value.IsUint()) {
  203. throwUnexpectedTypeError("uint", memberId, context, extraContext);
  204. }
  205. return &it->value;
  206. }
  207. inline Value *FindArrayInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
  208. if (!val.IsObject()) {
  209. return nullptr;
  210. }
  211. Value::MemberIterator it = val.FindMember(memberId);
  212. if (it == val.MemberEnd()) {
  213. return nullptr;
  214. }
  215. if (!it->value.IsArray()) {
  216. throwUnexpectedTypeError("array", memberId, context, extraContext);
  217. }
  218. return &it->value;
  219. }
  220. inline Value *FindObjectInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
  221. if (!val.IsObject()) {
  222. return nullptr;
  223. }
  224. Value::MemberIterator it = val.FindMember(memberId);
  225. if (it == val.MemberEnd()) {
  226. return nullptr;
  227. }
  228. if (!it->value.IsObject()) {
  229. throwUnexpectedTypeError("object", memberId, context, extraContext);
  230. }
  231. return &it->value;
  232. }
  233. inline Value *FindExtensionInContext(Value &val, const char *extensionId, const char* context, const char* extraContext = nullptr) {
  234. if (Value *extensionList = FindObjectInContext(val, "extensions", context, extraContext)) {
  235. if (Value *extension = FindObjectInContext(*extensionList, extensionId, context, extraContext)) {
  236. return extension;
  237. }
  238. }
  239. return nullptr;
  240. }
  241. // Overloads when the value is the document.
  242. inline Value *FindString(Document &doc, const char *memberId) {
  243. return FindStringInContext(doc, memberId, "the document");
  244. }
  245. inline Value *FindNumber(Document &doc, const char *memberId) {
  246. return FindNumberInContext(doc, memberId, "the document");
  247. }
  248. inline Value *FindUInt(Document &doc, const char *memberId) {
  249. return FindUIntInContext(doc, memberId, "the document");
  250. }
  251. inline Value *FindArray(Document &val, const char *memberId) {
  252. return FindArrayInContext(val, memberId, "the document");
  253. }
  254. inline Value *FindObject(Document &doc, const char *memberId) {
  255. return FindObjectInContext(doc, memberId, "the document");
  256. }
  257. inline Value *FindExtension(Value &val, const char *extensionId) {
  258. return FindExtensionInContext(val, extensionId, "the document");
  259. }
  260. inline CustomExtension ReadExtensions(const char *name, Value &obj) {
  261. CustomExtension ret;
  262. ret.name = name;
  263. if (obj.IsObject()) {
  264. ret.mValues.isPresent = true;
  265. for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
  266. auto &val = it->value;
  267. ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
  268. }
  269. } else if (obj.IsArray()) {
  270. ret.mValues.value.reserve(obj.Size());
  271. ret.mValues.isPresent = true;
  272. for (unsigned int i = 0; i < obj.Size(); ++i) {
  273. ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
  274. }
  275. } else if (obj.IsNumber()) {
  276. if (obj.IsUint64()) {
  277. ret.mUint64Value.value = obj.GetUint64();
  278. ret.mUint64Value.isPresent = true;
  279. } else if (obj.IsInt64()) {
  280. ret.mInt64Value.value = obj.GetInt64();
  281. ret.mInt64Value.isPresent = true;
  282. } else if (obj.IsDouble()) {
  283. ret.mDoubleValue.value = obj.GetDouble();
  284. ret.mDoubleValue.isPresent = true;
  285. }
  286. } else if (obj.IsString()) {
  287. ReadValue(obj, ret.mStringValue);
  288. ret.mStringValue.isPresent = true;
  289. } else if (obj.IsBool()) {
  290. ret.mBoolValue.value = obj.GetBool();
  291. ret.mBoolValue.isPresent = true;
  292. }
  293. return ret;
  294. }
  295. } // namespace
  296. inline Value *Object::FindString(Value &val, const char *memberId) {
  297. return FindStringInContext(val, memberId, id.c_str(), name.c_str());
  298. }
  299. inline Value *Object::FindNumber(Value &val, const char *memberId) {
  300. return FindNumberInContext(val, memberId, id.c_str(), name.c_str());
  301. }
  302. inline Value *Object::FindUInt(Value &val, const char *memberId) {
  303. return FindUIntInContext(val, memberId, id.c_str(), name.c_str());
  304. }
  305. inline Value *Object::FindArray(Value &val, const char *memberId) {
  306. return FindArrayInContext(val, memberId, id.c_str(), name.c_str());
  307. }
  308. inline Value *Object::FindObject(Value &val, const char *memberId) {
  309. return FindObjectInContext(val, memberId, id.c_str(), name.c_str());
  310. }
  311. inline Value *Object::FindExtension(Value &val, const char *extensionId) {
  312. return FindExtensionInContext(val, extensionId, id.c_str(), name.c_str());
  313. }
  314. inline void Object::ReadExtensions(Value &val) {
  315. if (Value *curExtensions = FindObject(val, "extensions")) {
  316. this->customExtensions = glTF2::ReadExtensions("extensions", *curExtensions);
  317. }
  318. }
  319. inline void Object::ReadExtras(Value &val) {
  320. if (Value *curExtras = FindObject(val, "extras")) {
  321. this->extras = glTF2::ReadExtensions("extras", *curExtras);
  322. }
  323. }
  324. #ifdef ASSIMP_ENABLE_DRACO
  325. template <typename T>
  326. inline void CopyFaceIndex_Draco(Buffer &decodedIndexBuffer, const draco::Mesh &draco_mesh) {
  327. const size_t faceStride = sizeof(T) * 3;
  328. for (draco::FaceIndex f(0); f < draco_mesh.num_faces(); ++f) {
  329. const draco::Mesh::Face &face = draco_mesh.face(f);
  330. T indices[3] = { static_cast<T>(face[0].value()), static_cast<T>(face[1].value()), static_cast<T>(face[2].value()) };
  331. memcpy(decodedIndexBuffer.GetPointer() + (f.value() * faceStride), &indices[0], faceStride);
  332. }
  333. }
  334. inline void SetDecodedIndexBuffer_Draco(const draco::Mesh &dracoMesh, Mesh::Primitive &prim) {
  335. if (!prim.indices || dracoMesh.num_faces() == 0)
  336. return;
  337. // Create a decoded Index buffer (if there is one)
  338. size_t componentBytes = prim.indices->GetBytesPerComponent();
  339. std::unique_ptr<Buffer> decodedIndexBuffer(new Buffer());
  340. decodedIndexBuffer->Grow(dracoMesh.num_faces() * 3 * componentBytes);
  341. // If accessor uses the same size as draco implementation, copy the draco buffer directly
  342. // Usually uint32_t but shouldn't assume
  343. if (sizeof(dracoMesh.face(draco::FaceIndex(0))[0]) == componentBytes) {
  344. memcpy(decodedIndexBuffer->GetPointer(), &dracoMesh.face(draco::FaceIndex(0))[0], decodedIndexBuffer->byteLength);
  345. return;
  346. }
  347. // Not same size, convert
  348. switch (componentBytes) {
  349. case sizeof(uint32_t):
  350. CopyFaceIndex_Draco<uint32_t>(*decodedIndexBuffer, dracoMesh);
  351. break;
  352. case sizeof(uint16_t):
  353. CopyFaceIndex_Draco<uint16_t>(*decodedIndexBuffer, dracoMesh);
  354. break;
  355. case sizeof(uint8_t):
  356. CopyFaceIndex_Draco<uint8_t>(*decodedIndexBuffer, dracoMesh);
  357. break;
  358. default:
  359. ai_assert(false);
  360. break;
  361. }
  362. // Assign this alternate data buffer to the accessor
  363. prim.indices->decodedBuffer.swap(decodedIndexBuffer);
  364. }
  365. template <typename T>
  366. static bool GetAttributeForAllPoints_Draco(const draco::Mesh &dracoMesh,
  367. const draco::PointAttribute &dracoAttribute,
  368. Buffer &outBuffer) {
  369. size_t byteOffset = 0;
  370. T values[4] = { 0, 0, 0, 0 };
  371. for (draco::PointIndex i(0); i < dracoMesh.num_points(); ++i) {
  372. const draco::AttributeValueIndex val_index = dracoAttribute.mapped_index(i);
  373. if (!dracoAttribute.ConvertValue<T>(val_index, dracoAttribute.num_components(), values)) {
  374. return false;
  375. }
  376. memcpy(outBuffer.GetPointer() + byteOffset, &values[0], sizeof(T) * dracoAttribute.num_components());
  377. byteOffset += sizeof(T) * dracoAttribute.num_components();
  378. }
  379. return true;
  380. }
  381. inline void SetDecodedAttributeBuffer_Draco(const draco::Mesh &dracoMesh, uint32_t dracoAttribId, Accessor &accessor) {
  382. // Create decoded buffer
  383. const draco::PointAttribute *pDracoAttribute = dracoMesh.GetAttributeByUniqueId(dracoAttribId);
  384. if (pDracoAttribute == nullptr) {
  385. throw DeadlyImportError("GLTF: Invalid draco attribute id: ", dracoAttribId);
  386. }
  387. size_t componentBytes = accessor.GetBytesPerComponent();
  388. std::unique_ptr<Buffer> decodedAttribBuffer(new Buffer());
  389. decodedAttribBuffer->Grow(dracoMesh.num_points() * pDracoAttribute->num_components() * componentBytes);
  390. switch (accessor.componentType) {
  391. case ComponentType_BYTE:
  392. GetAttributeForAllPoints_Draco<int8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
  393. break;
  394. case ComponentType_UNSIGNED_BYTE:
  395. GetAttributeForAllPoints_Draco<uint8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
  396. break;
  397. case ComponentType_SHORT:
  398. GetAttributeForAllPoints_Draco<int16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
  399. break;
  400. case ComponentType_UNSIGNED_SHORT:
  401. GetAttributeForAllPoints_Draco<uint16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
  402. break;
  403. case ComponentType_UNSIGNED_INT:
  404. GetAttributeForAllPoints_Draco<uint32_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
  405. break;
  406. case ComponentType_FLOAT:
  407. GetAttributeForAllPoints_Draco<float>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
  408. break;
  409. default:
  410. ai_assert(false);
  411. break;
  412. }
  413. // Assign this alternate data buffer to the accessor
  414. accessor.decodedBuffer.swap(decodedAttribBuffer);
  415. }
  416. #endif // ASSIMP_ENABLE_DRACO
  417. //
  418. // LazyDict methods
  419. //
  420. template <class T>
  421. inline LazyDict<T>::LazyDict(Asset &asset, const char *dictId, const char *extId) :
  422. mDictId(dictId),
  423. mExtId(extId),
  424. mDict(0),
  425. mAsset(asset) {
  426. asset.mDicts.push_back(this); // register to the list of dictionaries
  427. }
  428. template <class T>
  429. inline LazyDict<T>::~LazyDict() {
  430. for (size_t i = 0; i < mObjs.size(); ++i) {
  431. delete mObjs[i];
  432. }
  433. }
  434. template <class T>
  435. inline void LazyDict<T>::AttachToDocument(Document &doc) {
  436. Value *container = nullptr;
  437. const char* context = nullptr;
  438. if (mExtId) {
  439. if (Value *exts = FindObject(doc, "extensions")) {
  440. container = FindObjectInContext(*exts, mExtId, "extensions");
  441. context = mExtId;
  442. }
  443. } else {
  444. container = &doc;
  445. context = "the document";
  446. }
  447. if (container) {
  448. mDict = FindArrayInContext(*container, mDictId, context);
  449. }
  450. }
  451. template <class T>
  452. inline void LazyDict<T>::DetachFromDocument() {
  453. mDict = nullptr;
  454. }
  455. template <class T>
  456. unsigned int LazyDict<T>::Remove(const char *id) {
  457. id = T::TranslateId(mAsset, id);
  458. typename IdDict::iterator objIt = mObjsById.find(id);
  459. if (objIt == mObjsById.end()) {
  460. throw DeadlyExportError("GLTF: Object with id \"" + std::string(id) + "\" is not found");
  461. }
  462. const unsigned int index = objIt->second;
  463. mAsset.mUsedIds[id] = false;
  464. mObjsById.erase(id);
  465. mObjsByOIndex.erase(index);
  466. delete mObjs[index];
  467. mObjs.erase(mObjs.begin() + index);
  468. //update index of object in mObjs;
  469. for (unsigned int i = index; i < mObjs.size(); ++i) {
  470. T *obj = mObjs[i];
  471. obj->index = i;
  472. }
  473. for (IdDict::iterator it = mObjsById.begin(); it != mObjsById.end(); ++it) {
  474. if (it->second <= index) {
  475. continue;
  476. }
  477. mObjsById[it->first] = it->second - 1;
  478. }
  479. for (Dict::iterator it = mObjsByOIndex.begin(); it != mObjsByOIndex.end(); ++it) {
  480. if (it->second <= index) {
  481. continue;
  482. }
  483. mObjsByOIndex[it->first] = it->second - 1;
  484. }
  485. return index;
  486. }
  487. template <class T>
  488. Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
  489. typename Dict::iterator it = mObjsByOIndex.find(i);
  490. if (it != mObjsByOIndex.end()) { // already created?
  491. return Ref<T>(mObjs, it->second);
  492. }
  493. // read it from the JSON object
  494. if (!mDict) {
  495. throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\"");
  496. }
  497. if (!mDict->IsArray()) {
  498. throw DeadlyImportError("GLTF: Field \"", mDictId, "\" is not an array");
  499. }
  500. if (i >= mDict->Size()) {
  501. throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
  502. }
  503. Value &obj = (*mDict)[i];
  504. if (!obj.IsObject()) {
  505. throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
  506. }
  507. if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
  508. throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
  509. }
  510. mRecursiveReferenceCheck.insert(i);
  511. // Unique ptr prevents memory leak in case of Read throws an exception
  512. auto inst = std::unique_ptr<T>(new T());
  513. // Try to make this human readable so it can be used in error messages.
  514. inst->id = std::string(mDictId) + "[" + ai_to_string(i) + "]";
  515. inst->oIndex = i;
  516. ReadMember(obj, "name", inst->name);
  517. inst->Read(obj, mAsset);
  518. inst->ReadExtensions(obj);
  519. inst->ReadExtras(obj);
  520. Ref<T> result = Add(inst.release());
  521. mRecursiveReferenceCheck.erase(i);
  522. return result;
  523. }
  524. template <class T>
  525. Ref<T> LazyDict<T>::Get(unsigned int i) {
  526. return Ref<T>(mObjs, i);
  527. }
  528. template <class T>
  529. Ref<T> LazyDict<T>::Get(const char *id) {
  530. id = T::TranslateId(mAsset, id);
  531. typename IdDict::iterator it = mObjsById.find(id);
  532. if (it != mObjsById.end()) { // already created?
  533. return Ref<T>(mObjs, it->second);
  534. }
  535. return Ref<T>();
  536. }
  537. template <class T>
  538. Ref<T> LazyDict<T>::Add(T *obj) {
  539. unsigned int idx = unsigned(mObjs.size());
  540. mObjs.push_back(obj);
  541. mObjsByOIndex[obj->oIndex] = idx;
  542. mObjsById[obj->id] = idx;
  543. mAsset.mUsedIds[obj->id] = true;
  544. return Ref<T>(mObjs, idx);
  545. }
  546. template <class T>
  547. Ref<T> LazyDict<T>::Create(const char *id) {
  548. Asset::IdMap::iterator it = mAsset.mUsedIds.find(id);
  549. if (it != mAsset.mUsedIds.end()) {
  550. throw DeadlyImportError("GLTF: two objects with the same ID exist");
  551. }
  552. T *inst = new T();
  553. unsigned int idx = unsigned(mObjs.size());
  554. inst->id = id;
  555. inst->index = idx;
  556. inst->oIndex = idx;
  557. return Add(inst);
  558. }
  559. //
  560. // glTF dictionary objects methods
  561. //
  562. inline Buffer::Buffer() :
  563. byteLength(0),
  564. type(Type_arraybuffer),
  565. EncodedRegion_Current(nullptr),
  566. mIsSpecial(false) {}
  567. inline Buffer::~Buffer() {
  568. for (SEncodedRegion *reg : EncodedRegion_List)
  569. delete reg;
  570. }
  571. inline const char *Buffer::TranslateId(Asset & /*r*/, const char *id) {
  572. return id;
  573. }
  574. inline void Buffer::Read(Value &obj, Asset &r) {
  575. size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
  576. byteLength = statedLength;
  577. Value *it = FindString(obj, "uri");
  578. if (!it) {
  579. if (statedLength > 0) {
  580. throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute");
  581. }
  582. return;
  583. }
  584. const char *uri = it->GetString();
  585. glTFCommon::Util::DataURI dataURI;
  586. if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
  587. if (dataURI.base64) {
  588. uint8_t *data = nullptr;
  589. this->byteLength = glTFCommon::Util::DecodeBase64(dataURI.data, dataURI.dataLength, data);
  590. this->mData.reset(data, std::default_delete<uint8_t[]>());
  591. if (statedLength > 0 && this->byteLength != statedLength) {
  592. throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
  593. " bytes, but found ", ai_to_string(dataURI.dataLength));
  594. }
  595. } else { // assume raw data
  596. if (statedLength != dataURI.dataLength) {
  597. throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength),
  598. " bytes, but found ", ai_to_string(dataURI.dataLength));
  599. }
  600. this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
  601. memcpy(this->mData.get(), dataURI.data, dataURI.dataLength);
  602. }
  603. } else { // Local file
  604. if (byteLength > 0) {
  605. std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir.back() == '/' ? r.mCurrentAssetDir : r.mCurrentAssetDir + '/') : "";
  606. IOStream *file = r.OpenFile(dir + uri, "rb");
  607. if (file) {
  608. bool ok = LoadFromStream(*file, byteLength);
  609. delete file;
  610. if (!ok)
  611. throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\"");
  612. } else {
  613. throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\"");
  614. }
  615. }
  616. }
  617. }
  618. inline bool Buffer::LoadFromStream(IOStream &stream, size_t length, size_t baseOffset) {
  619. byteLength = length ? length : stream.FileSize();
  620. if (baseOffset) {
  621. stream.Seek(baseOffset, aiOrigin_SET);
  622. }
  623. mData.reset(new uint8_t[byteLength], std::default_delete<uint8_t[]>());
  624. if (stream.Read(mData.get(), byteLength, 1) != 1) {
  625. return false;
  626. }
  627. return true;
  628. }
  629. inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) {
  630. // Check pointer to data
  631. if (pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided.");
  632. // Check offset
  633. if (pOffset > byteLength) {
  634. const uint8_t val_size = 32;
  635. char val[val_size];
  636. ai_snprintf(val, val_size, AI_SIZEFMT, pOffset);
  637. throw DeadlyImportError("GLTF: incorrect offset value (", val, ") for marking encoded region.");
  638. }
  639. // Check length
  640. if ((pOffset + pEncodedData_Length) > byteLength) {
  641. const uint8_t val_size = 64;
  642. char val[val_size];
  643. ai_snprintf(val, val_size, AI_SIZEFMT "/" AI_SIZEFMT, pOffset, pEncodedData_Length);
  644. throw DeadlyImportError("GLTF: encoded region with offset/length (", val, ") is out of range.");
  645. }
  646. // Add new region
  647. EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID));
  648. // And set new value for "byteLength"
  649. byteLength += (pDecodedData_Length - pEncodedData_Length);
  650. }
  651. inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) {
  652. if ((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) {
  653. return;
  654. }
  655. for (SEncodedRegion *reg : EncodedRegion_List) {
  656. if (reg->ID == pID) {
  657. EncodedRegion_Current = reg;
  658. return;
  659. }
  660. }
  661. throw DeadlyImportError("GLTF: EncodedRegion with ID: \"", pID, "\" not found.");
  662. }
  663. inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) {
  664. if ((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) {
  665. return false;
  666. }
  667. const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
  668. uint8_t *new_data = new uint8_t[new_data_size];
  669. // Copy data which place before replacing part.
  670. ::memcpy(new_data, mData.get(), pBufferData_Offset);
  671. // Copy new data.
  672. ::memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
  673. // Copy data which place after replacing part.
  674. ::memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset);
  675. // Apply new data
  676. mData.reset(new_data, std::default_delete<uint8_t[]>());
  677. byteLength = new_data_size;
  678. return true;
  679. }
  680. inline bool Buffer::ReplaceData_joint(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) {
  681. if ((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) {
  682. return false;
  683. }
  684. const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
  685. uint8_t *new_data = new uint8_t[new_data_size];
  686. // Copy data which place before replacing part.
  687. memcpy(new_data, mData.get(), pBufferData_Offset);
  688. // Copy new data.
  689. memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
  690. // Copy data which place after replacing part.
  691. memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], new_data_size - (pBufferData_Offset + pReplace_Count));
  692. // Apply new data
  693. mData.reset(new_data, std::default_delete<uint8_t[]>());
  694. byteLength = new_data_size;
  695. return true;
  696. }
  697. inline size_t Buffer::AppendData(uint8_t *data, size_t length) {
  698. const size_t offset = this->byteLength;
  699. // Force alignment to 4 bits
  700. const size_t paddedLength = (length + 3) & ~3;
  701. Grow(paddedLength);
  702. memcpy(mData.get() + offset, data, length);
  703. memset(mData.get() + offset + length, 0, paddedLength - length);
  704. return offset;
  705. }
  706. inline void Buffer::Grow(size_t amount) {
  707. if (amount <= 0) {
  708. return;
  709. }
  710. // Capacity is big enough
  711. if (capacity >= byteLength + amount) {
  712. byteLength += amount;
  713. return;
  714. }
  715. // Just allocate data which we need
  716. capacity = byteLength + amount;
  717. uint8_t *b = new uint8_t[capacity];
  718. if (nullptr != mData) {
  719. memcpy(b, mData.get(), byteLength);
  720. }
  721. mData.reset(b, std::default_delete<uint8_t[]>());
  722. byteLength += amount;
  723. }
  724. //
  725. // struct BufferView
  726. //
  727. inline void BufferView::Read(Value &obj, Asset &r) {
  728. if (Value *bufferVal = FindUInt(obj, "buffer")) {
  729. buffer = r.buffers.Retrieve(bufferVal->GetUint());
  730. }
  731. if (!buffer) {
  732. throw DeadlyImportError("GLTF: Buffer view without valid buffer.");
  733. }
  734. byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
  735. byteLength = MemberOrDefault(obj, "byteLength", size_t(0));
  736. byteStride = MemberOrDefault(obj, "byteStride", 0u);
  737. // Check length
  738. if ((byteOffset + byteLength) > buffer->byteLength) {
  739. throw DeadlyImportError("GLTF: Buffer view with offset/length (", byteOffset, "/", byteLength, ") is out of range.");
  740. }
  741. }
  742. inline uint8_t *BufferView::GetPointer(size_t accOffset) {
  743. if (!buffer) {
  744. return nullptr;
  745. }
  746. uint8_t *basePtr = buffer->GetPointer();
  747. if (!basePtr) {
  748. return nullptr;
  749. }
  750. size_t offset = accOffset + byteOffset;
  751. if (buffer->EncodedRegion_Current != nullptr) {
  752. const size_t begin = buffer->EncodedRegion_Current->Offset;
  753. const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
  754. if ((offset >= begin) && (offset < end)) {
  755. return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
  756. }
  757. }
  758. return basePtr + offset;
  759. }
  760. //
  761. // struct Accessor
  762. //
  763. inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
  764. if (bytes) {
  765. data.assign(bytes, bytes + numBytes);
  766. } else {
  767. data.resize(numBytes, 0x00);
  768. }
  769. }
  770. inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
  771. uint8_t *pIndices = indices->GetPointer(indicesByteOffset);
  772. const unsigned int indexSize = int(ComponentTypeSize(indicesType));
  773. uint8_t *indicesEnd = pIndices + count * indexSize;
  774. uint8_t *pValues = values->GetPointer(valuesByteOffset);
  775. while (pIndices != indicesEnd) {
  776. size_t offset;
  777. switch (indicesType) {
  778. case ComponentType_UNSIGNED_BYTE:
  779. offset = *pIndices;
  780. break;
  781. case ComponentType_UNSIGNED_SHORT:
  782. offset = *reinterpret_cast<uint16_t *>(pIndices);
  783. break;
  784. case ComponentType_UNSIGNED_INT:
  785. offset = *reinterpret_cast<uint32_t *>(pIndices);
  786. break;
  787. default:
  788. // have fun with float and negative values from signed types as indices.
  789. throw DeadlyImportError("Unsupported component type in index.");
  790. }
  791. offset *= elementSize;
  792. std::memcpy(data.data() + offset, pValues, elementSize);
  793. pValues += elementSize;
  794. pIndices += indexSize;
  795. }
  796. }
  797. inline void Accessor::Read(Value &obj, Asset &r) {
  798. if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
  799. bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
  800. }
  801. byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
  802. componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
  803. {
  804. const Value* countValue = FindUInt(obj, "count");
  805. if (!countValue)
  806. {
  807. throw DeadlyImportError("A count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
  808. }
  809. count = countValue->GetUint();
  810. }
  811. const char *typestr;
  812. type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
  813. if (bufferView) {
  814. // Check length
  815. unsigned long long byteLength = (unsigned long long)GetBytesPerComponent() * (unsigned long long)count;
  816. // handle integer overflow
  817. if (byteLength < count) {
  818. throw DeadlyImportError("GLTF: Accessor with offset/count (", byteOffset, "/", count, ") is out of range.");
  819. }
  820. if ((byteOffset + byteLength) > bufferView->byteLength || (bufferView->byteOffset + byteOffset + byteLength) > bufferView->buffer->byteLength) {
  821. throw DeadlyImportError("GLTF: Accessor with offset/length (", byteOffset, "/", byteLength, ") is out of range.");
  822. }
  823. }
  824. if (Value *sparseValue = FindObject(obj, "sparse")) {
  825. sparse.reset(new Sparse);
  826. // count
  827. ReadMember(*sparseValue, "count", sparse->count);
  828. // indices
  829. if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
  830. //indices bufferView
  831. Value *indiceViewID = FindUInt(*indicesValue, "bufferView");
  832. sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
  833. //indices byteOffset
  834. sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
  835. //indices componentType
  836. sparse->indicesType = MemberOrDefault(*indicesValue, "componentType", ComponentType_BYTE);
  837. //sparse->indices->Read(*indicesValue, r);
  838. }
  839. // value
  840. if (Value *valuesValue = FindObject(*sparseValue, "values")) {
  841. //value bufferView
  842. Value *valueViewID = FindUInt(*valuesValue, "bufferView");
  843. sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
  844. //value byteOffset
  845. sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
  846. //sparse->values->Read(*valuesValue, r);
  847. }
  848. // indicesType
  849. sparse->indicesType = MemberOrDefault(*sparseValue, "componentType", ComponentType_UNSIGNED_SHORT);
  850. const unsigned int elementSize = GetElementSize();
  851. const size_t dataSize = count * elementSize;
  852. sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : 0);
  853. sparse->PatchData(elementSize);
  854. }
  855. }
  856. inline unsigned int Accessor::GetNumComponents() {
  857. return AttribType::GetNumComponents(type);
  858. }
  859. inline unsigned int Accessor::GetBytesPerComponent() {
  860. return int(ComponentTypeSize(componentType));
  861. }
  862. inline unsigned int Accessor::GetElementSize() {
  863. return GetNumComponents() * GetBytesPerComponent();
  864. }
  865. inline uint8_t *Accessor::GetPointer() {
  866. if (decodedBuffer)
  867. return decodedBuffer->GetPointer();
  868. if (sparse)
  869. return sparse->data.data();
  870. if (!bufferView || !bufferView->buffer) return nullptr;
  871. uint8_t *basePtr = bufferView->buffer->GetPointer();
  872. if (!basePtr) return nullptr;
  873. size_t offset = byteOffset + bufferView->byteOffset;
  874. // Check if region is encoded.
  875. if (bufferView->buffer->EncodedRegion_Current != nullptr) {
  876. const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
  877. const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
  878. if ((offset >= begin) && (offset < end))
  879. return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
  880. }
  881. return basePtr + offset;
  882. }
  883. inline size_t Accessor::GetStride() {
  884. // Decoded buffer is always packed
  885. if (decodedBuffer)
  886. return GetElementSize();
  887. // Sparse and normal bufferView
  888. return (bufferView && bufferView->byteStride ? bufferView->byteStride : GetElementSize());
  889. }
  890. inline size_t Accessor::GetMaxByteSize() {
  891. if (decodedBuffer)
  892. return decodedBuffer->byteLength;
  893. return (bufferView ? bufferView->byteLength : sparse->data.size());
  894. }
  895. namespace {
  896. inline void CopyData(size_t count,
  897. const uint8_t *src, size_t src_stride,
  898. uint8_t *dst, size_t dst_stride) {
  899. if (src_stride == dst_stride) {
  900. memcpy(dst, src, count * src_stride);
  901. } else {
  902. size_t sz = std::min(src_stride, dst_stride);
  903. for (size_t i = 0; i < count; ++i) {
  904. memcpy(dst, src, sz);
  905. if (sz < dst_stride) {
  906. memset(dst + sz, 0, dst_stride - sz);
  907. }
  908. src += src_stride;
  909. dst += dst_stride;
  910. }
  911. }
  912. }
  913. } // namespace
  914. template <class T>
  915. void Accessor::ExtractData(T *&outData) {
  916. uint8_t *data = GetPointer();
  917. if (!data) {
  918. throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
  919. }
  920. const size_t elemSize = GetElementSize();
  921. const size_t totalSize = elemSize * count;
  922. const size_t stride = GetStride();
  923. const size_t targetElemSize = sizeof(T);
  924. if (elemSize > targetElemSize) {
  925. throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
  926. }
  927. const size_t maxSize = GetMaxByteSize();
  928. if (count * stride > maxSize) {
  929. throw DeadlyImportError("GLTF: count*stride ", (count * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
  930. }
  931. outData = new T[count];
  932. if (stride == elemSize && targetElemSize == elemSize) {
  933. memcpy(outData, data, totalSize);
  934. } else {
  935. for (size_t i = 0; i < count; ++i) {
  936. memcpy(outData + i, data + i * stride, elemSize);
  937. }
  938. }
  939. }
  940. inline void Accessor::WriteData(size_t _count, const void *src_buffer, size_t src_stride) {
  941. uint8_t *buffer_ptr = bufferView->buffer->GetPointer();
  942. size_t offset = byteOffset + bufferView->byteOffset;
  943. size_t dst_stride = GetNumComponents() * GetBytesPerComponent();
  944. const uint8_t *src = reinterpret_cast<const uint8_t *>(src_buffer);
  945. uint8_t *dst = reinterpret_cast<uint8_t *>(buffer_ptr + offset);
  946. ai_assert(dst + _count * dst_stride <= buffer_ptr + bufferView->buffer->byteLength);
  947. CopyData(_count, src, src_stride, dst, dst_stride);
  948. }
  949. inline void Accessor::WriteSparseValues(size_t _count, const void *src_data, size_t src_dataStride) {
  950. if (!sparse)
  951. return;
  952. // values
  953. uint8_t *value_buffer_ptr = sparse->values->buffer->GetPointer();
  954. size_t value_offset = sparse->valuesByteOffset + sparse->values->byteOffset;
  955. size_t value_dst_stride = GetNumComponents() * GetBytesPerComponent();
  956. const uint8_t *value_src = reinterpret_cast<const uint8_t *>(src_data);
  957. uint8_t *value_dst = reinterpret_cast<uint8_t *>(value_buffer_ptr + value_offset);
  958. ai_assert(value_dst + _count * value_dst_stride <= value_buffer_ptr + sparse->values->buffer->byteLength);
  959. CopyData(_count, value_src, src_dataStride, value_dst, value_dst_stride);
  960. }
  961. inline void Accessor::WriteSparseIndices(size_t _count, const void *src_idx, size_t src_idxStride) {
  962. if (!sparse)
  963. return;
  964. // indices
  965. uint8_t *indices_buffer_ptr = sparse->indices->buffer->GetPointer();
  966. size_t indices_offset = sparse->indicesByteOffset + sparse->indices->byteOffset;
  967. size_t indices_dst_stride = 1 * sizeof(unsigned short);
  968. const uint8_t *indices_src = reinterpret_cast<const uint8_t *>(src_idx);
  969. uint8_t *indices_dst = reinterpret_cast<uint8_t *>(indices_buffer_ptr + indices_offset);
  970. ai_assert(indices_dst + _count * indices_dst_stride <= indices_buffer_ptr + sparse->indices->buffer->byteLength);
  971. CopyData(_count, indices_src, src_idxStride, indices_dst, indices_dst_stride);
  972. }
  973. inline Accessor::Indexer::Indexer(Accessor &acc) :
  974. accessor(acc),
  975. data(acc.GetPointer()),
  976. elemSize(acc.GetElementSize()),
  977. stride(acc.GetStride()) {
  978. }
  979. //! Accesses the i-th value as defined by the accessor
  980. template <class T>
  981. T Accessor::Indexer::GetValue(int i) {
  982. ai_assert(data);
  983. if (i * stride >= accessor.GetMaxByteSize()) {
  984. throw DeadlyImportError("GLTF: Invalid index ", i, ", count out of range for buffer with stride ", stride, " and size ", accessor.GetMaxByteSize(), ".");
  985. }
  986. // Ensure that the memcpy doesn't overwrite the local.
  987. const size_t sizeToCopy = std::min(elemSize, sizeof(T));
  988. T value = T();
  989. // Assume platform endianness matches GLTF binary data (which is little-endian).
  990. memcpy(&value, data + i * stride, sizeToCopy);
  991. return value;
  992. }
  993. inline Image::Image() :
  994. width(0),
  995. height(0),
  996. mDataLength(0) {
  997. }
  998. inline void Image::Read(Value &obj, Asset &r) {
  999. //basisu: no need to handle .ktx2, .basis, load as is
  1000. if (!mDataLength) {
  1001. Value *curUri = FindString(obj, "uri");
  1002. if (nullptr != curUri) {
  1003. const char *uristr = curUri->GetString();
  1004. glTFCommon::Util::DataURI dataURI;
  1005. if (ParseDataURI(uristr, curUri->GetStringLength(), dataURI)) {
  1006. mimeType = dataURI.mediaType;
  1007. if (dataURI.base64) {
  1008. uint8_t *ptr = nullptr;
  1009. mDataLength = glTFCommon::Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr);
  1010. mData.reset(ptr);
  1011. }
  1012. } else {
  1013. this->uri = uristr;
  1014. }
  1015. } else if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
  1016. this->bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
  1017. if (Value *mtype = FindString(obj, "mimeType")) {
  1018. this->mimeType = mtype->GetString();
  1019. }
  1020. if (!this->bufferView || this->mimeType.empty()) {
  1021. throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " does not have a URI, so it must have a valid bufferView and mimetype");
  1022. }
  1023. Ref<Buffer> buffer = this->bufferView->buffer;
  1024. this->mDataLength = this->bufferView->byteLength;
  1025. // maybe this memcpy could be avoided if aiTexture does not delete[] pcData at destruction.
  1026. this->mData.reset(new uint8_t[this->mDataLength]);
  1027. memcpy(this->mData.get(), buffer->GetPointer() + this->bufferView->byteOffset, this->mDataLength);
  1028. } else {
  1029. throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " should have either a URI of a bufferView and mimetype");
  1030. }
  1031. }
  1032. }
  1033. inline uint8_t *Image::StealData() {
  1034. mDataLength = 0;
  1035. return mData.release();
  1036. }
  1037. // Never take over the ownership of data whenever binary or not
  1038. inline void Image::SetData(uint8_t *data, size_t length, Asset &r) {
  1039. Ref<Buffer> b = r.GetBodyBuffer();
  1040. if (b) { // binary file: append to body
  1041. std::string bvId = r.FindUniqueID(this->id, "imgdata");
  1042. bufferView = r.bufferViews.Create(bvId);
  1043. bufferView->buffer = b;
  1044. bufferView->byteLength = length;
  1045. bufferView->byteOffset = b->AppendData(data, length);
  1046. } else { // text file: will be stored as a data uri
  1047. uint8_t *temp = new uint8_t[length];
  1048. memcpy(temp, data, length);
  1049. this->mData.reset(temp);
  1050. this->mDataLength = length;
  1051. }
  1052. }
  1053. inline void Sampler::Read(Value &obj, Asset & /*r*/) {
  1054. SetDefaults();
  1055. ReadMember(obj, "name", name);
  1056. ReadMember(obj, "magFilter", magFilter);
  1057. ReadMember(obj, "minFilter", minFilter);
  1058. ReadMember(obj, "wrapS", wrapS);
  1059. ReadMember(obj, "wrapT", wrapT);
  1060. }
  1061. inline void Sampler::SetDefaults() {
  1062. //only wrapping modes have defaults
  1063. wrapS = SamplerWrap::Repeat;
  1064. wrapT = SamplerWrap::Repeat;
  1065. magFilter = SamplerMagFilter::UNSET;
  1066. minFilter = SamplerMinFilter::UNSET;
  1067. }
  1068. inline void Texture::Read(Value &obj, Asset &r) {
  1069. if (Value *sourceVal = FindUInt(obj, "source")) {
  1070. source = r.images.Retrieve(sourceVal->GetUint());
  1071. }
  1072. if (Value *samplerVal = FindUInt(obj, "sampler")) {
  1073. sampler = r.samplers.Retrieve(samplerVal->GetUint());
  1074. }
  1075. }
  1076. void Material::SetTextureProperties(Asset &r, Value *prop, TextureInfo &out) {
  1077. if (r.extensionsUsed.KHR_texture_transform) {
  1078. if (Value *pKHR_texture_transform = FindExtension(*prop, "KHR_texture_transform")) {
  1079. out.textureTransformSupported = true;
  1080. if (Value *array = FindArray(*pKHR_texture_transform, "offset")) {
  1081. out.TextureTransformExt_t.offset[0] = (*array)[0].GetFloat();
  1082. out.TextureTransformExt_t.offset[1] = (*array)[1].GetFloat();
  1083. } else {
  1084. out.TextureTransformExt_t.offset[0] = 0;
  1085. out.TextureTransformExt_t.offset[1] = 0;
  1086. }
  1087. if (!ReadMember(*pKHR_texture_transform, "rotation", out.TextureTransformExt_t.rotation)) {
  1088. out.TextureTransformExt_t.rotation = 0;
  1089. }
  1090. if (Value *array = FindArray(*pKHR_texture_transform, "scale")) {
  1091. out.TextureTransformExt_t.scale[0] = (*array)[0].GetFloat();
  1092. out.TextureTransformExt_t.scale[1] = (*array)[1].GetFloat();
  1093. } else {
  1094. out.TextureTransformExt_t.scale[0] = 1;
  1095. out.TextureTransformExt_t.scale[1] = 1;
  1096. }
  1097. }
  1098. }
  1099. if (Value *indexProp = FindUInt(*prop, "index")) {
  1100. out.texture = r.textures.Retrieve(indexProp->GetUint());
  1101. }
  1102. if (Value *texcoord = FindUInt(*prop, "texCoord")) {
  1103. out.texCoord = texcoord->GetUint();
  1104. }
  1105. }
  1106. inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, TextureInfo &out) {
  1107. if (Value *prop = FindMember(vals, propName)) {
  1108. SetTextureProperties(r, prop, out);
  1109. }
  1110. }
  1111. inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, NormalTextureInfo &out) {
  1112. if (Value *prop = FindMember(vals, propName)) {
  1113. SetTextureProperties(r, prop, out);
  1114. if (Value *scale = FindNumber(*prop, "scale")) {
  1115. out.scale = static_cast<float>(scale->GetDouble());
  1116. }
  1117. }
  1118. }
  1119. inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, OcclusionTextureInfo &out) {
  1120. if (Value *prop = FindMember(vals, propName)) {
  1121. SetTextureProperties(r, prop, out);
  1122. if (Value *strength = FindNumber(*prop, "strength")) {
  1123. out.strength = static_cast<float>(strength->GetDouble());
  1124. }
  1125. }
  1126. }
  1127. inline void Material::Read(Value &material, Asset &r) {
  1128. SetDefaults();
  1129. if (Value *curPbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) {
  1130. ReadMember(*curPbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor);
  1131. ReadTextureProperty(r, *curPbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture);
  1132. ReadTextureProperty(r, *curPbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture);
  1133. ReadMember(*curPbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor);
  1134. ReadMember(*curPbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor);
  1135. }
  1136. ReadTextureProperty(r, material, "normalTexture", this->normalTexture);
  1137. ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture);
  1138. ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture);
  1139. ReadMember(material, "emissiveFactor", this->emissiveFactor);
  1140. ReadMember(material, "doubleSided", this->doubleSided);
  1141. ReadMember(material, "alphaMode", this->alphaMode);
  1142. ReadMember(material, "alphaCutoff", this->alphaCutoff);
  1143. if (Value *extensions = FindObject(material, "extensions")) {
  1144. if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
  1145. if (Value *curPbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) {
  1146. PbrSpecularGlossiness pbrSG;
  1147. ReadMember(*curPbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor);
  1148. ReadTextureProperty(r, *curPbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture);
  1149. ReadTextureProperty(r, *curPbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture);
  1150. ReadMember(*curPbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor);
  1151. ReadMember(*curPbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor);
  1152. this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
  1153. }
  1154. }
  1155. // Extension KHR_texture_transform is handled in ReadTextureProperty
  1156. if (r.extensionsUsed.KHR_materials_sheen) {
  1157. if (Value *curMaterialSheen = FindObject(*extensions, "KHR_materials_sheen")) {
  1158. MaterialSheen sheen;
  1159. ReadMember(*curMaterialSheen, "sheenColorFactor", sheen.sheenColorFactor);
  1160. ReadTextureProperty(r, *curMaterialSheen, "sheenColorTexture", sheen.sheenColorTexture);
  1161. ReadMember(*curMaterialSheen, "sheenRoughnessFactor", sheen.sheenRoughnessFactor);
  1162. ReadTextureProperty(r, *curMaterialSheen, "sheenRoughnessTexture", sheen.sheenRoughnessTexture);
  1163. this->materialSheen = Nullable<MaterialSheen>(sheen);
  1164. }
  1165. }
  1166. if (r.extensionsUsed.KHR_materials_clearcoat) {
  1167. if (Value *curMaterialClearcoat = FindObject(*extensions, "KHR_materials_clearcoat")) {
  1168. MaterialClearcoat clearcoat;
  1169. ReadMember(*curMaterialClearcoat, "clearcoatFactor", clearcoat.clearcoatFactor);
  1170. ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatTexture", clearcoat.clearcoatTexture);
  1171. ReadMember(*curMaterialClearcoat, "clearcoatRoughnessFactor", clearcoat.clearcoatRoughnessFactor);
  1172. ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatRoughnessTexture", clearcoat.clearcoatRoughnessTexture);
  1173. ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatNormalTexture", clearcoat.clearcoatNormalTexture);
  1174. this->materialClearcoat = Nullable<MaterialClearcoat>(clearcoat);
  1175. }
  1176. }
  1177. if (r.extensionsUsed.KHR_materials_transmission) {
  1178. if (Value *curMaterialTransmission = FindObject(*extensions, "KHR_materials_transmission")) {
  1179. MaterialTransmission transmission;
  1180. ReadMember(*curMaterialTransmission, "transmissionFactor", transmission.transmissionFactor);
  1181. ReadTextureProperty(r, *curMaterialTransmission, "transmissionTexture", transmission.transmissionTexture);
  1182. this->materialTransmission = Nullable<MaterialTransmission>(transmission);
  1183. }
  1184. }
  1185. unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
  1186. }
  1187. }
  1188. namespace {
  1189. void SetVector(vec4 &v, const float (&in)[4]) {
  1190. v[0] = in[0];
  1191. v[1] = in[1];
  1192. v[2] = in[2];
  1193. v[3] = in[3];
  1194. }
  1195. void SetVector(vec3 &v, const float (&in)[3]) {
  1196. v[0] = in[0];
  1197. v[1] = in[1];
  1198. v[2] = in[2];
  1199. }
  1200. } // namespace
  1201. inline void Material::SetDefaults() {
  1202. //pbr materials
  1203. SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
  1204. pbrMetallicRoughness.metallicFactor = 1.0f;
  1205. pbrMetallicRoughness.roughnessFactor = 1.0f;
  1206. SetVector(emissiveFactor, defaultEmissiveFactor);
  1207. alphaMode = "OPAQUE";
  1208. alphaCutoff = 0.5f;
  1209. doubleSided = false;
  1210. unlit = false;
  1211. }
  1212. inline void PbrSpecularGlossiness::SetDefaults() {
  1213. //pbrSpecularGlossiness properties
  1214. SetVector(diffuseFactor, defaultDiffuseFactor);
  1215. SetVector(specularFactor, defaultSpecularFactor);
  1216. glossinessFactor = 1.0f;
  1217. }
  1218. inline void MaterialSheen::SetDefaults() {
  1219. //KHR_materials_sheen properties
  1220. SetVector(sheenColorFactor, defaultSheenFactor);
  1221. sheenRoughnessFactor = 0.f;
  1222. }
  1223. namespace {
  1224. template <int N>
  1225. inline int Compare(const char *attr, const char (&str)[N]) {
  1226. return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
  1227. }
  1228. #if _MSC_VER
  1229. #pragma warning(push)
  1230. #pragma warning(disable : 4706)
  1231. #endif // _MSC_VER
  1232. inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
  1233. if ((pos = Compare(attr, "POSITION"))) {
  1234. v = &(p.attributes.position);
  1235. } else if ((pos = Compare(attr, "NORMAL"))) {
  1236. v = &(p.attributes.normal);
  1237. } else if ((pos = Compare(attr, "TANGENT"))) {
  1238. v = &(p.attributes.tangent);
  1239. } else if ((pos = Compare(attr, "TEXCOORD"))) {
  1240. v = &(p.attributes.texcoord);
  1241. } else if ((pos = Compare(attr, "COLOR"))) {
  1242. v = &(p.attributes.color);
  1243. } else if ((pos = Compare(attr, "JOINT"))) {
  1244. v = &(p.attributes.joint);
  1245. } else if ((pos = Compare(attr, "JOINTMATRIX"))) {
  1246. v = &(p.attributes.jointmatrix);
  1247. } else if ((pos = Compare(attr, "WEIGHT"))) {
  1248. v = &(p.attributes.weight);
  1249. } else
  1250. return false;
  1251. return true;
  1252. }
  1253. inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
  1254. if ((pos = Compare(attr, "POSITION"))) {
  1255. v = &(p.targets[targetIndex].position);
  1256. } else if ((pos = Compare(attr, "NORMAL"))) {
  1257. v = &(p.targets[targetIndex].normal);
  1258. } else if ((pos = Compare(attr, "TANGENT"))) {
  1259. v = &(p.targets[targetIndex].tangent);
  1260. } else
  1261. return false;
  1262. return true;
  1263. }
  1264. } // namespace
  1265. inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
  1266. Value *curName = FindMember(pJSON_Object, "name");
  1267. if (nullptr != curName) {
  1268. name = curName->GetString();
  1269. }
  1270. /****************** Mesh primitives ******************/
  1271. Value *curPrimitives = FindArray(pJSON_Object, "primitives");
  1272. if (nullptr != curPrimitives) {
  1273. this->primitives.resize(curPrimitives->Size());
  1274. for (unsigned int i = 0; i < curPrimitives->Size(); ++i) {
  1275. Value &primitive = (*curPrimitives)[i];
  1276. Primitive &prim = this->primitives[i];
  1277. prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
  1278. if (Value *indices = FindUInt(primitive, "indices")) {
  1279. prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
  1280. }
  1281. if (Value *material = FindUInt(primitive, "material")) {
  1282. prim.material = pAsset_Root.materials.Retrieve(material->GetUint());
  1283. }
  1284. if (Value *attrs = FindObject(primitive, "attributes")) {
  1285. for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
  1286. if (!it->value.IsUint()) continue;
  1287. const char *attr = it->name.GetString();
  1288. // Valid attribute semantics include POSITION, NORMAL, TANGENT, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
  1289. // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
  1290. int undPos = 0;
  1291. Mesh::AccessorList *vec = nullptr;
  1292. if (GetAttribVector(prim, attr, vec, undPos)) {
  1293. size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
  1294. if ((*vec).size() != idx) {
  1295. throw DeadlyImportError("GLTF: Invalid attribute in mesh: ", name, " primitive: ", i, "attrib: ", attr,
  1296. ". All indices for indexed attribute semantics must start with 0 and be continuous positive integers: TEXCOORD_0, TEXCOORD_1, etc.");
  1297. }
  1298. (*vec).resize(idx + 1);
  1299. (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
  1300. }
  1301. }
  1302. }
  1303. #ifdef ASSIMP_ENABLE_DRACO
  1304. // KHR_draco_mesh_compression spec: Draco can only be used for glTF Triangles or Triangle Strips
  1305. if (pAsset_Root.extensionsUsed.KHR_draco_mesh_compression && (prim.mode == PrimitiveMode_TRIANGLES || prim.mode == PrimitiveMode_TRIANGLE_STRIP)) {
  1306. // Look for draco mesh compression extension and bufferView
  1307. // Skip if any missing
  1308. if (Value *dracoExt = FindExtension(primitive, "KHR_draco_mesh_compression")) {
  1309. if (Value *bufView = FindUInt(*dracoExt, "bufferView")) {
  1310. // Attempt to load indices and attributes using draco compression
  1311. auto bufferView = pAsset_Root.bufferViews.Retrieve(bufView->GetUint());
  1312. // Attempt to perform the draco decode on the buffer data
  1313. const char *bufferViewData = reinterpret_cast<const char *>(bufferView->buffer->GetPointer() + bufferView->byteOffset);
  1314. draco::DecoderBuffer decoderBuffer;
  1315. decoderBuffer.Init(bufferViewData, bufferView->byteLength);
  1316. draco::Decoder decoder;
  1317. auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer);
  1318. if (!decodeResult.ok()) {
  1319. // A corrupt Draco isn't actually fatal if the primitive data is also provided in a standard buffer, but does anyone do that?
  1320. throw DeadlyImportError("GLTF: Invalid Draco mesh compression in mesh: ", name, " primitive: ", i, ": ", decodeResult.status().error_msg_string());
  1321. }
  1322. // Now we have a draco mesh
  1323. const std::unique_ptr<draco::Mesh> &pDracoMesh = decodeResult.value();
  1324. // Redirect the accessors to the decoded data
  1325. // Indices
  1326. SetDecodedIndexBuffer_Draco(*pDracoMesh, prim);
  1327. // Vertex attributes
  1328. if (Value *attrs = FindObject(*dracoExt, "attributes")) {
  1329. for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
  1330. if (!it->value.IsUint()) continue;
  1331. const char *attr = it->name.GetString();
  1332. int undPos = 0;
  1333. Mesh::AccessorList *vec = nullptr;
  1334. if (GetAttribVector(prim, attr, vec, undPos)) {
  1335. size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
  1336. if (idx >= (*vec).size()) {
  1337. throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr,
  1338. ". All indices for indexed attribute semantics must start with 0 and be continuous positive integers: TEXCOORD_0, TEXCOORD_1, etc.");
  1339. }
  1340. if (!(*vec)[idx]) {
  1341. throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr,
  1342. ". All draco-encoded attributes must also define an accessor.");
  1343. }
  1344. Accessor &attribAccessor = *(*vec)[idx];
  1345. if (attribAccessor.count == 0)
  1346. throw DeadlyImportError("GLTF: Invalid draco attribute in mesh: ", name, " primitive: ", i, " attrib: ", attr);
  1347. // Redirect this accessor to the appropriate Draco vertex attribute data
  1348. const uint32_t dracoAttribId = it->value.GetUint();
  1349. SetDecodedAttributeBuffer_Draco(*pDracoMesh, dracoAttribId, attribAccessor);
  1350. }
  1351. }
  1352. }
  1353. }
  1354. }
  1355. }
  1356. #endif
  1357. Value *targetsArray = FindArray(primitive, "targets");
  1358. if (nullptr != targetsArray) {
  1359. prim.targets.resize(targetsArray->Size());
  1360. for (unsigned int j = 0; j < targetsArray->Size(); ++j) {
  1361. Value &target = (*targetsArray)[j];
  1362. if (!target.IsObject()) {
  1363. continue;
  1364. }
  1365. for (Value::MemberIterator it = target.MemberBegin(); it != target.MemberEnd(); ++it) {
  1366. if (!it->value.IsUint()) {
  1367. continue;
  1368. }
  1369. const char *attr = it->name.GetString();
  1370. // Valid attribute semantics include POSITION, NORMAL, TANGENT
  1371. int undPos = 0;
  1372. Mesh::AccessorList *vec = nullptr;
  1373. if (GetAttribTargetVector(prim, j, attr, vec, undPos)) {
  1374. size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
  1375. if ((*vec).size() <= idx) {
  1376. (*vec).resize(idx + 1);
  1377. }
  1378. (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
  1379. }
  1380. }
  1381. }
  1382. }
  1383. }
  1384. }
  1385. Value *curWeights = FindArray(pJSON_Object, "weights");
  1386. if (nullptr != curWeights) {
  1387. this->weights.resize(curWeights->Size());
  1388. for (unsigned int i = 0; i < curWeights->Size(); ++i) {
  1389. Value &weightValue = (*curWeights)[i];
  1390. if (weightValue.IsNumber()) {
  1391. this->weights[i] = weightValue.GetFloat();
  1392. }
  1393. }
  1394. }
  1395. Value *curExtras = FindObject(pJSON_Object, "extras");
  1396. if (nullptr != curExtras) {
  1397. if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
  1398. this->targetNames.resize(curTargetNames->Size());
  1399. for (unsigned int i = 0; i < curTargetNames->Size(); ++i) {
  1400. Value &targetNameValue = (*curTargetNames)[i];
  1401. if (targetNameValue.IsString()) {
  1402. this->targetNames[i] = targetNameValue.GetString();
  1403. }
  1404. }
  1405. }
  1406. }
  1407. }
  1408. inline void Camera::Read(Value &obj, Asset & /*r*/) {
  1409. std::string type_string = std::string(MemberOrDefault(obj, "type", "perspective"));
  1410. if (type_string == "orthographic") {
  1411. type = Camera::Orthographic;
  1412. } else {
  1413. type = Camera::Perspective;
  1414. }
  1415. const char *subobjId = (type == Camera::Orthographic) ? "orthographic" : "perspective";
  1416. Value *it = FindObject(obj, subobjId);
  1417. if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters");
  1418. if (type == Camera::Perspective) {
  1419. cameraProperties.perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
  1420. cameraProperties.perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f / 2.f);
  1421. cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
  1422. cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
  1423. } else {
  1424. cameraProperties.ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f);
  1425. cameraProperties.ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f);
  1426. cameraProperties.ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f);
  1427. cameraProperties.ortographic.znear = MemberOrDefault(*it, "znear", 0.01f);
  1428. }
  1429. }
  1430. inline void Light::Read(Value &obj, Asset & /*r*/) {
  1431. #ifndef M_PI
  1432. const float M_PI = 3.14159265358979323846f;
  1433. #endif
  1434. std::string type_string;
  1435. ReadMember(obj, "type", type_string);
  1436. if (type_string == "directional")
  1437. type = Light::Directional;
  1438. else if (type_string == "point")
  1439. type = Light::Point;
  1440. else
  1441. type = Light::Spot;
  1442. name = MemberOrDefault(obj, "name", "");
  1443. SetVector(color, vec3{ 1.0f, 1.0f, 1.0f });
  1444. ReadMember(obj, "color", color);
  1445. intensity = MemberOrDefault(obj, "intensity", 1.0f);
  1446. ReadMember(obj, "range", range);
  1447. if (type == Light::Spot) {
  1448. Value *spot = FindObject(obj, "spot");
  1449. if (!spot) throw DeadlyImportError("GLTF: Light missing its spot parameters");
  1450. innerConeAngle = MemberOrDefault(*spot, "innerConeAngle", 0.0f);
  1451. outerConeAngle = MemberOrDefault(*spot, "outerConeAngle", static_cast<float>(M_PI / 4.0f));
  1452. }
  1453. }
  1454. inline void Node::Read(Value &obj, Asset &r) {
  1455. if (name.empty()) {
  1456. name = id;
  1457. }
  1458. Value *curChildren = FindArray(obj, "children");
  1459. if (nullptr != curChildren) {
  1460. this->children.reserve(curChildren->Size());
  1461. for (unsigned int i = 0; i < curChildren->Size(); ++i) {
  1462. Value &child = (*curChildren)[i];
  1463. if (child.IsUint()) {
  1464. // get/create the child node
  1465. Ref<Node> chn = r.nodes.Retrieve(child.GetUint());
  1466. if (chn) {
  1467. this->children.push_back(chn);
  1468. }
  1469. }
  1470. }
  1471. }
  1472. Value *curMatrix = FindArray(obj, "matrix");
  1473. if (nullptr != curMatrix) {
  1474. ReadValue(*curMatrix, this->matrix);
  1475. } else {
  1476. ReadMember(obj, "translation", translation);
  1477. ReadMember(obj, "scale", scale);
  1478. ReadMember(obj, "rotation", rotation);
  1479. }
  1480. Value *curMesh = FindUInt(obj, "mesh");
  1481. if (nullptr != curMesh) {
  1482. unsigned int numMeshes = 1;
  1483. this->meshes.reserve(numMeshes);
  1484. Ref<Mesh> meshRef = r.meshes.Retrieve((*curMesh).GetUint());
  1485. if (meshRef) {
  1486. this->meshes.push_back(meshRef);
  1487. }
  1488. }
  1489. // Do not retrieve a skin here, just take a reference, to avoid infinite recursion
  1490. // Skins will be properly loaded later
  1491. Value *curSkin = FindUInt(obj, "skin");
  1492. if (nullptr != curSkin) {
  1493. this->skin = r.skins.Get(curSkin->GetUint());
  1494. }
  1495. Value *curCamera = FindUInt(obj, "camera");
  1496. if (nullptr != curCamera) {
  1497. this->camera = r.cameras.Retrieve(curCamera->GetUint());
  1498. if (this->camera) {
  1499. this->camera->id = this->id;
  1500. }
  1501. }
  1502. Value *curExtensions = FindObject(obj, "extensions");
  1503. if (nullptr != curExtensions) {
  1504. if (r.extensionsUsed.KHR_lights_punctual) {
  1505. if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) {
  1506. Value *curLight = FindUInt(*ext, "light");
  1507. if (nullptr != curLight) {
  1508. this->light = r.lights.Retrieve(curLight->GetUint());
  1509. if (this->light) {
  1510. this->light->id = this->id;
  1511. }
  1512. }
  1513. }
  1514. }
  1515. }
  1516. }
  1517. inline void Scene::Read(Value &obj, Asset &r) {
  1518. if (Value *scene_name = FindString(obj, "name")) {
  1519. if (scene_name->IsString()) {
  1520. this->name = scene_name->GetString();
  1521. }
  1522. }
  1523. if (Value *array = FindArray(obj, "nodes")) {
  1524. for (unsigned int i = 0; i < array->Size(); ++i) {
  1525. if (!(*array)[i].IsUint()) continue;
  1526. Ref<Node> node = r.nodes.Retrieve((*array)[i].GetUint());
  1527. if (node)
  1528. this->nodes.push_back(node);
  1529. }
  1530. }
  1531. }
  1532. inline void Skin::Read(Value &obj, Asset &r) {
  1533. if (Value *matrices = FindUInt(obj, "inverseBindMatrices")) {
  1534. inverseBindMatrices = r.accessors.Retrieve(matrices->GetUint());
  1535. }
  1536. if (Value *joints = FindArray(obj, "joints")) {
  1537. for (unsigned i = 0; i < joints->Size(); ++i) {
  1538. if (!(*joints)[i].IsUint()) continue;
  1539. Ref<Node> node = r.nodes.Retrieve((*joints)[i].GetUint());
  1540. if (node) {
  1541. this->jointNames.push_back(node);
  1542. }
  1543. }
  1544. }
  1545. }
  1546. inline void Animation::Read(Value &obj, Asset &r) {
  1547. Value *curSamplers = FindArray(obj, "samplers");
  1548. if (nullptr != curSamplers) {
  1549. for (unsigned i = 0; i < curSamplers->Size(); ++i) {
  1550. Value &sampler = (*curSamplers)[i];
  1551. Sampler s;
  1552. if (Value *input = FindUInt(sampler, "input")) {
  1553. s.input = r.accessors.Retrieve(input->GetUint());
  1554. }
  1555. if (Value *output = FindUInt(sampler, "output")) {
  1556. s.output = r.accessors.Retrieve(output->GetUint());
  1557. }
  1558. s.interpolation = Interpolation_LINEAR;
  1559. if (Value *interpolation = FindString(sampler, "interpolation")) {
  1560. const std::string interp = interpolation->GetString();
  1561. if (interp == "LINEAR") {
  1562. s.interpolation = Interpolation_LINEAR;
  1563. } else if (interp == "STEP") {
  1564. s.interpolation = Interpolation_STEP;
  1565. } else if (interp == "CUBICSPLINE") {
  1566. s.interpolation = Interpolation_CUBICSPLINE;
  1567. }
  1568. }
  1569. this->samplers.push_back(s);
  1570. }
  1571. }
  1572. Value *curChannels = FindArray(obj, "channels");
  1573. if (nullptr != curChannels) {
  1574. for (unsigned i = 0; i < curChannels->Size(); ++i) {
  1575. Value &channel = (*curChannels)[i];
  1576. Channel c;
  1577. Value *curSampler = FindUInt(channel, "sampler");
  1578. if (nullptr != curSampler) {
  1579. c.sampler = curSampler->GetUint();
  1580. }
  1581. if (Value *target = FindObject(channel, "target")) {
  1582. if (Value *node = FindUInt(*target, "node")) {
  1583. c.target.node = r.nodes.Retrieve(node->GetUint());
  1584. }
  1585. if (Value *path = FindString(*target, "path")) {
  1586. const std::string p = path->GetString();
  1587. if (p == "translation") {
  1588. c.target.path = AnimationPath_TRANSLATION;
  1589. } else if (p == "rotation") {
  1590. c.target.path = AnimationPath_ROTATION;
  1591. } else if (p == "scale") {
  1592. c.target.path = AnimationPath_SCALE;
  1593. } else if (p == "weights") {
  1594. c.target.path = AnimationPath_WEIGHTS;
  1595. }
  1596. }
  1597. }
  1598. this->channels.push_back(c);
  1599. }
  1600. }
  1601. }
  1602. inline void AssetMetadata::Read(Document &doc) {
  1603. if (Value *obj = FindObject(doc, "asset")) {
  1604. ReadMember(*obj, "copyright", copyright);
  1605. ReadMember(*obj, "generator", generator);
  1606. if (Value *versionString = FindStringInContext(*obj, "version", "\"asset\"")) {
  1607. version = versionString->GetString();
  1608. }
  1609. Value *curProfile = FindObjectInContext(*obj, "profile", "\"asset\"");
  1610. if (nullptr != curProfile) {
  1611. ReadMember(*curProfile, "api", this->profile.api);
  1612. ReadMember(*curProfile, "version", this->profile.version);
  1613. }
  1614. }
  1615. if (version.empty() || version[0] != '2') {
  1616. throw DeadlyImportError("GLTF: Unsupported glTF version: ", version);
  1617. }
  1618. }
  1619. //
  1620. // Asset methods implementation
  1621. //
  1622. inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData) {
  1623. ASSIMP_LOG_DEBUG("Reading GLTF2 binary");
  1624. GLB_Header header;
  1625. if (stream.Read(&header, sizeof(header), 1) != 1) {
  1626. throw DeadlyImportError("GLTF: Unable to read the file header");
  1627. }
  1628. if (strncmp((char *)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
  1629. throw DeadlyImportError("GLTF: Invalid binary glTF file");
  1630. }
  1631. AI_SWAP4(header.version);
  1632. asset.version = ai_to_string(header.version);
  1633. if (header.version != 2) {
  1634. throw DeadlyImportError("GLTF: Unsupported binary glTF version");
  1635. }
  1636. GLB_Chunk chunk;
  1637. if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
  1638. throw DeadlyImportError("GLTF: Unable to read JSON chunk");
  1639. }
  1640. AI_SWAP4(chunk.chunkLength);
  1641. AI_SWAP4(chunk.chunkType);
  1642. if (chunk.chunkType != ChunkType_JSON) {
  1643. throw DeadlyImportError("GLTF: JSON chunk missing");
  1644. }
  1645. // read the scene data
  1646. mSceneLength = chunk.chunkLength;
  1647. sceneData.resize(mSceneLength + 1);
  1648. sceneData[mSceneLength] = '\0';
  1649. if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
  1650. throw DeadlyImportError("GLTF: Could not read the file contents");
  1651. }
  1652. uint32_t padding = ((chunk.chunkLength + 3) & ~3) - chunk.chunkLength;
  1653. if (padding > 0) {
  1654. stream.Seek(padding, aiOrigin_CUR);
  1655. }
  1656. AI_SWAP4(header.length);
  1657. mBodyOffset = 12 + 8 + chunk.chunkLength + padding + 8;
  1658. if (header.length >= mBodyOffset) {
  1659. if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
  1660. throw DeadlyImportError("GLTF: Unable to read BIN chunk");
  1661. }
  1662. AI_SWAP4(chunk.chunkLength);
  1663. AI_SWAP4(chunk.chunkType);
  1664. if (chunk.chunkType != ChunkType_BIN) {
  1665. throw DeadlyImportError("GLTF: BIN chunk missing");
  1666. }
  1667. mBodyLength = chunk.chunkLength;
  1668. } else {
  1669. mBodyOffset = mBodyLength = 0;
  1670. }
  1671. }
  1672. inline void Asset::Load(const std::string &pFile, bool isBinary) {
  1673. ASSIMP_LOG_DEBUG("Loading GLTF2 asset");
  1674. mCurrentAssetDir.clear();
  1675. /*int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
  1676. if (pos != int(std::string::npos)) */
  1677. if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
  1678. mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile);
  1679. }
  1680. shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
  1681. if (!stream) {
  1682. throw DeadlyImportError("GLTF: Could not open file for reading");
  1683. }
  1684. // is binary? then read the header
  1685. std::vector<char> sceneData;
  1686. if (isBinary) {
  1687. SetAsBinary(); // also creates the body buffer
  1688. ReadBinaryHeader(*stream, sceneData);
  1689. } else {
  1690. mSceneLength = stream->FileSize();
  1691. mBodyLength = 0;
  1692. // read the scene data
  1693. sceneData.resize(mSceneLength + 1);
  1694. sceneData[mSceneLength] = '\0';
  1695. if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
  1696. throw DeadlyImportError("GLTF: Could not read the file contents");
  1697. }
  1698. }
  1699. // parse the JSON document
  1700. ASSIMP_LOG_DEBUG("Parsing GLTF2 JSON");
  1701. Document doc;
  1702. doc.ParseInsitu(&sceneData[0]);
  1703. if (doc.HasParseError()) {
  1704. char buffer[32];
  1705. ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
  1706. throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError()));
  1707. }
  1708. if (!doc.IsObject()) {
  1709. throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
  1710. }
  1711. // Fill the buffer instance for the current file embedded contents
  1712. if (mBodyLength > 0) {
  1713. if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
  1714. throw DeadlyImportError("GLTF: Unable to read gltf file");
  1715. }
  1716. }
  1717. // Load the metadata
  1718. asset.Read(doc);
  1719. ReadExtensionsUsed(doc);
  1720. ReadExtensionsRequired(doc);
  1721. #ifndef ASSIMP_ENABLE_DRACO
  1722. // Is Draco required?
  1723. if (extensionsRequired.KHR_draco_mesh_compression) {
  1724. throw DeadlyImportError("GLTF: Draco mesh compression not supported.");
  1725. }
  1726. #endif
  1727. // Prepare the dictionaries
  1728. for (size_t i = 0; i < mDicts.size(); ++i) {
  1729. mDicts[i]->AttachToDocument(doc);
  1730. }
  1731. // Read the "scene" property, which specifies which scene to load
  1732. // and recursively load everything referenced by it
  1733. unsigned int sceneIndex = 0;
  1734. Value *curScene = FindUInt(doc, "scene");
  1735. if (nullptr != curScene) {
  1736. sceneIndex = curScene->GetUint();
  1737. }
  1738. if (Value *scenesArray = FindArray(doc, "scenes")) {
  1739. if (sceneIndex < scenesArray->Size()) {
  1740. this->scene = scenes.Retrieve(sceneIndex);
  1741. }
  1742. }
  1743. if (Value *skinsArray = FindArray(doc, "skins")) {
  1744. for (unsigned int i = 0; i < skinsArray->Size(); ++i) {
  1745. skins.Retrieve(i);
  1746. }
  1747. }
  1748. if (Value *animsArray = FindArray(doc, "animations")) {
  1749. for (unsigned int i = 0; i < animsArray->Size(); ++i) {
  1750. animations.Retrieve(i);
  1751. }
  1752. }
  1753. // Clean up
  1754. for (size_t i = 0; i < mDicts.size(); ++i) {
  1755. mDicts[i]->DetachFromDocument();
  1756. }
  1757. }
  1758. inline void Asset::SetAsBinary() {
  1759. if (!mBodyBuffer) {
  1760. mBodyBuffer = buffers.Create("binary_glTF");
  1761. mBodyBuffer->MarkAsSpecial();
  1762. }
  1763. }
  1764. // As required extensions are only a concept in glTF 2.0, this is here
  1765. // instead of glTFCommon.h
  1766. #define CHECK_REQUIRED_EXT(EXT) \
  1767. if (exts.find(#EXT) != exts.end()) extensionsRequired.EXT = true;
  1768. inline void Asset::ReadExtensionsRequired(Document &doc) {
  1769. Value *extsRequired = FindArray(doc, "extensionsRequired");
  1770. if (nullptr == extsRequired) {
  1771. return;
  1772. }
  1773. std::gltf_unordered_map<std::string, bool> exts;
  1774. for (unsigned int i = 0; i < extsRequired->Size(); ++i) {
  1775. if ((*extsRequired)[i].IsString()) {
  1776. exts[(*extsRequired)[i].GetString()] = true;
  1777. }
  1778. }
  1779. CHECK_REQUIRED_EXT(KHR_draco_mesh_compression);
  1780. #undef CHECK_REQUIRED_EXT
  1781. }
  1782. inline void Asset::ReadExtensionsUsed(Document &doc) {
  1783. Value *extsUsed = FindArray(doc, "extensionsUsed");
  1784. if (!extsUsed) return;
  1785. std::gltf_unordered_map<std::string, bool> exts;
  1786. for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
  1787. if ((*extsUsed)[i].IsString()) {
  1788. exts[(*extsUsed)[i].GetString()] = true;
  1789. }
  1790. }
  1791. CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
  1792. CHECK_EXT(KHR_materials_unlit);
  1793. CHECK_EXT(KHR_lights_punctual);
  1794. CHECK_EXT(KHR_texture_transform);
  1795. CHECK_EXT(KHR_materials_sheen);
  1796. CHECK_EXT(KHR_materials_clearcoat);
  1797. CHECK_EXT(KHR_materials_transmission);
  1798. CHECK_EXT(KHR_draco_mesh_compression);
  1799. CHECK_EXT(KHR_texture_basisu);
  1800. #undef CHECK_EXT
  1801. }
  1802. inline IOStream *Asset::OpenFile(const std::string& path, const char *mode, bool /*absolute*/) {
  1803. #ifdef ASSIMP_API
  1804. return mIOSystem->Open(path, mode);
  1805. #else
  1806. if (path.size() < 2) return nullptr;
  1807. if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
  1808. path = mCurrentAssetDir + path;
  1809. }
  1810. FILE *f = fopen(path.c_str(), mode);
  1811. return f ? new IOStream(f) : nullptr;
  1812. #endif
  1813. }
  1814. inline std::string Asset::FindUniqueID(const std::string &str, const char *suffix) {
  1815. std::string id = str;
  1816. if (!id.empty()) {
  1817. if (mUsedIds.find(id) == mUsedIds.end())
  1818. return id;
  1819. id += "_";
  1820. }
  1821. id += suffix;
  1822. Asset::IdMap::iterator it = mUsedIds.find(id);
  1823. if (it == mUsedIds.end()) {
  1824. return id;
  1825. }
  1826. std::vector<char> buffer;
  1827. buffer.resize(id.size() + 16);
  1828. int offset = ai_snprintf(buffer.data(), buffer.size(), "%s_", id.c_str());
  1829. for (int i = 0; it != mUsedIds.end(); ++i) {
  1830. ai_snprintf(buffer.data() + offset, buffer.size() - offset, "%d", i);
  1831. id = buffer.data();
  1832. it = mUsedIds.find(id);
  1833. }
  1834. return id;
  1835. }
  1836. #if _MSC_VER
  1837. #pragma warning(pop)
  1838. #endif // _MSC_VER
  1839. } // namespace glTF2