summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/assimp/code/glTF2Asset.inl
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/assimp/code/glTF2Asset.inl')
-rw-r--r--src/3rdparty/assimp/code/glTF2Asset.inl1449
1 files changed, 0 insertions, 1449 deletions
diff --git a/src/3rdparty/assimp/code/glTF2Asset.inl b/src/3rdparty/assimp/code/glTF2Asset.inl
deleted file mode 100644
index 549df747e..000000000
--- a/src/3rdparty/assimp/code/glTF2Asset.inl
+++ /dev/null
@@ -1,1449 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2017, assimp team
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
-copyright notice, this list of conditions and the
-following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the
-following disclaimer in the documentation and/or other
-materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
-contributors may be used to endorse or promote products
-derived from this software without specific prior
-written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-#include "StringUtils.h"
-
-// Header files, Assimp
-#include <assimp/DefaultLogger.hpp>
-
-using namespace Assimp;
-
-namespace glTF2 {
-
-namespace {
-
- //
- // JSON Value reading helpers
- //
-
- template<class T>
- struct ReadHelper { static bool Read(Value& val, T& out) {
- return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
- }};
-
- template<> struct ReadHelper<bool> { static bool Read(Value& val, bool& out) {
- return val.IsBool() ? out = val.GetBool(), true : false;
- }};
-
- template<> struct ReadHelper<float> { static bool Read(Value& val, float& out) {
- return val.IsNumber() ? out = static_cast<float>(val.GetDouble()), true : false;
- }};
-
- template<unsigned int N> struct ReadHelper<float[N]> { static bool Read(Value& val, float (&out)[N]) {
- if (!val.IsArray() || val.Size() != N) return false;
- for (unsigned int i = 0; i < N; ++i) {
- if (val[i].IsNumber())
- out[i] = static_cast<float>(val[i].GetDouble());
- }
- return true;
- }};
-
- template<> struct ReadHelper<const char*> { static bool Read(Value& val, const char*& out) {
- return val.IsString() ? (out = val.GetString(), true) : false;
- }};
-
- template<> struct ReadHelper<std::string> { static bool Read(Value& val, std::string& out) {
- return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false;
- }};
-
- template<class T> struct ReadHelper< Nullable<T> > { static bool Read(Value& val, Nullable<T>& out) {
- return out.isPresent = ReadHelper<T>::Read(val, out.value);
- }};
-
- template<class T>
- inline static bool ReadValue(Value& val, T& out)
- {
- return ReadHelper<T>::Read(val, out);
- }
-
- template<class T>
- inline static bool ReadMember(Value& obj, const char* id, T& out)
- {
- Value::MemberIterator it = obj.FindMember(id);
- if (it != obj.MemberEnd()) {
- return ReadHelper<T>::Read(it->value, out);
- }
- return false;
- }
-
- template<class T>
- inline static T MemberOrDefault(Value& obj, const char* id, T defaultValue)
- {
- T out;
- return ReadMember(obj, id, out) ? out : defaultValue;
- }
-
- inline Value* FindMember(Value& val, const char* id)
- {
- Value::MemberIterator it = val.FindMember(id);
- return (it != val.MemberEnd()) ? &it->value : 0;
- }
-
- inline Value* FindString(Value& val, const char* id)
- {
- Value::MemberIterator it = val.FindMember(id);
- return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0;
- }
-
- inline Value* FindNumber(Value& val, const char* id)
- {
- Value::MemberIterator it = val.FindMember(id);
- return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0;
- }
-
- inline Value* FindUInt(Value& val, const char* id)
- {
- Value::MemberIterator it = val.FindMember(id);
- return (it != val.MemberEnd() && it->value.IsUint()) ? &it->value : 0;
- }
-
- inline Value* FindArray(Value& val, const char* id)
- {
- Value::MemberIterator it = val.FindMember(id);
- return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : 0;
- }
-
- inline Value* FindObject(Value& val, const char* id)
- {
- Value::MemberIterator it = val.FindMember(id);
- return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : 0;
- }
-}
-
-//
-// LazyDict methods
-//
-
-template<class T>
-inline LazyDict<T>::LazyDict(Asset& asset, const char* dictId, const char* extId)
- : mDictId(dictId), mExtId(extId), mDict(0), mAsset(asset)
-{
- asset.mDicts.push_back(this); // register to the list of dictionaries
-}
-
-template<class T>
-inline LazyDict<T>::~LazyDict()
-{
- for (size_t i = 0; i < mObjs.size(); ++i) {
- delete mObjs[i];
- }
-}
-
-
-template<class T>
-inline void LazyDict<T>::AttachToDocument(Document& doc)
-{
- Value* container = 0;
-
- if (mExtId) {
- if (Value* exts = FindObject(doc, "extensions")) {
- container = FindObject(*exts, mExtId);
- }
- }
- else {
- container = &doc;
- }
-
- if (container) {
- mDict = FindArray(*container, mDictId);
- }
-}
-
-template<class T>
-inline void LazyDict<T>::DetachFromDocument()
-{
- mDict = 0;
-}
-
-template<class T>
-unsigned int LazyDict<T>::Remove(const char* id)
-{
- id = T::TranslateId(mAsset, id);
-
- typename IdDict::iterator it = mObjsById.find(id);
-
- if (it == mObjsById.end()) {
- throw DeadlyExportError("GLTF: Object with id \"" + std::string(id) + "\" is not found");
- }
-
- const unsigned int index = it->second;
-
- mAsset.mUsedIds[id] = false;
- mObjsById.erase(id);
- mObjsByOIndex.erase(index);
- mObjs.erase(mObjs.begin() + index);
-
- //update index of object in mObjs;
- for (unsigned int i = index; i < mObjs.size(); ++i) {
- T *obj = mObjs[i];
-
- obj->index = i;
- }
-
- for (IdDict::iterator it = mObjsById.begin(); it != mObjsById.end(); ++it) {
- if (it->second <= index) {
- continue;
- }
-
- mObjsById[it->first] = it->second - 1;
- }
-
- for (Dict::iterator it = mObjsByOIndex.begin(); it != mObjsByOIndex.end(); ++it) {
- if (it->second <= index) {
- continue;
- }
-
- mObjsByOIndex[it->first] = it->second - 1;
- }
-
- return index;
-}
-
-template<class T>
-Ref<T> LazyDict<T>::Retrieve(unsigned int i)
-{
-
- typename Dict::iterator it = mObjsByOIndex.find(i);
- if (it != mObjsByOIndex.end()) {// already created?
- return Ref<T>(mObjs, it->second);
- }
-
- // read it from the JSON object
- if (!mDict) {
- throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\"");
- }
-
- if (!mDict->IsArray()) {
- throw DeadlyImportError("GLTF: Field is not an array \"" + std::string(mDictId) + "\"");
- }
-
- Value &obj = (*mDict)[i];
-
- if (!obj.IsObject()) {
- throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object");
- }
-
- T* inst = new T();
- inst->id = std::string(mDictId) + "_" + to_string(i);
- inst->oIndex = i;
- ReadMember(obj, "name", inst->name);
- inst->Read(obj, mAsset);
-
- return Add(inst);
-}
-
-template<class T>
-Ref<T> LazyDict<T>::Get(unsigned int i)
-{
-
- return Ref<T>(mObjs, i);
-
-}
-
-template<class T>
-Ref<T> LazyDict<T>::Get(const char* id)
-{
- id = T::TranslateId(mAsset, id);
-
- typename IdDict::iterator it = mObjsById.find(id);
- if (it != mObjsById.end()) { // already created?
- return Ref<T>(mObjs, it->second);
- }
-
- return Ref<T>();
-}
-
-template<class T>
-Ref<T> LazyDict<T>::Add(T* obj)
-{
- unsigned int idx = unsigned(mObjs.size());
- mObjs.push_back(obj);
- mObjsByOIndex[obj->oIndex] = idx;
- mObjsById[obj->id] = idx;
- mAsset.mUsedIds[obj->id] = true;
- return Ref<T>(mObjs, idx);
-}
-
-template<class T>
-Ref<T> LazyDict<T>::Create(const char* id)
-{
- Asset::IdMap::iterator it = mAsset.mUsedIds.find(id);
- if (it != mAsset.mUsedIds.end()) {
- throw DeadlyImportError("GLTF: two objects with the same ID exist");
- }
- T* inst = new T();
- unsigned int idx = unsigned(mObjs.size());
- inst->id = id;
- inst->index = idx;
- inst->oIndex = idx;
- return Add(inst);
-}
-
-
-//
-// glTF dictionary objects methods
-//
-
-
-inline Buffer::Buffer()
- : byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false)
-{ }
-
-inline Buffer::~Buffer()
-{
- for(SEncodedRegion* reg : EncodedRegion_List) delete reg;
-}
-
-inline const char* Buffer::TranslateId(Asset& /*r*/, const char* id)
-{
- return id;
-}
-
-inline void Buffer::Read(Value& obj, Asset& r)
-{
- size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
- byteLength = statedLength;
-
- Value* it = FindString(obj, "uri");
- if (!it) {
- if (statedLength > 0) {
- throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute");
- }
- return;
- }
-
- const char* uri = it->GetString();
-
- Util::DataURI dataURI;
- if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
- if (dataURI.base64) {
- uint8_t* data = 0;
- this->byteLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, data);
- this->mData.reset(data, std::default_delete<uint8_t[]>());
-
- if (statedLength > 0 && this->byteLength != statedLength) {
- throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) +
- " bytes, but found " + to_string(dataURI.dataLength));
- }
- }
- else { // assume raw data
- if (statedLength != dataURI.dataLength) {
- throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) +
- " bytes, but found " + to_string(dataURI.dataLength));
- }
-
- this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>());
- memcpy( this->mData.get(), dataURI.data, dataURI.dataLength );
- }
- }
- else { // Local file
- if (byteLength > 0) {
- std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir + "/") : "";
-
- IOStream* file = r.OpenFile(dir + uri, "rb");
- if (file) {
- bool ok = LoadFromStream(*file, byteLength);
- delete file;
-
- if (!ok)
- throw DeadlyImportError("GLTF: error while reading referenced file \"" + std::string(uri) + "\"" );
- }
- else {
- throw DeadlyImportError("GLTF: could not open referenced file \"" + std::string(uri) + "\"");
- }
- }
- }
-}
-
-inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseOffset)
-{
- byteLength = length ? length : stream.FileSize();
-
- if (baseOffset) {
- stream.Seek(baseOffset, aiOrigin_SET);
- }
-
- mData.reset(new uint8_t[byteLength], std::default_delete<uint8_t[]>());
-
- if (stream.Read(mData.get(), byteLength, 1) != 1) {
- return false;
- }
- return true;
-}
-
-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)
-{
- // Check pointer to data
- if(pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided.");
-
- // Check offset
- if(pOffset > byteLength)
- {
- const uint8_t val_size = 32;
-
- char val[val_size];
-
- ai_snprintf(val, val_size, "%llu", (long long)pOffset);
- throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region.");
- }
-
- // Check length
- if((pOffset + pEncodedData_Length) > byteLength)
- {
- const uint8_t val_size = 64;
-
- char val[val_size];
-
- ai_snprintf(val, val_size, "%llu, %llu", (long long)pOffset, (long long)pEncodedData_Length);
- throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range.");
- }
-
- // Add new region
- EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID));
- // And set new value for "byteLength"
- byteLength += (pDecodedData_Length - pEncodedData_Length);
-}
-
-inline void Buffer::EncodedRegion_SetCurrent(const std::string& pID)
-{
- if((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return;
-
- for(SEncodedRegion* reg : EncodedRegion_List)
- {
- if(reg->ID == pID)
- {
- EncodedRegion_Current = reg;
-
- return;
- }
-
- }
-
- throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found.");
-}
-
-inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
-{
-const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
-
-uint8_t* new_data;
-
- if((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) return false;
-
- new_data = new uint8_t[new_data_size];
- // Copy data which place before replacing part.
- memcpy(new_data, mData.get(), pBufferData_Offset);
- // Copy new data.
- memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
- // Copy data which place after replacing part.
- memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset);
- // Apply new data
- mData.reset(new_data, std::default_delete<uint8_t[]>());
- byteLength = new_data_size;
-
- return true;
-}
-
-inline size_t Buffer::AppendData(uint8_t* data, size_t length)
-{
- size_t offset = this->byteLength;
- Grow(length);
- memcpy(mData.get() + offset, data, length);
- return offset;
-}
-
-inline void Buffer::Grow(size_t amount)
-{
- if (amount <= 0) return;
- uint8_t* b = new uint8_t[byteLength + amount];
- if (mData) memcpy(b, mData.get(), byteLength);
- mData.reset(b, std::default_delete<uint8_t[]>());
- byteLength += amount;
-}
-
-//
-// struct BufferView
-//
-
-inline void BufferView::Read(Value& obj, Asset& r)
-{
-
- if (Value* bufferVal = FindUInt(obj, "buffer")) {
- buffer = r.buffers.Retrieve(bufferVal->GetUint());
- }
-
- byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
- byteLength = MemberOrDefault(obj, "byteLength", 0u);
- byteStride = MemberOrDefault(obj, "byteStride", 0u);
-}
-
-//
-// struct Accessor
-//
-
-inline void Accessor::Read(Value& obj, Asset& r)
-{
-
- if (Value* bufferViewVal = FindUInt(obj, "bufferView")) {
- bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
- }
-
- byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
- componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
- count = MemberOrDefault(obj, "count", 0u);
-
- const char* typestr;
- type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
-}
-
-inline unsigned int Accessor::GetNumComponents()
-{
- return AttribType::GetNumComponents(type);
-}
-
-inline unsigned int Accessor::GetBytesPerComponent()
-{
- return int(ComponentTypeSize(componentType));
-}
-
-inline unsigned int Accessor::GetElementSize()
-{
- return GetNumComponents() * GetBytesPerComponent();
-}
-
-inline uint8_t* Accessor::GetPointer()
-{
- if (!bufferView || !bufferView->buffer) return 0;
- uint8_t* basePtr = bufferView->buffer->GetPointer();
- if (!basePtr) return 0;
-
- size_t offset = byteOffset + bufferView->byteOffset;
-
- // Check if region is encoded.
- if(bufferView->buffer->EncodedRegion_Current != nullptr)
- {
- const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
- const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
-
- if((offset >= begin) && (offset < end))
- return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
- }
-
- return basePtr + offset;
-}
-
-namespace {
- inline void CopyData(size_t count,
- const uint8_t* src, size_t src_stride,
- uint8_t* dst, size_t dst_stride)
- {
- if (src_stride == dst_stride) {
- memcpy(dst, src, count * src_stride);
- }
- else {
- size_t sz = std::min(src_stride, dst_stride);
- for (size_t i = 0; i < count; ++i) {
- memcpy(dst, src, sz);
- if (sz < dst_stride) {
- memset(dst + sz, 0, dst_stride - sz);
- }
- src += src_stride;
- dst += dst_stride;
- }
- }
- }
-}
-
-template<class T>
-bool Accessor::ExtractData(T*& outData)
-{
- uint8_t* data = GetPointer();
- if (!data) return false;
-
- const size_t elemSize = GetElementSize();
- const size_t totalSize = elemSize * count;
-
- const size_t stride = bufferView && bufferView->byteStride ? bufferView->byteStride : elemSize;
-
- const size_t targetElemSize = sizeof(T);
- ai_assert(elemSize <= targetElemSize);
-
- ai_assert(count*stride <= bufferView->byteLength);
-
- outData = new T[count];
- if (stride == elemSize && targetElemSize == elemSize) {
- memcpy(outData, data, totalSize);
- }
- else {
- for (size_t i = 0; i < count; ++i) {
- memcpy(outData + i, data + i*stride, elemSize);
- }
- }
-
- return true;
-}
-
-inline void Accessor::WriteData(size_t count, const void* src_buffer, size_t src_stride)
-{
- uint8_t* buffer_ptr = bufferView->buffer->GetPointer();
- size_t offset = byteOffset + bufferView->byteOffset;
-
- size_t dst_stride = GetNumComponents() * GetBytesPerComponent();
-
- const uint8_t* src = reinterpret_cast<const uint8_t*>(src_buffer);
- uint8_t* dst = reinterpret_cast< uint8_t*>(buffer_ptr + offset);
-
- ai_assert(dst + count*dst_stride <= buffer_ptr + bufferView->buffer->byteLength);
- CopyData(count, src, src_stride, dst, dst_stride);
-}
-
-
-
-inline Accessor::Indexer::Indexer(Accessor& acc)
- : accessor(acc)
- , data(acc.GetPointer())
- , elemSize(acc.GetElementSize())
- , stride(acc.bufferView && acc.bufferView->byteStride ? acc.bufferView->byteStride : elemSize)
-{
-
-}
-
-//! Accesses the i-th value as defined by the accessor
-template<class T>
-T Accessor::Indexer::GetValue(int i)
-{
- ai_assert(data);
- ai_assert(i*stride < accessor.bufferView->byteLength);
- T value = T();
- memcpy(&value, data + i*stride, elemSize);
- //value >>= 8 * (sizeof(T) - elemSize);
- return value;
-}
-
-inline Image::Image()
- : width(0)
- , height(0)
- , mData(0)
- , mDataLength(0)
-{
-
-}
-
-inline void Image::Read(Value& obj, Asset& /*r*/)
-{
- if (!mDataLength) {
- if (Value* uri = FindString(obj, "uri")) {
- const char* uristr = uri->GetString();
-
- Util::DataURI dataURI;
- if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) {
- mimeType = dataURI.mediaType;
- if (dataURI.base64) {
- mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, mData);
- }
- }
- else {
- this->uri = uristr;
- }
- }
- }
-}
-
-inline uint8_t* Image::StealData()
-{
- uint8_t* data = mData;
- mDataLength = 0;
- mData = 0;
- return data;
-}
-
-inline void Image::SetData(uint8_t* data, size_t length, Asset& r)
-{
- Ref<Buffer> b = r.GetBodyBuffer();
- if (b) { // binary file: append to body
- std::string bvId = r.FindUniqueID(this->id, "imgdata");
- bufferView = r.bufferViews.Create(bvId);
-
- bufferView->buffer = b;
- bufferView->byteLength = length;
- bufferView->byteOffset = b->AppendData(data, length);
- }
- else { // text file: will be stored as a data uri
- this->mData = data;
- this->mDataLength = length;
- }
-}
-
-inline void Sampler::Read(Value& obj, Asset& /*r*/)
-{
- SetDefaults();
-
- ReadMember(obj, "name", name);
- ReadMember(obj, "magFilter", magFilter);
- ReadMember(obj, "minFilter", minFilter);
- ReadMember(obj, "wrapS", wrapS);
- ReadMember(obj, "wrapT", wrapT);
-}
-
-inline void Sampler::SetDefaults()
-{
- //only wrapping modes have defaults
- wrapS = SamplerWrap::Repeat;
- wrapT = SamplerWrap::Repeat;
- magFilter = SamplerMagFilter::UNSET;
- minFilter = SamplerMinFilter::UNSET;
-}
-
-inline void Texture::Read(Value& obj, Asset& r)
-{
- if (Value* sourceVal = FindUInt(obj, "source")) {
- source = r.images.Retrieve(sourceVal->GetUint());
- }
-
- if (Value* samplerVal = FindUInt(obj, "sampler")) {
- sampler = r.samplers.Retrieve(samplerVal->GetUint());
- }
-}
-
-namespace {
- inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out)
- {
- if (Value* index = FindUInt(*prop, "index")) {
- out.texture = r.textures.Retrieve(index->GetUint());
- }
-
- if (Value* texcoord = FindUInt(*prop, "texCoord")) {
- out.texCoord = texcoord->GetUint();
- }
- }
-
- inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, TextureInfo& out)
- {
- if (Value* prop = FindMember(vals, propName)) {
- SetTextureProperties(r, prop, out);
- }
- }
-
- inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, NormalTextureInfo& out)
- {
- if (Value* prop = FindMember(vals, propName)) {
- SetTextureProperties(r, prop, out);
-
- if (Value* scale = FindNumber(*prop, "scale")) {
- out.scale = static_cast<float>(scale->GetDouble());
- }
- }
- }
-
- inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, OcclusionTextureInfo& out)
- {
- if (Value* prop = FindMember(vals, propName)) {
- SetTextureProperties(r, prop, out);
-
- if (Value* strength = FindNumber(*prop, "strength")) {
- out.strength = static_cast<float>(strength->GetDouble());
- }
- }
- }
-}
-
-inline void Material::Read(Value& material, Asset& r)
-{
- SetDefaults();
-
- if (Value* pbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) {
- ReadMember(*pbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor);
- ReadTextureProperty(r, *pbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture);
- ReadTextureProperty(r, *pbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture);
- ReadMember(*pbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor);
- ReadMember(*pbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor);
- }
-
- ReadTextureProperty(r, material, "normalTexture", this->normalTexture);
- ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture);
- ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture);
- ReadMember(material, "emissiveFactor", this->emissiveFactor);
-
- ReadMember(material, "doubleSided", this->doubleSided);
- ReadMember(material, "alphaMode", this->alphaMode);
- ReadMember(material, "alphaCutoff", this->alphaCutoff);
-
- if (Value* extensions = FindObject(material, "extensions")) {
- if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
- if (Value* pbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) {
- PbrSpecularGlossiness pbrSG;
-
- ReadMember(*pbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor);
- ReadTextureProperty(r, *pbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture);
- ReadTextureProperty(r, *pbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture);
- ReadMember(*pbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor);
- ReadMember(*pbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor);
-
- this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
- }
- }
- }
-}
-
-namespace {
- void SetVector(vec4& v, const float(&in)[4])
- { v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; v[3] = in[3]; }
-
- void SetVector(vec3& v, const float(&in)[3])
- { v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; }
-}
-
-inline void Material::SetDefaults()
-{
- //pbr materials
- SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
- pbrMetallicRoughness.metallicFactor = 1.0;
- pbrMetallicRoughness.roughnessFactor = 1.0;
-
- SetVector(emissiveFactor, defaultEmissiveFactor);
- alphaMode = "OPAQUE";
- alphaCutoff = 0.5;
- doubleSided = false;
-}
-
-inline void PbrSpecularGlossiness::SetDefaults()
-{
- //pbrSpecularGlossiness properties
- SetVector(diffuseFactor, defaultDiffuseFactor);
- SetVector(specularFactor, defaultSpecularFactor);
- glossinessFactor = 1.0;
-}
-
-namespace {
-
- template<int N>
- inline int Compare(const char* attr, const char (&str)[N]) {
- return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
- }
-
- inline bool GetAttribVector(Mesh::Primitive& p, const char* attr, Mesh::AccessorList*& v, int& pos)
- {
- if ((pos = Compare(attr, "POSITION"))) {
- v = &(p.attributes.position);
- }
- else if ((pos = Compare(attr, "NORMAL"))) {
- v = &(p.attributes.normal);
- }
- else if ((pos = Compare(attr, "TANGENT"))) {
- v = &(p.attributes.tangent);
- }
- else if ((pos = Compare(attr, "TEXCOORD"))) {
- v = &(p.attributes.texcoord);
- }
- else if ((pos = Compare(attr, "COLOR"))) {
- v = &(p.attributes.color);
- }
- else if ((pos = Compare(attr, "JOINT"))) {
- v = &(p.attributes.joint);
- }
- else if ((pos = Compare(attr, "JOINTMATRIX"))) {
- v = &(p.attributes.jointmatrix);
- }
- else if ((pos = Compare(attr, "WEIGHT"))) {
- v = &(p.attributes.weight);
- }
- else return false;
- return true;
- }
-}
-
-inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
-{
- if (Value* name = FindMember(pJSON_Object, "name")) {
- this->name = name->GetString();
- }
-
- /****************** Mesh primitives ******************/
- if (Value* primitives = FindArray(pJSON_Object, "primitives")) {
- this->primitives.resize(primitives->Size());
- for (unsigned int i = 0; i < primitives->Size(); ++i) {
- Value& primitive = (*primitives)[i];
-
- Primitive& prim = this->primitives[i];
- prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
-
- if (Value* attrs = FindObject(primitive, "attributes")) {
- for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
- if (!it->value.IsUint()) continue;
- const char* attr = it->name.GetString();
- // Valid attribute semantics include POSITION, NORMAL, TANGENT, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
- // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
-
- int undPos = 0;
- Mesh::AccessorList* vec = 0;
- if (GetAttribVector(prim, attr, vec, undPos)) {
- size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
- if ((*vec).size() <= idx) (*vec).resize(idx + 1);
- (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
- }
- }
- }
-
- if (Value* indices = FindUInt(primitive, "indices")) {
- prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
- }
-
- if (Value* material = FindUInt(primitive, "material")) {
- prim.material = pAsset_Root.materials.Retrieve(material->GetUint());
- }
- }
- }
-}
-
-inline void Camera::Read(Value& obj, Asset& /*r*/)
-{
- type = MemberOrDefault(obj, "type", Camera::Perspective);
-
- const char* subobjId = (type == Camera::Orthographic) ? "orthographic" : "perspective";
-
- Value* it = FindObject(obj, subobjId);
- if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters");
-
- if (type == Camera::Perspective) {
- cameraProperties.perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
- cameraProperties.perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f/2.f);
- cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
- cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
- }
- else {
- cameraProperties.ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f);
- cameraProperties.ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f);
- cameraProperties.ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f);
- cameraProperties.ortographic.znear = MemberOrDefault(obj, "znear", 0.01f);
- }
-}
-
-inline void Node::Read(Value& obj, Asset& r)
-{
-
- if (Value* children = FindArray(obj, "children")) {
- this->children.reserve(children->Size());
- for (unsigned int i = 0; i < children->Size(); ++i) {
- Value& child = (*children)[i];
- if (child.IsUint()) {
- // get/create the child node
- Ref<Node> chn = r.nodes.Retrieve(child.GetUint());
- if (chn) this->children.push_back(chn);
- }
- }
- }
-
- if (Value* matrix = FindArray(obj, "matrix")) {
- ReadValue(*matrix, this->matrix);
- }
- else {
- ReadMember(obj, "translation", translation);
- ReadMember(obj, "scale", scale);
- ReadMember(obj, "rotation", rotation);
- }
-
- if (Value* mesh = FindUInt(obj, "mesh")) {
- unsigned numMeshes = 1;
-
- this->meshes.reserve(numMeshes);
-
- Ref<Mesh> meshRef = r.meshes.Retrieve((*mesh).GetUint());
-
- if (meshRef) this->meshes.push_back(meshRef);
- }
-
- if (Value* camera = FindUInt(obj, "camera")) {
- this->camera = r.cameras.Retrieve(camera->GetUint());
- if (this->camera)
- this->camera->id = this->id;
- }
-}
-
-inline void Scene::Read(Value& obj, Asset& r)
-{
- if (Value* array = FindArray(obj, "nodes")) {
- for (unsigned int i = 0; i < array->Size(); ++i) {
- if (!(*array)[i].IsUint()) continue;
- Ref<Node> node = r.nodes.Retrieve((*array)[i].GetUint());
- if (node)
- this->nodes.push_back(node);
- }
- }
-}
-
-inline void AssetMetadata::Read(Document& doc)
-{
- if (Value* obj = FindObject(doc, "asset")) {
- ReadMember(*obj, "copyright", copyright);
- ReadMember(*obj, "generator", generator);
-
- if (Value* versionString = FindString(*obj, "version")) {
- version = versionString->GetString();
- } else if (Value* versionNumber = FindNumber (*obj, "version")) {
- char buf[4];
-
- ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
-
- version = buf;
- }
-
- if (Value* profile = FindObject(*obj, "profile")) {
- ReadMember(*profile, "api", this->profile.api);
- ReadMember(*profile, "version", this->profile.version);
- }
- }
-
- if (version.empty() || version[0] != '2') {
- throw DeadlyImportError("GLTF: Unsupported glTF version: " + version);
- }
-}
-
-//
-// Asset methods implementation
-//
-
-inline void Asset::ReadBinaryHeader(IOStream& stream, std::vector<char>& sceneData)
-{
- GLB_Header header;
- if (stream.Read(&header, sizeof(header), 1) != 1) {
- throw DeadlyImportError("GLTF: Unable to read the file header");
- }
-
- if (strncmp((char*)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
- throw DeadlyImportError("GLTF: Invalid binary glTF file");
- }
-
- AI_SWAP4(header.version);
- asset.version = to_string(header.version);
- if (header.version != 2) {
- throw DeadlyImportError("GLTF: Unsupported binary glTF version");
- }
-
- GLB_Chunk chunk;
- if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
- throw DeadlyImportError("GLTF: Unable to read JSON chunk");
- }
-
- AI_SWAP4(chunk.chunkLength);
- AI_SWAP4(chunk.chunkType);
-
- if (chunk.chunkType != ChunkType_JSON) {
- throw DeadlyImportError("GLTF: JSON chunk missing");
- }
-
- // read the scene data
-
- mSceneLength = chunk.chunkLength;
- sceneData.resize(mSceneLength + 1);
- sceneData[mSceneLength] = '\0';
-
- if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
- throw DeadlyImportError("GLTF: Could not read the file contents");
- }
-
- uint32_t padding = ((chunk.chunkLength + 3) & ~3) - chunk.chunkLength;
- if (padding > 0) {
- stream.Seek(padding, aiOrigin_CUR);
- }
-
- AI_SWAP4(header.length);
- mBodyOffset = 12 + 8 + chunk.chunkLength + padding + 8;
- if (header.length >= mBodyOffset) {
- if (stream.Read(&chunk, sizeof(chunk), 1) != 1) {
- throw DeadlyImportError("GLTF: Unable to read BIN chunk");
- }
-
- AI_SWAP4(chunk.chunkLength);
- AI_SWAP4(chunk.chunkType);
-
- if (chunk.chunkType != ChunkType_BIN) {
- throw DeadlyImportError("GLTF: BIN chunk missing");
- }
-
- mBodyLength = chunk.chunkLength;
- }
- else {
- mBodyOffset = mBodyLength = 0;
- }
-}
-
-inline void Asset::Load(const std::string& pFile, bool isBinary)
-{
- mCurrentAssetDir.clear();
- int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
- if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1);
-
- shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
- if (!stream) {
- throw DeadlyImportError("GLTF: Could not open file for reading");
- }
-
- // is binary? then read the header
- std::vector<char> sceneData;
- if (isBinary) {
- SetAsBinary(); // also creates the body buffer
- ReadBinaryHeader(*stream, sceneData);
- }
- else {
- mSceneLength = stream->FileSize();
- mBodyLength = 0;
-
-
- // read the scene data
-
- sceneData.resize(mSceneLength + 1);
- sceneData[mSceneLength] = '\0';
-
- if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
- throw DeadlyImportError("GLTF: Could not read the file contents");
- }
- }
-
-
- // parse the JSON document
-
- Document doc;
- doc.ParseInsitu(&sceneData[0]);
-
- if (doc.HasParseError()) {
- char buffer[32];
- ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset()));
- throw DeadlyImportError(std::string("GLTF: JSON parse error, offset ") + buffer + ": "
- + GetParseError_En(doc.GetParseError()));
- }
-
- if (!doc.IsObject()) {
- throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
- }
-
- // Fill the buffer instance for the current file embedded contents
- if (mBodyLength > 0) {
- if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
- throw DeadlyImportError("GLTF: Unable to read gltf file");
- }
- }
-
-
- // Load the metadata
- asset.Read(doc);
- ReadExtensionsUsed(doc);
-
- // Prepare the dictionaries
- for (size_t i = 0; i < mDicts.size(); ++i) {
- mDicts[i]->AttachToDocument(doc);
- }
-
- // Read the "scene" property, which specifies which scene to load
- // and recursively load everything referenced by it
- if (Value* scene = FindUInt(doc, "scene")) {
- unsigned int sceneIndex = scene->GetUint();
-
- Ref<Scene> s = scenes.Retrieve(sceneIndex);
-
- this->scene = s;
- }
-
- // Clean up
- for (size_t i = 0; i < mDicts.size(); ++i) {
- mDicts[i]->DetachFromDocument();
- }
-}
-
-inline void Asset::SetAsBinary()
-{
- if (!mBodyBuffer) {
- mBodyBuffer = buffers.Create("binary_glTF");
- mBodyBuffer->MarkAsSpecial();
- }
-}
-
-
-inline void Asset::ReadExtensionsUsed(Document& doc)
-{
- Value* extsUsed = FindArray(doc, "extensionsUsed");
- if (!extsUsed) return;
-
- std::gltf_unordered_map<std::string, bool> exts;
-
- for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
- if ((*extsUsed)[i].IsString()) {
- exts[(*extsUsed)[i].GetString()] = true;
- }
- }
-
- #define CHECK_EXT(EXT) \
- if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
-
- CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
-
- #undef CHECK_EXT
-}
-
-inline IOStream* Asset::OpenFile(std::string path, const char* mode, bool /*absolute*/)
-{
- #ifdef ASSIMP_API
- return mIOSystem->Open(path, mode);
- #else
- if (path.size() < 2) return 0;
- if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
- path = mCurrentAssetDir + path;
- }
- FILE* f = fopen(path.c_str(), mode);
- return f ? new IOStream(f) : 0;
- #endif
-}
-
-inline std::string Asset::FindUniqueID(const std::string& str, const char* suffix)
-{
- std::string id = str;
-
- if (!id.empty()) {
- if (mUsedIds.find(id) == mUsedIds.end())
- return id;
-
- id += "_";
- }
-
- id += suffix;
-
- Asset::IdMap::iterator it = mUsedIds.find(id);
- if (it == mUsedIds.end())
- return id;
-
- std::vector<char> buffer;
- buffer.resize(id.size() + 16);
- int offset = ai_snprintf(buffer.data(), buffer.size(), "%s_", id.c_str());
- for (int i = 0; it != mUsedIds.end(); ++i) {
- ai_snprintf(buffer.data() + offset, buffer.size() - offset, "%d", i);
- id = buffer.data();
- it = mUsedIds.find(id);
- }
-
- return id;
-}
-
-namespace Util {
-
- inline
- bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) {
- if ( NULL == const_uri ) {
- return false;
- }
-
- if (const_uri[0] != 0x10) { // we already parsed this uri?
- if (strncmp(const_uri, "data:", 5) != 0) // not a data uri?
- return false;
- }
-
- // set defaults
- out.mediaType = "text/plain";
- out.charset = "US-ASCII";
- out.base64 = false;
-
- char* uri = const_cast<char*>(const_uri);
- if (uri[0] != 0x10) {
- uri[0] = 0x10;
- uri[1] = uri[2] = uri[3] = uri[4] = 0;
-
- size_t i = 5, j;
- if (uri[i] != ';' && uri[i] != ',') { // has media type?
- uri[1] = char(i);
- for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) {
- // nothing to do!
- }
- }
- while (uri[i] == ';' && i < uriLen) {
- uri[i++] = '\0';
- for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) {
- // nothing to do!
- }
-
- if ( strncmp( uri + j, "charset=", 8 ) == 0 ) {
- uri[2] = char(j + 8);
- } else if ( strncmp( uri + j, "base64", 6 ) == 0 ) {
- uri[3] = char(j);
- }
- }
- if (i < uriLen) {
- uri[i++] = '\0';
- uri[4] = char(i);
- } else {
- uri[1] = uri[2] = uri[3] = 0;
- uri[4] = 5;
- }
- }
-
- if ( uri[ 1 ] != 0 ) {
- out.mediaType = uri + uri[ 1 ];
- }
- if ( uri[ 2 ] != 0 ) {
- out.charset = uri + uri[ 2 ];
- }
- if ( uri[ 3 ] != 0 ) {
- out.base64 = true;
- }
- out.data = uri + uri[4];
- out.dataLength = (uri + uriLen) - out.data;
-
- return true;
- }
-
- template<bool B>
- struct DATA
- {
- static const uint8_t tableDecodeBase64[128];
- };
-
- template<bool B>
- const uint8_t DATA<B>::tableDecodeBase64[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0,
- 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
- 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0
- };
-
- inline char EncodeCharBase64(uint8_t b)
- {
- return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)];
- }
-
- inline uint8_t DecodeCharBase64(char c)
- {
- return DATA<true>::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs?
- /*if (c >= 'A' && c <= 'Z') return c - 'A';
- if (c >= 'a' && c <= 'z') return c - 'a' + 26;
- if (c >= '0' && c <= '9') return c - '0' + 52;
- if (c == '+') return 62;
- if (c == '/') return 63;
- return 64; // '-' */
- }
-
- inline size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out)
- {
- ai_assert(inLength % 4 == 0);
-
- if (inLength < 4) {
- out = 0;
- return 0;
- }
-
- int nEquals = int(in[inLength - 1] == '=') +
- int(in[inLength - 2] == '=');
-
- size_t outLength = (inLength * 3) / 4 - nEquals;
- out = new uint8_t[outLength];
- memset(out, 0, outLength);
-
- size_t i, j = 0;
-
- for (i = 0; i + 4 < inLength; i += 4) {
- uint8_t b0 = DecodeCharBase64(in[i]);
- uint8_t b1 = DecodeCharBase64(in[i + 1]);
- uint8_t b2 = DecodeCharBase64(in[i + 2]);
- uint8_t b3 = DecodeCharBase64(in[i + 3]);
-
- out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
- out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
- out[j++] = (uint8_t)((b2 << 6) | b3);
- }
-
- {
- uint8_t b0 = DecodeCharBase64(in[i]);
- uint8_t b1 = DecodeCharBase64(in[i + 1]);
- uint8_t b2 = DecodeCharBase64(in[i + 2]);
- uint8_t b3 = DecodeCharBase64(in[i + 3]);
-
- out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
- if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
- if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3);
- }
-
- return outLength;
- }
-
-
-
- inline void EncodeBase64(
- const uint8_t* in, size_t inLength,
- std::string& out)
- {
- size_t outLength = ((inLength + 2) / 3) * 4;
-
- size_t j = out.size();
- out.resize(j + outLength);
-
- for (size_t i = 0; i < inLength; i += 3) {
- uint8_t b = (in[i] & 0xFC) >> 2;
- out[j++] = EncodeCharBase64(b);
-
- b = (in[i] & 0x03) << 4;
- if (i + 1 < inLength) {
- b |= (in[i + 1] & 0xF0) >> 4;
- out[j++] = EncodeCharBase64(b);
-
- b = (in[i + 1] & 0x0F) << 2;
- if (i + 2 < inLength) {
- b |= (in[i + 2] & 0xC0) >> 6;
- out[j++] = EncodeCharBase64(b);
-
- b = in[i + 2] & 0x3F;
- out[j++] = EncodeCharBase64(b);
- }
- else {
- out[j++] = EncodeCharBase64(b);
- out[j++] = '=';
- }
- }
- else {
- out[j++] = EncodeCharBase64(b);
- out[j++] = '=';
- out[j++] = '=';
- }
- }
- }
-
-}
-
-} // ns glTF