2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-scene3d/internal/loader/glb-loader-impl.h>
22 #include <dali/devel-api/adaptor-framework/file-stream.h>
23 #include <dali/integration-api/debug.h>
26 #include <dali-scene3d/internal/loader/gltf2-util.h>
27 #include <dali-scene3d/public-api/loader/load-result.h>
28 #include <dali-scene3d/public-api/loader/utils.h>
33 namespace Dali::Scene3D::Loader::Internal
37 static constexpr uint32_t GLB_MAGIC = 0x46546C67;
38 static constexpr uint32_t JSON_CHUNK_TYPE = 0x4E4F534A;
39 static constexpr uint32_t DATA_CHUNK_TYPE = 0x004E4942;
56 bool GlbLoaderImpl::LoadModel(const std::string& url, Dali::Scene3D::Loader::LoadResult& result)
58 Dali::FileStream fileStream(url, FileStream::READ | FileStream::BINARY);
59 auto& stream = fileStream.GetStream();
60 if(!stream.rdbuf()->in_avail())
62 DALI_LOG_ERROR("Load Model file is failed, url : %s\n", url.c_str());
68 stream.seekg(0u, stream.beg);
69 stream.read(reinterpret_cast<char*>(&glbHeader), sizeof(GlbHeader));
71 if(glbHeader.magic != GLB_MAGIC)
73 DALI_LOG_ERROR("Wrong file format, url : %s\n", url.c_str());
77 ChunkHeader jsonChunkHeader;
78 stream.read(reinterpret_cast<char*>(&jsonChunkHeader), sizeof(ChunkHeader));
80 if(jsonChunkHeader.chunkType != JSON_CHUNK_TYPE)
82 DALI_LOG_ERROR("Glb files first chunk is not a json chunk.\n");
86 std::vector<uint8_t> jsonChunkData;
87 jsonChunkData.resize(jsonChunkHeader.chunkLength);
88 stream.read(reinterpret_cast<char*>(&jsonChunkData[0]), static_cast<std::streamsize>(static_cast<size_t>(jsonChunkHeader.chunkLength)));
89 std::string gltfText(jsonChunkData.begin(), jsonChunkData.end());
91 uint32_t binaryChunkOffset = sizeof(GlbHeader) + sizeof(ChunkHeader) + jsonChunkHeader.chunkLength;
92 std::vector<uint8_t> binaryChunkData;
93 if(glbHeader.length > binaryChunkOffset)
95 ChunkHeader binaryChunkHeader;
96 stream.read(reinterpret_cast<char*>(&binaryChunkHeader), sizeof(ChunkHeader));
98 if(binaryChunkHeader.chunkType != DATA_CHUNK_TYPE)
100 DALI_LOG_ERROR("Glb files has wrong binary chunk data.\n");
104 binaryChunkData.resize(binaryChunkHeader.chunkLength);
105 stream.read(reinterpret_cast<char*>(&binaryChunkData[0]), static_cast<std::streamsize>(static_cast<size_t>(binaryChunkHeader.chunkLength)));
108 json::unique_ptr root(json_parse(gltfText.c_str(), gltfText.size()));
111 DALI_LOG_ERROR("Failed to parse %s\n", url.c_str());
115 gt::Document document;
117 bool isMRendererModel(false);
118 if(!Gltf2Util::GenerateDocument(root, document, isMRendererModel))
120 DALI_LOG_ERROR("Failed to parse %s\n", url.c_str());
124 auto path = url.substr(0, url.rfind('/') + 1);
125 Gltf2Util::ConversionContext context{result, path, INVALID_INDEX};
127 auto& outBuffers = context.mOutput.mResources.mBuffers;
128 outBuffers.reserve(document.mBuffers.size());
129 if(!binaryChunkData.empty())
131 BufferDefinition dataBuffer(binaryChunkData);
132 outBuffers.emplace_back(std::move(dataBuffer));
135 Gltf2Util::ConvertGltfToContext(document, context, isMRendererModel);
140 } // namespace Dali::Scene3D::Loader::Internal