diff options
Diffstat (limited to 'indra/newview/gltf/accessor.cpp')
-rw-r--r-- | indra/newview/gltf/accessor.cpp | 274 |
1 files changed, 253 insertions, 21 deletions
diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp index 55d36b7a32..2ef9237f2d 100644 --- a/indra/newview/gltf/accessor.cpp +++ b/indra/newview/gltf/accessor.cpp @@ -27,40 +27,272 @@ #include "../llviewerprecompiledheaders.h" #include "asset.h" +#include "buffer_util.h" +#include "llfilesystem.h" using namespace LL::GLTF; +using namespace boost::json; -const Buffer& Buffer::operator=(const tinygltf::Buffer& src) +namespace LL { - mData = src.data; - mName = src.name; - mUri = src.uri; + namespace GLTF + { + Accessor::Type gltf_type_to_enum(const std::string& type) + { + if (type == "SCALAR") + { + return Accessor::Type::SCALAR; + } + else if (type == "VEC2") + { + return Accessor::Type::VEC2; + } + else if (type == "VEC3") + { + return Accessor::Type::VEC3; + } + else if (type == "VEC4") + { + return Accessor::Type::VEC4; + } + else if (type == "MAT2") + { + return Accessor::Type::MAT2; + } + else if (type == "MAT3") + { + return Accessor::Type::MAT3; + } + else if (type == "MAT4") + { + return Accessor::Type::MAT4; + } + + LL_WARNS("GLTF") << "Unknown accessor type: " << type << LL_ENDL; + llassert(false); + + return Accessor::Type::SCALAR; + } + + std::string enum_to_gltf_type(Accessor::Type type) + { + switch (type) + { + case Accessor::Type::SCALAR: + return "SCALAR"; + case Accessor::Type::VEC2: + return "VEC2"; + case Accessor::Type::VEC3: + return "VEC3"; + case Accessor::Type::VEC4: + return "VEC4"; + case Accessor::Type::MAT2: + return "MAT2"; + case Accessor::Type::MAT3: + return "MAT3"; + case Accessor::Type::MAT4: + return "MAT4"; + } + + LL_WARNS("GLTF") << "Unknown accessor type: " << (S32)type << LL_ENDL; + llassert(false); + + return "SCALAR"; + } + } +} + +void Buffer::erase(Asset& asset, S32 offset, S32 length) +{ + S32 idx = this - &asset.mBuffers[0]; + + mData.erase(mData.begin() + offset, mData.begin() + offset + length); + + llassert(mData.size() <= size_t(INT_MAX)); + mByteLength = S32(mData.size()); + + for (BufferView& view : asset.mBufferViews) + { + if (view.mBuffer == idx) + { + if (view.mByteOffset >= offset) + { + view.mByteOffset -= length; + } + } + } +} + +bool Buffer::prep(Asset& asset) +{ + if (mByteLength == 0) + { + return false; + } + + LLUUID id; + if (mUri.size() == UUID_STR_SIZE && LLUUID::parseUUID(mUri, &id) && id.notNull()) + { // loaded from an asset, fetch the buffer data from the asset store + LLFileSystem file(id, LLAssetType::AT_GLTF_BIN, LLFileSystem::READ); + + if (mByteLength > file.getSize()) + { + LL_WARNS("GLTF") << "Unexpected glbin size: " << id << " is " << file.getSize() << " bytes, expected " << mByteLength << LL_ENDL; + return false; + } + + mData.resize(mByteLength); + if (!file.read((U8*)mData.data(), mByteLength)) + { + LL_WARNS("GLTF") << "Failed to load buffer data from asset: " << id << LL_ENDL; + return false; + } + } + else if (mUri.find("data:") == 0) + { // loaded from a data URI, load the texture from the data + LL_WARNS() << "Data URIs not yet supported" << LL_ENDL; + return false; + } + else if (!asset.mFilename.empty() && + !mUri.empty()) // <-- uri could be empty if we're loading from .glb + { + std::string dir = gDirUtilp->getDirName(asset.mFilename); + std::string bin_file = dir + gDirUtilp->getDirDelimiter() + mUri; + + std::ifstream file(bin_file, std::ios::binary); + if (!file.is_open()) + { + LL_WARNS("GLTF") << "Failed to open file: " << bin_file << LL_ENDL; + return false; + } + + file.seekg(0, std::ios::end); + if (mByteLength > file.tellg()) + { + LL_WARNS("GLTF") << "Unexpected file size: " << bin_file << " is " << file.tellg() << " bytes, expected " << mByteLength << LL_ENDL; + return false; + } + file.seekg(0, std::ios::beg); + + mData.resize(mByteLength); + file.read((char*)mData.data(), mData.size()); + } + + // POSTCONDITION: on success, mData.size == mByteLength + llassert(mData.size() == mByteLength); + return true; +} + +bool Buffer::save(Asset& asset, const std::string& folder) +{ + if (mUri.substr(0, 5) == "data:") + { + LL_WARNS("GLTF") << "Data URIs not yet supported" << LL_ENDL; + return false; + } + + std::string bin_file = folder + gDirUtilp->getDirDelimiter(); + + if (mUri.empty()) + { + if (mName.empty()) + { + S32 idx = this - &asset.mBuffers[0]; + mUri = llformat("buffer_%d.bin", idx); + } + else + { + mUri = mName + ".bin"; + } + } + + bin_file += mUri; + + std::ofstream file(bin_file, std::ios::binary); + if (!file.is_open()) + { + LL_WARNS("GLTF") << "Failed to open file: " << bin_file << LL_ENDL; + return false; + } + + file.write((char*)mData.data(), mData.size()); + + return true; +} + +void Buffer::serialize(object& dst) const +{ + write(mName, "name", dst); + write(mUri, "uri", dst); + write_always(mByteLength, "byteLength", dst); +}; + +const Buffer& Buffer::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "name", mName); + copy(src, "uri", mUri); + copy(src, "byteLength", mByteLength); + + // NOTE: DO NOT attempt to handle the uri here. + // The uri is a reference to a file that is not loaded until + // after the json document is parsed + } return *this; } -const BufferView& BufferView::operator=(const tinygltf::BufferView& src) +void BufferView::serialize(object& dst) const { - mBuffer = src.buffer; - mByteLength = src.byteLength; - mByteOffset = src.byteOffset; - mByteStride = src.byteStride; - mTarget = src.target; - mName = src.name; + write_always(mBuffer, "buffer", dst); + write_always(mByteLength, "byteLength", dst); + write(mByteOffset, "byteOffset", dst, 0); + write(mByteStride, "byteStride", dst, 0); + write(mTarget, "target", dst, -1); + write(mName, "name", dst); +} + +const BufferView& BufferView::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "buffer", mBuffer); + copy(src, "byteLength", mByteLength); + copy(src, "byteOffset", mByteOffset); + copy(src, "byteStride", mByteStride); + copy(src, "target", mTarget); + copy(src, "name", mName); + } return *this; } -const Accessor& Accessor::operator=(const tinygltf::Accessor& src) +void Accessor::serialize(object& dst) const { - mBufferView = src.bufferView; - mByteOffset = src.byteOffset; - mComponentType = src.componentType; - mCount = src.count; - mType = src.type; - mNormalized = src.normalized; - mName = src.name; - mMax = src.maxValues; - mMin = src.minValues; + write(mName, "name", dst); + write(mBufferView, "bufferView", dst, INVALID_INDEX); + write(mByteOffset, "byteOffset", dst, 0); + write_always(mComponentType, "componentType", dst); + write_always(mCount, "count", dst); + write_always(enum_to_gltf_type(mType), "type", dst); + write(mNormalized, "normalized", dst, false); + write(mMax, "max", dst); + write(mMin, "min", dst); +} +const Accessor& Accessor::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "name", mName); + copy(src, "bufferView", mBufferView); + copy(src, "byteOffset", mByteOffset); + copy(src, "componentType", mComponentType); + copy(src, "count", mCount); + copy(src, "type", mType); + copy(src, "normalized", mNormalized); + copy(src, "max", mMax); + copy(src, "min", mMin); + } return *this; } |