glTF2Asset.inl 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449
  1. /*
  2. Open Asset Import Library (assimp)
  3. ----------------------------------------------------------------------
  4. Copyright (c) 2006-2017, 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 "StringUtils.h"
  34. // Header files, Assimp
  35. #include <assimp/DefaultLogger.hpp>
  36. using namespace Assimp;
  37. namespace glTF2 {
  38. namespace {
  39. //
  40. // JSON Value reading helpers
  41. //
  42. template<class T>
  43. struct ReadHelper { static bool Read(Value& val, T& out) {
  44. return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
  45. }};
  46. template<> struct ReadHelper<bool> { static bool Read(Value& val, bool& out) {
  47. return val.IsBool() ? out = val.GetBool(), true : false;
  48. }};
  49. template<> struct ReadHelper<float> { static bool Read(Value& val, float& out) {
  50. return val.IsNumber() ? out = static_cast<float>(val.GetDouble()), true : false;
  51. }};
  52. template<unsigned int N> struct ReadHelper<float[N]> { static bool Read(Value& val, float (&out)[N]) {
  53. if (!val.IsArray() || val.Size() != N) return false;
  54. for (unsigned int i = 0; i < N; ++i) {
  55. if (val[i].IsNumber())
  56. out[i] = static_cast<float>(val[i].GetDouble());
  57. }
  58. return true;
  59. }};
  60. template<> struct ReadHelper<const char*> { static bool Read(Value& val, const char*& out) {
  61. return val.IsString() ? (out = val.GetString(), true) : false;
  62. }};
  63. template<> struct ReadHelper<std::string> { static bool Read(Value& val, std::string& out) {
  64. return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false;
  65. }};
  66. template<class T> struct ReadHelper< Nullable<T> > { static bool Read(Value& val, Nullable<T>& out) {
  67. return out.isPresent = ReadHelper<T>::Read(val, out.value);
  68. }};
  69. template<class T>
  70. inline static bool ReadValue(Value& val, T& out)
  71. {
  72. return ReadHelper<T>::Read(val, out);
  73. }
  74. template<class T>
  75. inline static bool ReadMember(Value& obj, const char* id, T& out)
  76. {
  77. Value::MemberIterator it = obj.FindMember(id);
  78. if (it != obj.MemberEnd()) {
  79. return ReadHelper<T>::Read(it->value, out);
  80. }
  81. return false;
  82. }
  83. template<class T>
  84. inline static T MemberOrDefault(Value& obj, const char* id, T defaultValue)
  85. {
  86. T out;
  87. return ReadMember(obj, id, out) ? out : defaultValue;
  88. }
  89. inline Value* FindMember(Value& val, const char* id)
  90. {
  91. Value::MemberIterator it = val.FindMember(id);
  92. return (it != val.MemberEnd()) ? &it->value : 0;
  93. }
  94. inline Value* FindString(Value& val, const char* id)
  95. {
  96. Value::MemberIterator it = val.FindMember(id);
  97. return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0;
  98. }
  99. inline Value* FindNumber(Value& val, const char* id)
  100. {
  101. Value::MemberIterator it = val.FindMember(id);
  102. return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0;
  103. }
  104. inline Value* FindUInt(Value& val, const char* id)
  105. {
  106. Value::MemberIterator it = val.FindMember(id);
  107. return (it != val.MemberEnd() && it->value.IsUint()) ? &it->value : 0;
  108. }
  109. inline Value* FindArray(Value& val, const char* id)
  110. {
  111. Value::MemberIterator it = val.FindMember(id);
  112. return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : 0;
  113. }
  114. inline Value* FindObject(Value& val, const char* id)
  115. {
  116. Value::MemberIterator it = val.FindMember(id);
  117. return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : 0;
  118. }
  119. }
  120. //
  121. // LazyDict methods
  122. //
  123. template<class T>
  124. inline LazyDict<T>::LazyDict(Asset& asset, const char* dictId, const char* extId)
  125. : mDictId(dictId), mExtId(extId), mDict(0), mAsset(asset)
  126. {
  127. asset.mDicts.push_back(this); // register to the list of dictionaries
  128. }
  129. template<class T>
  130. inline LazyDict<T>::~LazyDict()
  131. {
  132. for (size_t i = 0; i < mObjs.size(); ++i) {
  133. delete mObjs[i];
  134. }
  135. }
  136. template<class T>
  137. inline void LazyDict<T>::AttachToDocument(Document& doc)
  138. {
  139. Value* container = 0;
  140. if (mExtId) {
  141. if (Value* exts = FindObject(doc, "extensions")) {
  142. container = FindObject(*exts, mExtId);
  143. }
  144. }
  145. else {
  146. container = &doc;
  147. }
  148. if (container) {
  149. mDict = FindArray(*container, mDictId);
  150. }
  151. }
  152. template<class T>
  153. inline void LazyDict<T>::DetachFromDocument()
  154. {
  155. mDict = 0;
  156. }
  157. template<class T>
  158. unsigned int LazyDict<T>::Remove(const char* id)
  159. {
  160. id = T::TranslateId(mAsset, id);
  161. typename IdDict::iterator it = mObjsById.find(id);
  162. if (it == mObjsById.end()) {
  163. throw DeadlyExportError("GLTF: Object with id \"" + std::string(id) + "\" is not found");
  164. }
  165. const unsigned int index = it->second;
  166. mAsset.mUsedIds[id] = false;
  167. mObjsById.erase(id);
  168. mObjsByOIndex.erase(index);
  169. mObjs.erase(mObjs.begin() + index);
  170. //update index of object in mObjs;
  171. for (unsigned int i = index; i < mObjs.size(); ++i) {
  172. T *obj = mObjs[i];
  173. obj->index = i;
  174. }
  175. for (IdDict::iterator it = mObjsById.begin(); it != mObjsById.end(); ++it) {
  176. if (it->second <= index) {
  177. continue;
  178. }
  179. mObjsById[it->first] = it->second - 1;
  180. }
  181. for (Dict::iterator it = mObjsByOIndex.begin(); it != mObjsByOIndex.end(); ++it) {
  182. if (it->second <= index) {
  183. continue;
  184. }
  185. mObjsByOIndex[it->first] = it->second - 1;
  186. }
  187. return index;
  188. }
  189. template<class T>
  190. Ref<T> LazyDict<T>::Retrieve(unsigned int i)
  191. {
  192. typename Dict::iterator it = mObjsByOIndex.find(i);
  193. if (it != mObjsByOIndex.end()) {// already created?
  194. return Ref<T>(mObjs, it->second);
  195. }
  196. // read it from the JSON object
  197. if (!mDict) {
  198. throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\"");
  199. }
  200. if (!mDict->IsArray()) {
  201. throw DeadlyImportError("GLTF: Field is not an array \"" + std::string(mDictId) + "\"");
  202. }
  203. Value &obj = (*mDict)[i];
  204. if (!obj.IsObject()) {
  205. throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object");
  206. }
  207. T* inst = new T();
  208. inst->id = std::string(mDictId) + "_" + to_string(i);
  209. inst->oIndex = i;
  210. ReadMember(obj, "name", inst->name);
  211. inst->Read(obj, mAsset);
  212. return Add(inst);
  213. }
  214. template<class T>
  215. Ref<T> LazyDict<T>::Get(unsigned int i)
  216. {
  217. return Ref<T>(mObjs, i);
  218. }
  219. template<class T>
  220. Ref<T> LazyDict<T>::Get(const char* id)
  221. {
  222. id = T::TranslateId(mAsset, id);
  223. typename IdDict::iterator it = mObjsById.find(id);
  224. if (it != mObjsById.end()) { // already created?
  225. return Ref<T>(mObjs, it->second);
  226. }
  227. return Ref<T>();
  228. }
  229. template<class T>
  230. Ref<T> LazyDict<T>::Add(T* obj)
  231. {
  232. unsigned int idx = unsigned(mObjs.size());
  233. mObjs.push_back(obj);
  234. mObjsByOIndex[obj->oIndex] = idx;
  235. mObjsById[obj->id] = idx;
  236. mAsset.mUsedIds[obj->id] = true;
  237. return Ref<T>(mObjs, idx);
  238. }
  239. template<class T>
  240. Ref<T> LazyDict<T>::Create(const char* id)
  241. {
  242. Asset::IdMap::iterator it = mAsset.mUsedIds.find(id);
  243. if (it != mAsset.mUsedIds.end()) {
  244. throw DeadlyImportError("GLTF: two objects with the same ID exist");
  245. }
  246. T* inst = new T();
  247. unsigned int idx = unsigned(mObjs.size());
  248. inst->id = id;
  249. inst->index = idx;
  250. inst->oIndex = idx;
  251. return Add(inst);
  252. }
  253. //
  254. // glTF dictionary objects methods
  255. //
  256. inline Buffer::Buffer()
  257. : byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false)
  258. { }
  259. inline Buffer::~Buffer()
  260. {
  261. for(SEncodedRegion* reg : EncodedRegion_List) delete reg;
  262. }
  263. inline const char* Buffer::TranslateId(Asset& /*r*/, const char* id)
  264. {
  265. return id;
  266. }
  267. inline void Buffer::Read(Value& obj, Asset& r)
  268. {
  269. size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
  270. byteLength = statedLength;
  271. Value* it = FindString(obj, "uri");
  272. if (!it) {
  273. if (statedLength > 0) {
  274. throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute");
  275. }
  276. return;
  277. }
  278. const char* uri = it->GetString();
  279. Util::DataURI dataURI;
  280. if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
  281. if (dataURI.base64) {
  282. uint8_t* data = 0;
  283. this->byteLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, data);
  284. this->mData.reset(data, std::default_delete<uint8_t[]>());
  285. if (statedLength > 0 && this->byteLength != statedLength) {
  286. throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) +
  287. " bytes, but found " + to_string(dataURI.dataLength));
  288. }
  289. }
  290. else { // assume raw data
  291. if (statedLength != dataURI.dataLength) {
  292. throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) +
  293. " bytes, but found " + to_string(dataURI.dataLength));
  294. }
  295. this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
  296. memcpy( this->mData.get(), dataURI.data, dataURI.dataLength );
  297. }
  298. }
  299. else { // Local file
  300. if (byteLength > 0) {
  301. std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir + "/") : "";
  302. IOStream* file = r.OpenFile(dir + uri, "rb");
  303. if (file) {
  304. bool ok = LoadFromStream(*file, byteLength);
  305. delete file;
  306. if (!ok)
  307. throw DeadlyImportError("GLTF: error while reading referenced file \"" + std::string(uri) + "\"" );
  308. }
  309. else {
  310. throw DeadlyImportError("GLTF: could not open referenced file \"" + std::string(uri) + "\"");
  311. }
  312. }
  313. }
  314. }
  315. inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseOffset)
  316. {
  317. byteLength = length ? length : stream.FileSize();
  318. if (baseOffset) {
  319. stream.Seek(baseOffset, aiOrigin_SET);
  320. }
  321. mData.reset(new uint8_t[byteLength], std::default_delete<uint8_t[]>());
  322. if (stream.Read(mData.get(), byteLength, 1) != 1) {
  323. return false;
  324. }
  325. return true;
  326. }
  327. 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)
  328. {
  329. // Check pointer to data
  330. if(pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided.");
  331. // Check offset
  332. if(pOffset > byteLength)
  333. {
  334. const uint8_t val_size = 32;
  335. char val[val_size];
  336. ai_snprintf(val, val_size, "%llu", (long long)pOffset);
  337. throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region.");
  338. }
  339. // Check length
  340. if((pOffset + pEncodedData_Length) > byteLength)
  341. {
  342. const uint8_t val_size = 64;
  343. char val[val_size];
  344. ai_snprintf(val, val_size, "%llu, %llu", (long long)pOffset, (long long)pEncodedData_Length);
  345. throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range.");
  346. }
  347. // Add new region
  348. EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID));
  349. // And set new value for "byteLength"
  350. byteLength += (pDecodedData_Length - pEncodedData_Length);
  351. }
  352. inline void Buffer::EncodedRegion_SetCurrent(const std::string& pID)
  353. {
  354. if((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return;
  355. for(SEncodedRegion* reg : EncodedRegion_List)
  356. {
  357. if(reg->ID == pID)
  358. {
  359. EncodedRegion_Current = reg;
  360. return;
  361. }
  362. }
  363. throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found.");
  364. }
  365. inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
  366. {
  367. const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
  368. uint8_t* new_data;
  369. if((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) return false;
  370. new_data = new uint8_t[new_data_size];
  371. // Copy data which place before replacing part.
  372. memcpy(new_data, mData.get(), pBufferData_Offset);
  373. // Copy new data.
  374. memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
  375. // Copy data which place after replacing part.
  376. memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset);
  377. // Apply new data
  378. mData.reset(new_data, std::default_delete<uint8_t[]>());
  379. byteLength = new_data_size;
  380. return true;
  381. }
  382. inline size_t Buffer::AppendData(uint8_t* data, size_t length)
  383. {
  384. size_t offset = this->byteLength;
  385. Grow(length);
  386. memcpy(mData.get() + offset, data, length);
  387. return offset;
  388. }
  389. inline void Buffer::Grow(size_t amount)
  390. {
  391. if (amount <= 0) return;
  392. uint8_t* b = new uint8_t[byteLength + amount];
  393. if (mData) memcpy(b, mData.get(), byteLength);
  394. mData.reset(b, std::default_delete<uint8_t[]>());
  395. byteLength += amount;
  396. }
  397. //
  398. // struct BufferView
  399. //
  400. inline void BufferView::Read(Value& obj, Asset& r)
  401. {
  402. if (Value* bufferVal = FindUInt(obj, "buffer")) {
  403. buffer = r.buffers.Retrieve(bufferVal->GetUint());
  404. }
  405. byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
  406. byteLength = MemberOrDefault(obj, "byteLength", 0u);
  407. byteStride = MemberOrDefault(obj, "byteStride", 0u);
  408. }
  409. //
  410. // struct Accessor
  411. //
  412. inline void Accessor::Read(Value& obj, Asset& r)
  413. {
  414. if (Value* bufferViewVal = FindUInt(obj, "bufferView")) {
  415. bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
  416. }
  417. byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
  418. componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
  419. count = MemberOrDefault(obj, "count", 0u);
  420. const char* typestr;
  421. type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
  422. }
  423. inline unsigned int Accessor::GetNumComponents()
  424. {
  425. return AttribType::GetNumComponents(type);
  426. }
  427. inline unsigned int Accessor::GetBytesPerComponent()
  428. {
  429. return int(ComponentTypeSize(componentType));
  430. }
  431. inline unsigned int Accessor::GetElementSize()
  432. {
  433. return GetNumComponents() * GetBytesPerComponent();
  434. }
  435. inline uint8_t* Accessor::GetPointer()
  436. {
  437. if (!bufferView || !bufferView->buffer) return 0;
  438. uint8_t* basePtr = bufferView->buffer->GetPointer();
  439. if (!basePtr) return 0;
  440. size_t offset = byteOffset + bufferView->byteOffset;
  441. // Check if region is encoded.
  442. if(bufferView->buffer->EncodedRegion_Current != nullptr)
  443. {
  444. const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
  445. const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
  446. if((offset >= begin) && (offset < end))
  447. return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
  448. }
  449. return basePtr + offset;
  450. }
  451. namespace {
  452. inline void CopyData(size_t count,
  453. const uint8_t* src, size_t src_stride,
  454. uint8_t* dst, size_t dst_stride)
  455. {
  456. if (src_stride == dst_stride) {
  457. memcpy(dst, src, count * src_stride);
  458. }
  459. else {
  460. size_t sz = std::min(src_stride, dst_stride);
  461. for (size_t i = 0; i < count; ++i) {
  462. memcpy(dst, src, sz);
  463. if (sz < dst_stride) {
  464. memset(dst + sz, 0, dst_stride - sz);
  465. }
  466. src += src_stride;
  467. dst += dst_stride;
  468. }
  469. }
  470. }
  471. }
  472. template<class T>
  473. bool Accessor::ExtractData(T*& outData)
  474. {
  475. uint8_t* data = GetPointer();
  476. if (!data) return false;
  477. const size_t elemSize = GetElementSize();
  478. const size_t totalSize = elemSize * count;
  479. const size_t stride = bufferView && bufferView->byteStride ? bufferView->byteStride : elemSize;
  480. const size_t targetElemSize = sizeof(T);
  481. ai_assert(elemSize <= targetElemSize);
  482. ai_assert(count*stride <= bufferView->byteLength);
  483. outData = new T[count];
  484. if (stride == elemSize && targetElemSize == elemSize) {
  485. memcpy(outData, data, totalSize);
  486. }
  487. else {
  488. for (size_t i = 0; i < count; ++i) {
  489. memcpy(outData + i, data + i*stride, elemSize);
  490. }
  491. }
  492. return true;
  493. }
  494. inline void Accessor::WriteData(size_t count, const void* src_buffer, size_t src_stride)
  495. {
  496. uint8_t* buffer_ptr = bufferView->buffer->GetPointer();
  497. size_t offset = byteOffset + bufferView->byteOffset;
  498. size_t dst_stride = GetNumComponents() * GetBytesPerComponent();
  499. const uint8_t* src = reinterpret_cast<const uint8_t*>(src_buffer);
  500. uint8_t* dst = reinterpret_cast< uint8_t*>(buffer_ptr + offset);
  501. ai_assert(dst + count*dst_stride <= buffer_ptr + bufferView->buffer->byteLength);
  502. CopyData(count, src, src_stride, dst, dst_stride);
  503. }
  504. inline Accessor::Indexer::Indexer(Accessor& acc)
  505. : accessor(acc)
  506. , data(acc.GetPointer())
  507. , elemSize(acc.GetElementSize())
  508. , stride(acc.bufferView && acc.bufferView->byteStride ? acc.bufferView->byteStride : elemSize)
  509. {
  510. }
  511. //! Accesses the i-th value as defined by the accessor
  512. template<class T>
  513. T Accessor::Indexer::GetValue(int i)
  514. {
  515. ai_assert(data);
  516. ai_assert(i*stride < accessor.bufferView->byteLength);
  517. T value = T();
  518. memcpy(&value, data + i*stride, elemSize);
  519. //value >>= 8 * (sizeof(T) - elemSize);
  520. return value;
  521. }
  522. inline Image::Image()
  523. : width(0)
  524. , height(0)
  525. , mData(0)
  526. , mDataLength(0)
  527. {
  528. }
  529. inline void Image::Read(Value& obj, Asset& /*r*/)
  530. {
  531. if (!mDataLength) {
  532. if (Value* uri = FindString(obj, "uri")) {
  533. const char* uristr = uri->GetString();
  534. Util::DataURI dataURI;
  535. if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) {
  536. mimeType = dataURI.mediaType;
  537. if (dataURI.base64) {
  538. mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, mData);
  539. }
  540. }
  541. else {
  542. this->uri = uristr;
  543. }
  544. }
  545. }
  546. }
  547. inline uint8_t* Image::StealData()
  548. {
  549. uint8_t* data = mData;
  550. mDataLength = 0;
  551. mData = 0;
  552. return data;
  553. }
  554. inline void Image::SetData(uint8_t* data, size_t length, Asset& r)
  555. {
  556. Ref<Buffer> b = r.GetBodyBuffer();
  557. if (b) { // binary file: append to body
  558. std::string bvId = r.FindUniqueID(this->id, "imgdata");
  559. bufferView = r.bufferViews.Create(bvId);
  560. bufferView->buffer = b;
  561. bufferView->byteLength = length;
  562. bufferView->byteOffset = b->AppendData(data, length);
  563. }
  564. else { // text file: will be stored as a data uri
  565. this->mData = data;
  566. this->mDataLength = length;
  567. }
  568. }
  569. inline void Sampler::Read(Value& obj, Asset& /*r*/)
  570. {
  571. SetDefaults();
  572. ReadMember(obj, "name", name);
  573. ReadMember(obj, "magFilter", magFilter);
  574. ReadMember(obj, "minFilter", minFilter);
  575. ReadMember(obj, "wrapS", wrapS);
  576. ReadMember(obj, "wrapT", wrapT);
  577. }
  578. inline void Sampler::SetDefaults()
  579. {
  580. //only wrapping modes have defaults
  581. wrapS = SamplerWrap::Repeat;
  582. wrapT = SamplerWrap::Repeat;
  583. magFilter = SamplerMagFilter::UNSET;
  584. minFilter = SamplerMinFilter::UNSET;
  585. }
  586. inline void Texture::Read(Value& obj, Asset& r)
  587. {
  588. if (Value* sourceVal = FindUInt(obj, "source")) {
  589. source = r.images.Retrieve(sourceVal->GetUint());
  590. }
  591. if (Value* samplerVal = FindUInt(obj, "sampler")) {
  592. sampler = r.samplers.Retrieve(samplerVal->GetUint());
  593. }
  594. }
  595. namespace {
  596. inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out)
  597. {
  598. if (Value* index = FindUInt(*prop, "index")) {
  599. out.texture = r.textures.Retrieve(index->GetUint());
  600. }
  601. if (Value* texcoord = FindUInt(*prop, "texCoord")) {
  602. out.texCoord = texcoord->GetUint();
  603. }
  604. }
  605. inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, TextureInfo& out)
  606. {
  607. if (Value* prop = FindMember(vals, propName)) {
  608. SetTextureProperties(r, prop, out);
  609. }
  610. }
  611. inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, NormalTextureInfo& out)
  612. {
  613. if (Value* prop = FindMember(vals, propName)) {
  614. SetTextureProperties(r, prop, out);
  615. if (Value* scale = FindNumber(*prop, "scale")) {
  616. out.scale = static_cast<float>(scale->GetDouble());
  617. }
  618. }
  619. }
  620. inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, OcclusionTextureInfo& out)
  621. {
  622. if (Value* prop = FindMember(vals, propName)) {
  623. SetTextureProperties(r, prop, out);
  624. if (Value* strength = FindNumber(*prop, "strength")) {
  625. out.strength = static_cast<float>(strength->GetDouble());
  626. }
  627. }
  628. }
  629. }
  630. inline void Material::Read(Value& material, Asset& r)
  631. {
  632. SetDefaults();
  633. if (Value* pbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) {
  634. ReadMember(*pbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor);
  635. ReadTextureProperty(r, *pbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture);
  636. ReadTextureProperty(r, *pbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture);
  637. ReadMember(*pbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor);
  638. ReadMember(*pbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor);
  639. }
  640. ReadTextureProperty(r, material, "normalTexture", this->normalTexture);
  641. ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture);
  642. ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture);
  643. ReadMember(material, "emissiveFactor", this->emissiveFactor);
  644. ReadMember(material, "doubleSided", this->doubleSided);
  645. ReadMember(material, "alphaMode", this->alphaMode);
  646. ReadMember(material, "alphaCutoff", this->alphaCutoff);
  647. if (Value* extensions = FindObject(material, "extensions")) {
  648. if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
  649. if (Value* pbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) {
  650. PbrSpecularGlossiness pbrSG;
  651. ReadMember(*pbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor);
  652. ReadTextureProperty(r, *pbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture);
  653. ReadTextureProperty(r, *pbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture);
  654. ReadMember(*pbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor);
  655. ReadMember(*pbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor);
  656. this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
  657. }
  658. }
  659. }
  660. }
  661. namespace {
  662. void SetVector(vec4& v, const float(&in)[4])
  663. { v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; v[3] = in[3]; }
  664. void SetVector(vec3& v, const float(&in)[3])
  665. { v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; }
  666. }
  667. inline void Material::SetDefaults()
  668. {
  669. //pbr materials
  670. SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
  671. pbrMetallicRoughness.metallicFactor = 1.0;
  672. pbrMetallicRoughness.roughnessFactor = 1.0;
  673. SetVector(emissiveFactor, defaultEmissiveFactor);
  674. alphaMode = "OPAQUE";
  675. alphaCutoff = 0.5;
  676. doubleSided = false;
  677. }
  678. inline void PbrSpecularGlossiness::SetDefaults()
  679. {
  680. //pbrSpecularGlossiness properties
  681. SetVector(diffuseFactor, defaultDiffuseFactor);
  682. SetVector(specularFactor, defaultSpecularFactor);
  683. glossinessFactor = 1.0;
  684. }
  685. namespace {
  686. template<int N>
  687. inline int Compare(const char* attr, const char (&str)[N]) {
  688. return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
  689. }
  690. inline bool GetAttribVector(Mesh::Primitive& p, const char* attr, Mesh::AccessorList*& v, int& pos)
  691. {
  692. if ((pos = Compare(attr, "POSITION"))) {
  693. v = &(p.attributes.position);
  694. }
  695. else if ((pos = Compare(attr, "NORMAL"))) {
  696. v = &(p.attributes.normal);
  697. }
  698. else if ((pos = Compare(attr, "TANGENT"))) {
  699. v = &(p.attributes.tangent);
  700. }
  701. else if ((pos = Compare(attr, "TEXCOORD"))) {
  702. v = &(p.attributes.texcoord);
  703. }
  704. else if ((pos = Compare(attr, "COLOR"))) {
  705. v = &(p.attributes.color);
  706. }
  707. else if ((pos = Compare(attr, "JOINT"))) {
  708. v = &(p.attributes.joint);
  709. }
  710. else if ((pos = Compare(attr, "JOINTMATRIX"))) {
  711. v = &(p.attributes.jointmatrix);
  712. }
  713. else if ((pos = Compare(attr, "WEIGHT"))) {
  714. v = &(p.attributes.weight);
  715. }
  716. else return false;
  717. return true;
  718. }
  719. }
  720. inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
  721. {
  722. if (Value* name = FindMember(pJSON_Object, "name")) {
  723. this->name = name->GetString();
  724. }
  725. /****************** Mesh primitives ******************/
  726. if (Value* primitives = FindArray(pJSON_Object, "primitives")) {
  727. this->primitives.resize(primitives->Size());
  728. for (unsigned int i = 0; i < primitives->Size(); ++i) {
  729. Value& primitive = (*primitives)[i];
  730. Primitive& prim = this->primitives[i];
  731. prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
  732. if (Value* attrs = FindObject(primitive, "attributes")) {
  733. for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
  734. if (!it->value.IsUint()) continue;
  735. const char* attr = it->name.GetString();
  736. // Valid attribute semantics include POSITION, NORMAL, TANGENT, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
  737. // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
  738. int undPos = 0;
  739. Mesh::AccessorList* vec = 0;
  740. if (GetAttribVector(prim, attr, vec, undPos)) {
  741. size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
  742. if ((*vec).size() <= idx) (*vec).resize(idx + 1);
  743. (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
  744. }
  745. }
  746. }
  747. if (Value* indices = FindUInt(primitive, "indices")) {
  748. prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
  749. }
  750. if (Value* material = FindUInt(primitive, "material")) {
  751. prim.material = pAsset_Root.materials.Retrieve(material->GetUint());
  752. }
  753. }
  754. }
  755. }
  756. inline void Camera::Read(Value& obj, Asset& /*r*/)
  757. {
  758. type = MemberOrDefault(obj, "type", Camera::Perspective);
  759. const char* subobjId = (type == Camera::Orthographic) ? "orthographic" : "perspective";
  760. Value* it = FindObject(obj, subobjId);
  761. if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters");
  762. if (type == Camera::Perspective) {
  763. cameraProperties.perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
  764. cameraProperties.perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f/2.f);
  765. cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
  766. cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
  767. }
  768. else {
  769. cameraProperties.ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f);
  770. cameraProperties.ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f);
  771. cameraProperties.ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f);
  772. cameraProperties.ortographic.znear = MemberOrDefault(obj, "znear", 0.01f);
  773. }
  774. }
  775. inline void Node::Read(Value& obj, Asset& r)
  776. {
  777. if (Value* children = FindArray(obj, "children")) {
  778. this->children.reserve(children->Size());
  779. for (unsigned int i = 0; i < children->Size(); ++i) {
  780. Value& child = (*children)[i];
  781. if (child.IsUint()) {
  782. // get/create the child node
  783. Ref<Node> chn = r.nodes.Retrieve(child.GetUint());
  784. if (chn) this->children.push_back(chn);
  785. }
  786. }
  787. }
  788. if (Value* matrix = FindArray(obj, "matrix")) {
  789. ReadValue(*matrix, this->matrix);
  790. }
  791. else {
  792. ReadMember(obj, "translation", translation);
  793. ReadMember(obj, "scale", scale);
  794. ReadMember(obj, "rotation", rotation);
  795. }
  796. if (Value* mesh = FindUInt(obj, "mesh")) {
  797. unsigned numMeshes = 1;
  798. this->meshes.reserve(numMeshes);
  799. Ref<Mesh> meshRef = r.meshes.Retrieve((*mesh).GetUint());
  800. if (meshRef) this->meshes.push_back(meshRef);
  801. }
  802. if (Value* camera = FindUInt(obj, "camera")) {
  803. this->camera = r.cameras.Retrieve(camera->GetUint());
  804. if (this->camera)
  805. this->camera->id = this->id;
  806. }
  807. }
  808. inline void Scene::Read(Value& obj, Asset& r)
  809. {
  810. if (Value* array = FindArray(obj, "nodes")) {
  811. for (unsigned int i = 0; i < array->Size(); ++i) {
  812. if (!(*array)[i].IsUint()) continue;
  813. Ref<Node> node = r.nodes.Retrieve((*array)[i].GetUint());
  814. if (node)
  815. this->nodes.push_back(node);
  816. }
  817. }
  818. }
  819. inline void AssetMetadata::Read(Document& doc)
  820. {
  821. if (Value* obj = FindObject(doc, "asset")) {
  822. ReadMember(*obj, "copyright", copyright);
  823. ReadMember(*obj, "generator", generator);
  824. if (Value* versionString = FindString(*obj, "version")) {
  825. version = versionString->GetString();
  826. } else if (Value* versionNumber = FindNumber (*obj, "version")) {
  827. char buf[4];
  828. ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
  829. version = buf;
  830. }
  831. if (Value* profile = FindObject(*obj, "profile")) {
  832. ReadMember(*profile, "api", this->profile.api);
  833. ReadMember(*profile, "version", this->profile.version);
  834. }
  835. }
  836. if (version.empty() || version[0] != '2') {
  837. throw DeadlyImportError("GLTF: Unsupported glTF version: " + version);
  838. }
  839. }
  840. //
  841. // Asset methods implementation
  842. //
  843. inline void Asset::ReadBinaryHeader(IOStream& stream, std::vector<char>& sceneData)
  844. {
  845. GLB_Header header;
  846. if (stream.Read(&header, sizeof(header), 1) != 1) {
  847. throw DeadlyImportError("GLTF: Unable to read the file header");
  848. }
  849. if (strncmp((char*)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
  850. throw DeadlyImportError("GLTF: Invalid binary glTF file");
  851. }
  852. AI_SWAP4(header.version);
  853. asset.version = to_string(header.version);
  854. if (header.version != 2) {
  855. throw DeadlyImportError("GLTF: Unsupported binary glTF version");
  856. }
  857. GLB_Chunk chunk;
  858. if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
  859. throw DeadlyImportError("GLTF: Unable to read JSON chunk");
  860. }
  861. AI_SWAP4(chunk.chunkLength);
  862. AI_SWAP4(chunk.chunkType);
  863. if (chunk.chunkType != ChunkType_JSON) {
  864. throw DeadlyImportError("GLTF: JSON chunk missing");
  865. }
  866. // read the scene data
  867. mSceneLength = chunk.chunkLength;
  868. sceneData.resize(mSceneLength + 1);
  869. sceneData[mSceneLength] = '\0';
  870. if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
  871. throw DeadlyImportError("GLTF: Could not read the file contents");
  872. }
  873. uint32_t padding = ((chunk.chunkLength + 3) & ~3) - chunk.chunkLength;
  874. if (padding > 0) {
  875. stream.Seek(padding, aiOrigin_CUR);
  876. }
  877. AI_SWAP4(header.length);
  878. mBodyOffset = 12 + 8 + chunk.chunkLength + padding + 8;
  879. if (header.length >= mBodyOffset) {
  880. if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
  881. throw DeadlyImportError("GLTF: Unable to read BIN chunk");
  882. }
  883. AI_SWAP4(chunk.chunkLength);
  884. AI_SWAP4(chunk.chunkType);
  885. if (chunk.chunkType != ChunkType_BIN) {
  886. throw DeadlyImportError("GLTF: BIN chunk missing");
  887. }
  888. mBodyLength = chunk.chunkLength;
  889. }
  890. else {
  891. mBodyOffset = mBodyLength = 0;
  892. }
  893. }
  894. inline void Asset::Load(const std::string& pFile, bool isBinary)
  895. {
  896. mCurrentAssetDir.clear();
  897. int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
  898. if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1);
  899. shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
  900. if (!stream) {
  901. throw DeadlyImportError("GLTF: Could not open file for reading");
  902. }
  903. // is binary? then read the header
  904. std::vector<char> sceneData;
  905. if (isBinary) {
  906. SetAsBinary(); // also creates the body buffer
  907. ReadBinaryHeader(*stream, sceneData);
  908. }
  909. else {
  910. mSceneLength = stream->FileSize();
  911. mBodyLength = 0;
  912. // read the scene data
  913. sceneData.resize(mSceneLength + 1);
  914. sceneData[mSceneLength] = '\0';
  915. if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
  916. throw DeadlyImportError("GLTF: Could not read the file contents");
  917. }
  918. }
  919. // parse the JSON document
  920. Document doc;
  921. doc.ParseInsitu(&sceneData[0]);
  922. if (doc.HasParseError()) {
  923. char buffer[32];
  924. ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
  925. throw DeadlyImportError(std::string("GLTF: JSON parse error, offset ") + buffer + ": "
  926. + GetParseError_En(doc.GetParseError()));
  927. }
  928. if (!doc.IsObject()) {
  929. throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
  930. }
  931. // Fill the buffer instance for the current file embedded contents
  932. if (mBodyLength > 0) {
  933. if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
  934. throw DeadlyImportError("GLTF: Unable to read gltf file");
  935. }
  936. }
  937. // Load the metadata
  938. asset.Read(doc);
  939. ReadExtensionsUsed(doc);
  940. // Prepare the dictionaries
  941. for (size_t i = 0; i < mDicts.size(); ++i) {
  942. mDicts[i]->AttachToDocument(doc);
  943. }
  944. // Read the "scene" property, which specifies which scene to load
  945. // and recursively load everything referenced by it
  946. if (Value* scene = FindUInt(doc, "scene")) {
  947. unsigned int sceneIndex = scene->GetUint();
  948. Ref<Scene> s = scenes.Retrieve(sceneIndex);
  949. this->scene = s;
  950. }
  951. // Clean up
  952. for (size_t i = 0; i < mDicts.size(); ++i) {
  953. mDicts[i]->DetachFromDocument();
  954. }
  955. }
  956. inline void Asset::SetAsBinary()
  957. {
  958. if (!mBodyBuffer) {
  959. mBodyBuffer = buffers.Create("binary_glTF");
  960. mBodyBuffer->MarkAsSpecial();
  961. }
  962. }
  963. inline void Asset::ReadExtensionsUsed(Document& doc)
  964. {
  965. Value* extsUsed = FindArray(doc, "extensionsUsed");
  966. if (!extsUsed) return;
  967. std::gltf_unordered_map<std::string, bool> exts;
  968. for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
  969. if ((*extsUsed)[i].IsString()) {
  970. exts[(*extsUsed)[i].GetString()] = true;
  971. }
  972. }
  973. #define CHECK_EXT(EXT) \
  974. if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
  975. CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
  976. #undef CHECK_EXT
  977. }
  978. inline IOStream* Asset::OpenFile(std::string path, const char* mode, bool /*absolute*/)
  979. {
  980. #ifdef ASSIMP_API
  981. return mIOSystem->Open(path, mode);
  982. #else
  983. if (path.size() < 2) return 0;
  984. if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
  985. path = mCurrentAssetDir + path;
  986. }
  987. FILE* f = fopen(path.c_str(), mode);
  988. return f ? new IOStream(f) : 0;
  989. #endif
  990. }
  991. inline std::string Asset::FindUniqueID(const std::string& str, const char* suffix)
  992. {
  993. std::string id = str;
  994. if (!id.empty()) {
  995. if (mUsedIds.find(id) == mUsedIds.end())
  996. return id;
  997. id += "_";
  998. }
  999. id += suffix;
  1000. Asset::IdMap::iterator it = mUsedIds.find(id);
  1001. if (it == mUsedIds.end())
  1002. return id;
  1003. std::vector<char> buffer;
  1004. buffer.resize(id.size() + 16);
  1005. int offset = ai_snprintf(buffer.data(), buffer.size(), "%s_", id.c_str());
  1006. for (int i = 0; it != mUsedIds.end(); ++i) {
  1007. ai_snprintf(buffer.data() + offset, buffer.size() - offset, "%d", i);
  1008. id = buffer.data();
  1009. it = mUsedIds.find(id);
  1010. }
  1011. return id;
  1012. }
  1013. namespace Util {
  1014. inline
  1015. bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) {
  1016. if ( NULL == const_uri ) {
  1017. return false;
  1018. }
  1019. if (const_uri[0] != 0x10) { // we already parsed this uri?
  1020. if (strncmp(const_uri, "data:", 5) != 0) // not a data uri?
  1021. return false;
  1022. }
  1023. // set defaults
  1024. out.mediaType = "text/plain";
  1025. out.charset = "US-ASCII";
  1026. out.base64 = false;
  1027. char* uri = const_cast<char*>(const_uri);
  1028. if (uri[0] != 0x10) {
  1029. uri[0] = 0x10;
  1030. uri[1] = uri[2] = uri[3] = uri[4] = 0;
  1031. size_t i = 5, j;
  1032. if (uri[i] != ';' && uri[i] != ',') { // has media type?
  1033. uri[1] = char(i);
  1034. for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) {
  1035. // nothing to do!
  1036. }
  1037. }
  1038. while (uri[i] == ';' && i < uriLen) {
  1039. uri[i++] = '\0';
  1040. for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) {
  1041. // nothing to do!
  1042. }
  1043. if ( strncmp( uri + j, "charset=", 8 ) == 0 ) {
  1044. uri[2] = char(j + 8);
  1045. } else if ( strncmp( uri + j, "base64", 6 ) == 0 ) {
  1046. uri[3] = char(j);
  1047. }
  1048. }
  1049. if (i < uriLen) {
  1050. uri[i++] = '\0';
  1051. uri[4] = char(i);
  1052. } else {
  1053. uri[1] = uri[2] = uri[3] = 0;
  1054. uri[4] = 5;
  1055. }
  1056. }
  1057. if ( uri[ 1 ] != 0 ) {
  1058. out.mediaType = uri + uri[ 1 ];
  1059. }
  1060. if ( uri[ 2 ] != 0 ) {
  1061. out.charset = uri + uri[ 2 ];
  1062. }
  1063. if ( uri[ 3 ] != 0 ) {
  1064. out.base64 = true;
  1065. }
  1066. out.data = uri + uri[4];
  1067. out.dataLength = (uri + uriLen) - out.data;
  1068. return true;
  1069. }
  1070. template<bool B>
  1071. struct DATA
  1072. {
  1073. static const uint8_t tableDecodeBase64[128];
  1074. };
  1075. template<bool B>
  1076. const uint8_t DATA<B>::tableDecodeBase64[128] = {
  1077. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1078. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1079. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
  1080. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0,
  1081. 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  1082. 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
  1083. 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  1084. 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0
  1085. };
  1086. inline char EncodeCharBase64(uint8_t b)
  1087. {
  1088. return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)];
  1089. }
  1090. inline uint8_t DecodeCharBase64(char c)
  1091. {
  1092. return DATA<true>::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs?
  1093. /*if (c >= 'A' && c <= 'Z') return c - 'A';
  1094. if (c >= 'a' && c <= 'z') return c - 'a' + 26;
  1095. if (c >= '0' && c <= '9') return c - '0' + 52;
  1096. if (c == '+') return 62;
  1097. if (c == '/') return 63;
  1098. return 64; // '-' */
  1099. }
  1100. inline size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out)
  1101. {
  1102. ai_assert(inLength % 4 == 0);
  1103. if (inLength < 4) {
  1104. out = 0;
  1105. return 0;
  1106. }
  1107. int nEquals = int(in[inLength - 1] == '=') +
  1108. int(in[inLength - 2] == '=');
  1109. size_t outLength = (inLength * 3) / 4 - nEquals;
  1110. out = new uint8_t[outLength];
  1111. memset(out, 0, outLength);
  1112. size_t i, j = 0;
  1113. for (i = 0; i + 4 < inLength; i += 4) {
  1114. uint8_t b0 = DecodeCharBase64(in[i]);
  1115. uint8_t b1 = DecodeCharBase64(in[i + 1]);
  1116. uint8_t b2 = DecodeCharBase64(in[i + 2]);
  1117. uint8_t b3 = DecodeCharBase64(in[i + 3]);
  1118. out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
  1119. out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
  1120. out[j++] = (uint8_t)((b2 << 6) | b3);
  1121. }
  1122. {
  1123. uint8_t b0 = DecodeCharBase64(in[i]);
  1124. uint8_t b1 = DecodeCharBase64(in[i + 1]);
  1125. uint8_t b2 = DecodeCharBase64(in[i + 2]);
  1126. uint8_t b3 = DecodeCharBase64(in[i + 3]);
  1127. out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
  1128. if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
  1129. if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3);
  1130. }
  1131. return outLength;
  1132. }
  1133. inline void EncodeBase64(
  1134. const uint8_t* in, size_t inLength,
  1135. std::string& out)
  1136. {
  1137. size_t outLength = ((inLength + 2) / 3) * 4;
  1138. size_t j = out.size();
  1139. out.resize(j + outLength);
  1140. for (size_t i = 0; i < inLength; i += 3) {
  1141. uint8_t b = (in[i] & 0xFC) >> 2;
  1142. out[j++] = EncodeCharBase64(b);
  1143. b = (in[i] & 0x03) << 4;
  1144. if (i + 1 < inLength) {
  1145. b |= (in[i + 1] & 0xF0) >> 4;
  1146. out[j++] = EncodeCharBase64(b);
  1147. b = (in[i + 1] & 0x0F) << 2;
  1148. if (i + 2 < inLength) {
  1149. b |= (in[i + 2] & 0xC0) >> 6;
  1150. out[j++] = EncodeCharBase64(b);
  1151. b = in[i + 2] & 0x3F;
  1152. out[j++] = EncodeCharBase64(b);
  1153. }
  1154. else {
  1155. out[j++] = EncodeCharBase64(b);
  1156. out[j++] = '=';
  1157. }
  1158. }
  1159. else {
  1160. out[j++] = EncodeCharBase64(b);
  1161. out[j++] = '=';
  1162. out[j++] = '=';
  1163. }
  1164. }
  1165. }
  1166. }
  1167. } // ns glTF