/src/assimp/code/AssetLib/glTF/glTFAsset.inl
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2025, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | | |
39 | | ---------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | #include <assimp/MemoryIOWrapper.h> |
43 | | #include <assimp/StringUtils.h> |
44 | | #include <iomanip> |
45 | | |
46 | | // Header files, Assimp |
47 | | #include <assimp/DefaultLogger.hpp> |
48 | | #include <assimp/Base64.hpp> |
49 | | |
50 | | #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC |
51 | | // Header files, Open3DGC. |
52 | | #include <Open3DGC/o3dgcSC3DMCDecoder.h> |
53 | | #endif |
54 | | |
55 | | using namespace Assimp; |
56 | | |
57 | | namespace glTF { |
58 | | using namespace glTFCommon; |
59 | | |
60 | | #if _MSC_VER |
61 | | #pragma warning(push) |
62 | | #pragma warning(disable : 4706) |
63 | | #endif // _MSC_VER |
64 | | |
65 | | // |
66 | | // LazyDict methods |
67 | | // |
68 | | |
69 | | template <class T> |
70 | | inline LazyDict<T>::LazyDict(Asset &asset, const char *dictId, const char *extId) : |
71 | 546 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { |
72 | 546 | asset.mDicts.push_back(this); // register to the list of dictionaries |
73 | 546 | } glTF::LazyDict<glTF::Accessor>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Animation>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Buffer>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::BufferView>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Camera>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Image>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Material>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Mesh>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Node>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Sampler>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Scene>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Skin>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Texture>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
glTF::LazyDict<glTF::Light>::LazyDict(glTF::Asset&, char const*, char const*) Line | Count | Source | 71 | 39 | mDictId(dictId), mExtId(extId), mDict(nullptr), mAsset(asset) { | 72 | 39 | asset.mDicts.push_back(this); // register to the list of dictionaries | 73 | 39 | } |
|
74 | | |
75 | | template <class T> |
76 | 546 | inline LazyDict<T>::~LazyDict() { |
77 | 546 | for (size_t i = 0; i < mObjs.size(); ++i) { |
78 | 0 | delete mObjs[i]; |
79 | 0 | } |
80 | 546 | } glTF::LazyDict<glTF::Light>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Texture>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Skin>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Scene>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Sampler>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Node>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Mesh>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Material>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Image>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Camera>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::BufferView>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Buffer>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Animation>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
glTF::LazyDict<glTF::Accessor>::~LazyDict() Line | Count | Source | 76 | 39 | inline LazyDict<T>::~LazyDict() { | 77 | 39 | for (size_t i = 0; i < mObjs.size(); ++i) { | 78 | 0 | delete mObjs[i]; | 79 | 0 | } | 80 | 39 | } |
|
81 | | |
82 | | template <class T> |
83 | 0 | inline void LazyDict<T>::AttachToDocument(Document &doc) { |
84 | 0 | Value *container = nullptr; |
85 | |
|
86 | 0 | if (mExtId) { |
87 | 0 | if (Value *exts = FindObject(doc, "extensions")) { |
88 | 0 | container = FindObject(*exts, mExtId); |
89 | 0 | } |
90 | 0 | } else { |
91 | 0 | container = &doc; |
92 | 0 | } |
93 | |
|
94 | 0 | if (container) { |
95 | 0 | mDict = FindObject(*container, mDictId); |
96 | 0 | } |
97 | 0 | } Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Image>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Material>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Node>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) Unexecuted instantiation: glTF::LazyDict<glTF::Light>::AttachToDocument(rapidjson::GenericDocument<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>, rapidjson::CrtAllocator>&) |
98 | | |
99 | | template <class T> |
100 | 0 | inline void LazyDict<T>::DetachFromDocument() { |
101 | 0 | mDict = nullptr; |
102 | 0 | } Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Image>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Material>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Node>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::DetachFromDocument() Unexecuted instantiation: glTF::LazyDict<glTF::Light>::DetachFromDocument() |
103 | | |
104 | | template <class T> |
105 | 0 | Ref<T> LazyDict<T>::Get(unsigned int i) { |
106 | 0 | return Ref<T>(mObjs, i); |
107 | 0 | } Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Get(unsigned int) Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Get(unsigned int) Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Get(unsigned int) Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Get(unsigned int) Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Get(unsigned int) |
108 | | |
109 | | template <class T> |
110 | 0 | Ref<T> LazyDict<T>::Get(const char *id) { |
111 | 0 | id = T::TranslateId(mAsset, id); |
112 | |
|
113 | 0 | typename Dict::iterator it = mObjsById.find(id); |
114 | 0 | if (it != mObjsById.end()) { // already created? |
115 | 0 | return Ref<T>(mObjs, it->second); |
116 | 0 | } |
117 | | |
118 | | // read it from the JSON object |
119 | 0 | if (!mDict) { |
120 | 0 | throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\""); |
121 | 0 | } |
122 | | |
123 | 0 | Value::MemberIterator obj = mDict->FindMember(id); |
124 | 0 | if (obj == mDict->MemberEnd()) { |
125 | 0 | throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\""); |
126 | 0 | } |
127 | 0 | if (!obj->value.IsObject()) { |
128 | 0 | throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object"); |
129 | 0 | } |
130 | | |
131 | | // create an instance of the given type |
132 | 0 | T *inst = new T(); |
133 | 0 | inst->id = id; |
134 | 0 | ReadMember(obj->value, "name", inst->name); |
135 | 0 | inst->Read(obj->value, mAsset); |
136 | 0 | return Add(inst); |
137 | 0 | } Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Image>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Light>::Get(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::Get(char const*) |
138 | | |
139 | | template <class T> |
140 | 0 | Ref<T> LazyDict<T>::Add(T *obj) { |
141 | 0 | unsigned int idx = unsigned(mObjs.size()); |
142 | 0 | mObjs.push_back(obj); |
143 | 0 | mObjsById[obj->id] = idx; |
144 | 0 | mAsset.mUsedIds[obj->id] = true; |
145 | 0 | return Ref<T>(mObjs, idx); |
146 | 0 | } Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Add(glTF::Buffer*) Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::Add(glTF::BufferView*) Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::Add(glTF::Accessor*) Unexecuted instantiation: glTF::LazyDict<glTF::Image>::Add(glTF::Image*) Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::Add(glTF::Sampler*) Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Add(glTF::Texture*) Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Add(glTF::Material*) Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Add(glTF::Mesh*) Unexecuted instantiation: glTF::LazyDict<glTF::Camera>::Add(glTF::Camera*) Unexecuted instantiation: glTF::LazyDict<glTF::Light>::Add(glTF::Light*) Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Add(glTF::Node*) Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::Add(glTF::Skin*) Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::Add(glTF::Scene*) Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::Add(glTF::Animation*) |
147 | | |
148 | | template <class T> |
149 | 0 | Ref<T> LazyDict<T>::Create(const char *id) { |
150 | 0 | Asset::IdMap::iterator it = mAsset.mUsedIds.find(id); |
151 | 0 | if (it != mAsset.mUsedIds.end()) { |
152 | 0 | throw DeadlyImportError("GLTF: two objects with the same ID exist"); |
153 | 0 | } |
154 | 0 | T *inst = new T(); |
155 | 0 | inst->id = id; |
156 | 0 | return Add(inst); |
157 | 0 | } Unexecuted instantiation: glTF::LazyDict<glTF::Buffer>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::BufferView>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Accessor>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Sampler>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Texture>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Image>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Material>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Skin>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Mesh>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Node>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Scene>::Create(char const*) Unexecuted instantiation: glTF::LazyDict<glTF::Animation>::Create(char const*) |
158 | | |
159 | | // |
160 | | // glTF dictionary objects methods |
161 | | // |
162 | | |
163 | | inline Buffer::Buffer() : |
164 | 0 | byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false) {} |
165 | | |
166 | 0 | inline Buffer::~Buffer() { |
167 | 0 | for (SEncodedRegion *reg : EncodedRegion_List) |
168 | 0 | delete reg; |
169 | 0 | } |
170 | | |
171 | 0 | inline const char *Buffer::TranslateId(Asset &r, const char *id) { |
172 | | // Compatibility with old spec |
173 | 0 | if (r.extensionsUsed.KHR_binary_glTF && strcmp(id, "KHR_binary_glTF") == 0) { |
174 | 0 | return "binary_glTF"; |
175 | 0 | } |
176 | | |
177 | 0 | return id; |
178 | 0 | } |
179 | | |
180 | 0 | inline void Buffer::Read(Value &obj, Asset &r) { |
181 | 0 | size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0); |
182 | 0 | byteLength = statedLength; |
183 | |
|
184 | 0 | Value *it = FindString(obj, "uri"); |
185 | 0 | if (!it) { |
186 | 0 | if (statedLength > 0) { |
187 | 0 | throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute"); |
188 | 0 | } |
189 | 0 | return; |
190 | 0 | } |
191 | | |
192 | 0 | const char *uri = it->GetString(); |
193 | |
|
194 | 0 | glTFCommon::Util::DataURI dataURI; |
195 | 0 | if (ParseDataURI(uri, it->GetStringLength(), dataURI)) { |
196 | 0 | if (dataURI.base64) { |
197 | 0 | uint8_t *data = nullptr; |
198 | 0 | this->byteLength = Base64::Decode(dataURI.data, dataURI.dataLength, data); |
199 | 0 | this->mData.reset(data, std::default_delete<uint8_t[]>()); |
200 | |
|
201 | 0 | if (statedLength > 0 && this->byteLength != statedLength) { |
202 | 0 | throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength), |
203 | 0 | " bytes, but found ", ai_to_string(dataURI.dataLength)); |
204 | 0 | } |
205 | 0 | } else { // assume raw data |
206 | 0 | if (statedLength != dataURI.dataLength) { |
207 | 0 | throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", ai_to_string(statedLength), |
208 | 0 | " bytes, but found ", ai_to_string(dataURI.dataLength)); |
209 | 0 | } |
210 | | |
211 | 0 | this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete<uint8_t[]>()); |
212 | 0 | memcpy(this->mData.get(), dataURI.data, dataURI.dataLength); |
213 | 0 | } |
214 | 0 | } else { // Local file |
215 | 0 | if (byteLength > 0) { |
216 | 0 | std::string dir = !r.mCurrentAssetDir.empty() ? ( |
217 | 0 | r.mCurrentAssetDir.back() == '/' ? |
218 | 0 | r.mCurrentAssetDir : |
219 | 0 | r.mCurrentAssetDir + '/') : |
220 | 0 | ""; |
221 | |
|
222 | 0 | IOStream *file = r.OpenFile(dir + uri, "rb"); |
223 | 0 | if (file) { |
224 | 0 | bool ok = LoadFromStream(*file, byteLength); |
225 | 0 | delete file; |
226 | |
|
227 | 0 | if (!ok) |
228 | 0 | throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\""); |
229 | 0 | } else { |
230 | 0 | throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\""); |
231 | 0 | } |
232 | 0 | } |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | 0 | inline bool Buffer::LoadFromStream(IOStream &stream, size_t length, size_t baseOffset) { |
237 | 0 | byteLength = length ? length : stream.FileSize(); |
238 | |
|
239 | 0 | if (baseOffset) { |
240 | 0 | stream.Seek(baseOffset, aiOrigin_SET); |
241 | 0 | } |
242 | |
|
243 | 0 | mData.reset(new uint8_t[byteLength], std::default_delete<uint8_t[]>()); |
244 | |
|
245 | 0 | if (stream.Read(mData.get(), byteLength, 1) != 1) { |
246 | 0 | return false; |
247 | 0 | } |
248 | 0 | return true; |
249 | 0 | } |
250 | | |
251 | 0 | 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) { |
252 | | // Check pointer to data |
253 | 0 | if (pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided."); |
254 | | |
255 | | // Check offset |
256 | 0 | if (pOffset > byteLength) { |
257 | 0 | const uint8_t val_size = 32; |
258 | |
|
259 | 0 | char val[val_size]; |
260 | |
|
261 | 0 | ai_snprintf(val, val_size, AI_SIZEFMT, pOffset); |
262 | 0 | throw DeadlyImportError("GLTF: incorrect offset value (", val, ") for marking encoded region."); |
263 | 0 | } |
264 | | |
265 | | // Check length |
266 | 0 | if ((pOffset + pEncodedData_Length) > byteLength) { |
267 | 0 | const uint8_t val_size = 64; |
268 | |
|
269 | 0 | char val[val_size]; |
270 | |
|
271 | 0 | ai_snprintf(val, val_size, AI_SIZEFMT "/" AI_SIZEFMT, pOffset, pEncodedData_Length); |
272 | 0 | throw DeadlyImportError("GLTF: encoded region with offset/length (", val, ") is out of range."); |
273 | 0 | } |
274 | | |
275 | | // Add new region |
276 | 0 | EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID)); |
277 | | // And set new value for "byteLength" |
278 | 0 | byteLength += (pDecodedData_Length - pEncodedData_Length); |
279 | 0 | } |
280 | | |
281 | 0 | inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) { |
282 | 0 | if ((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return; |
283 | | |
284 | 0 | for (SEncodedRegion *reg : EncodedRegion_List) { |
285 | 0 | if (reg->ID == pID) { |
286 | 0 | EncodedRegion_Current = reg; |
287 | |
|
288 | 0 | return; |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | 0 | throw DeadlyImportError("GLTF: EncodedRegion with ID: \"", pID, "\" not found."); |
293 | 0 | } |
294 | | |
295 | 0 | inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) { |
296 | 0 | const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count; |
297 | |
|
298 | 0 | uint8_t *new_data; |
299 | |
|
300 | 0 | if ((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) return false; |
301 | | |
302 | 0 | new_data = new uint8_t[new_data_size]; |
303 | | // Copy data which place before replacing part. |
304 | 0 | memcpy(new_data, mData.get(), pBufferData_Offset); |
305 | | // Copy new data. |
306 | 0 | memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count); |
307 | | // Copy data which place after replacing part. |
308 | 0 | memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset); |
309 | | // Apply new data |
310 | 0 | mData.reset(new_data, std::default_delete<uint8_t[]>()); |
311 | 0 | byteLength = new_data_size; |
312 | |
|
313 | 0 | return true; |
314 | 0 | } |
315 | | |
316 | 0 | inline size_t Buffer::AppendData(uint8_t *data, size_t length) { |
317 | 0 | size_t offset = this->byteLength; |
318 | 0 | Grow(length); |
319 | 0 | memcpy(mData.get() + offset, data, length); |
320 | 0 | return offset; |
321 | 0 | } |
322 | | |
323 | 0 | inline void Buffer::Grow(size_t amount) { |
324 | 0 | if (amount <= 0) return; |
325 | 0 | if (capacity >= byteLength + amount) { |
326 | 0 | byteLength += amount; |
327 | 0 | return; |
328 | 0 | } |
329 | | |
330 | | // Shift operation is standard way to divide integer by 2, it doesn't cast it to float back and forth, also works for odd numbers, |
331 | | // originally it would look like: static_cast<size_t>(capacity * 1.5f) |
332 | 0 | capacity = std::max(capacity + (capacity >> 1), byteLength + amount); |
333 | |
|
334 | 0 | uint8_t *b = new uint8_t[capacity]; |
335 | 0 | if (mData) memcpy(b, mData.get(), byteLength); |
336 | 0 | mData.reset(b, std::default_delete<uint8_t[]>()); |
337 | 0 | byteLength += amount; |
338 | 0 | } |
339 | | |
340 | | // |
341 | | // struct BufferView |
342 | | // |
343 | | |
344 | 0 | inline void BufferView::Read(Value &obj, Asset &r) { |
345 | 0 | const char *bufferId = MemberOrDefault<const char *>(obj, "buffer", 0); |
346 | 0 | if (bufferId) { |
347 | 0 | buffer = r.buffers.Get(bufferId); |
348 | 0 | } |
349 | |
|
350 | 0 | byteOffset = MemberOrDefault(obj, "byteOffset", 0u); |
351 | 0 | byteLength = MemberOrDefault(obj, "byteLength", 0u); |
352 | 0 | } |
353 | | |
354 | | // |
355 | | // struct Accessor |
356 | | // |
357 | | |
358 | 0 | inline void Accessor::Read(Value &obj, Asset &r) { |
359 | 0 | const char *bufferViewId = MemberOrDefault<const char *>(obj, "bufferView", 0); |
360 | 0 | if (bufferViewId) { |
361 | 0 | bufferView = r.bufferViews.Get(bufferViewId); |
362 | 0 | } |
363 | |
|
364 | 0 | byteOffset = MemberOrDefault(obj, "byteOffset", 0u); |
365 | 0 | byteStride = MemberOrDefault(obj, "byteStride", 0u); |
366 | 0 | componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); |
367 | 0 | count = MemberOrDefault(obj, "count", 0u); |
368 | |
|
369 | 0 | const char *typestr; |
370 | 0 | type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR; |
371 | 0 | } |
372 | | |
373 | 0 | inline unsigned int Accessor::GetNumComponents() { |
374 | 0 | return AttribType::GetNumComponents(type); |
375 | 0 | } |
376 | | |
377 | 0 | inline unsigned int Accessor::GetBytesPerComponent() { |
378 | 0 | return int(ComponentTypeSize(componentType)); |
379 | 0 | } |
380 | | |
381 | 0 | inline unsigned int Accessor::GetElementSize() { |
382 | 0 | return GetNumComponents() * GetBytesPerComponent(); |
383 | 0 | } |
384 | | |
385 | 0 | inline uint8_t *Accessor::GetPointer() { |
386 | 0 | if (!bufferView || !bufferView->buffer) return nullptr; |
387 | 0 | uint8_t *basePtr = bufferView->buffer->GetPointer(); |
388 | 0 | if (!basePtr) return nullptr; |
389 | | |
390 | 0 | size_t offset = byteOffset + bufferView->byteOffset; |
391 | | |
392 | | // Check if region is encoded. |
393 | 0 | if (bufferView->buffer->EncodedRegion_Current != nullptr) { |
394 | 0 | const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset; |
395 | 0 | const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length; |
396 | |
|
397 | 0 | if ((offset >= begin) && (offset < end)) |
398 | 0 | return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin]; |
399 | 0 | } |
400 | | |
401 | 0 | return basePtr + offset; |
402 | 0 | } |
403 | | |
404 | | namespace { |
405 | | inline void CopyData(size_t count, |
406 | | const uint8_t *src, size_t src_stride, |
407 | 0 | uint8_t *dst, size_t dst_stride) { |
408 | 0 | if (src_stride == dst_stride) { |
409 | 0 | memcpy(dst, src, count * src_stride); |
410 | 0 | } else { |
411 | 0 | size_t sz = std::min(src_stride, dst_stride); |
412 | 0 | for (size_t i = 0; i < count; ++i) { |
413 | 0 | memcpy(dst, src, sz); |
414 | 0 | if (sz < dst_stride) { |
415 | 0 | memset(dst + sz, 0, dst_stride - sz); |
416 | 0 | } |
417 | 0 | src += src_stride; |
418 | 0 | dst += dst_stride; |
419 | 0 | } |
420 | 0 | } |
421 | 0 | } Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::CopyData(unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long) Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::CopyData(unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long) |
422 | | } // namespace |
423 | | |
424 | | template <class T> |
425 | 0 | bool Accessor::ExtractData(T *&outData) { |
426 | 0 | uint8_t *data = GetPointer(); |
427 | 0 | if (!data) return false; |
428 | | |
429 | 0 | const size_t elemSize = GetElementSize(); |
430 | 0 | const size_t totalSize = elemSize * count; |
431 | |
|
432 | 0 | const size_t stride = byteStride ? byteStride : elemSize; |
433 | |
|
434 | 0 | const size_t targetElemSize = sizeof(T); |
435 | 0 | ai_assert(elemSize <= targetElemSize); |
436 | |
|
437 | 0 | ai_assert(count * stride <= bufferView->byteLength); |
438 | |
|
439 | 0 | outData = new T[count]; |
440 | 0 | if (stride == elemSize && targetElemSize == elemSize) { |
441 | 0 | memcpy(outData, data, totalSize); |
442 | 0 | } else { |
443 | 0 | for (size_t i = 0; i < count; ++i) { |
444 | 0 | memcpy(outData + i, data + i * stride, elemSize); |
445 | 0 | } |
446 | 0 | } |
447 | |
|
448 | 0 | return true; |
449 | 0 | } |
450 | | |
451 | 0 | inline void Accessor::WriteData(size_t cnt, const void *src_buffer, size_t src_stride) { |
452 | 0 | uint8_t *buffer_ptr = bufferView->buffer->GetPointer(); |
453 | 0 | size_t offset = byteOffset + bufferView->byteOffset; |
454 | |
|
455 | 0 | size_t dst_stride = GetNumComponents() * GetBytesPerComponent(); |
456 | |
|
457 | 0 | const uint8_t *src = reinterpret_cast<const uint8_t *>(src_buffer); |
458 | 0 | uint8_t *dst = reinterpret_cast<uint8_t *>(buffer_ptr + offset); |
459 | |
|
460 | 0 | ai_assert(dst + count * dst_stride <= buffer_ptr + bufferView->buffer->byteLength); |
461 | 0 | CopyData(cnt, src, src_stride, dst, dst_stride); |
462 | 0 | } |
463 | | |
464 | | inline Accessor::Indexer::Indexer(Accessor &acc) : |
465 | 0 | accessor(acc), data(acc.GetPointer()), elemSize(acc.GetElementSize()), stride(acc.byteStride ? acc.byteStride : elemSize) { |
466 | 0 | } |
467 | | |
468 | | //! Accesses the i-th value as defined by the accessor |
469 | | template <class T> |
470 | 0 | T Accessor::Indexer::GetValue(int i) { |
471 | 0 | ai_assert(data); |
472 | 0 | ai_assert(i * stride < accessor.bufferView->byteLength); |
473 | 0 | T value = T(); |
474 | 0 | memcpy(&value, data + i * stride, elemSize); |
475 | | //value >>= 8 * (sizeof(T) - elemSize); |
476 | 0 | return value; |
477 | 0 | } |
478 | | |
479 | | inline Image::Image() : |
480 | 0 | width(0), height(0), mDataLength(0) { |
481 | 0 | } |
482 | | |
483 | 0 | inline void Image::Read(Value &obj, Asset &r) { |
484 | | // Check for extensions first (to detect binary embedded data) |
485 | 0 | if (Value *extensions = FindObject(obj, "extensions")) { |
486 | 0 | if (r.extensionsUsed.KHR_binary_glTF) { |
487 | 0 | if (Value *ext = FindObject(*extensions, "KHR_binary_glTF")) { |
488 | |
|
489 | 0 | width = MemberOrDefault(*ext, "width", 0); |
490 | 0 | height = MemberOrDefault(*ext, "height", 0); |
491 | |
|
492 | 0 | ReadMember(*ext, "mimeType", mimeType); |
493 | |
|
494 | 0 | const char *bufferViewId; |
495 | 0 | if (ReadMember(*ext, "bufferView", bufferViewId)) { |
496 | 0 | Ref<BufferView> bv = r.bufferViews.Get(bufferViewId); |
497 | 0 | if (bv) { |
498 | 0 | mDataLength = bv->byteLength; |
499 | 0 | mData.reset(new uint8_t[mDataLength]); |
500 | 0 | memcpy(mData.get(), bv->buffer->GetPointer() + bv->byteOffset, mDataLength); |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | 0 | } |
505 | 0 | } |
506 | |
|
507 | 0 | if (!mDataLength) { |
508 | 0 | Value *curUri = FindString(obj, "uri"); |
509 | 0 | if (nullptr != curUri) { |
510 | 0 | const char *uristr = curUri->GetString(); |
511 | |
|
512 | 0 | glTFCommon::Util::DataURI dataURI; |
513 | 0 | if (ParseDataURI(uristr, curUri->GetStringLength(), dataURI)) { |
514 | 0 | mimeType = dataURI.mediaType; |
515 | 0 | if (dataURI.base64) { |
516 | 0 | uint8_t *ptr = nullptr; |
517 | 0 | mDataLength = Base64::Decode(dataURI.data, dataURI.dataLength, ptr); |
518 | 0 | mData.reset(ptr); |
519 | 0 | } |
520 | 0 | } else { |
521 | 0 | this->uri = uristr; |
522 | 0 | } |
523 | 0 | } |
524 | 0 | } |
525 | 0 | } |
526 | | |
527 | 0 | inline uint8_t *Image::StealData() { |
528 | 0 | mDataLength = 0; |
529 | 0 | return mData.release(); |
530 | 0 | } |
531 | | |
532 | 0 | inline void Image::SetData(uint8_t *data, size_t length, Asset &r) { |
533 | 0 | Ref<Buffer> b = r.GetBodyBuffer(); |
534 | 0 | if (b) { // binary file: append to body |
535 | 0 | std::string bvId = r.FindUniqueID(this->id, "imgdata"); |
536 | 0 | bufferView = r.bufferViews.Create(bvId); |
537 | |
|
538 | 0 | bufferView->buffer = b; |
539 | 0 | bufferView->byteLength = length; |
540 | 0 | bufferView->byteOffset = b->AppendData(data, length); |
541 | 0 | } else { // text file: will be stored as a data uri |
542 | 0 | uint8_t *temp = new uint8_t[length]; |
543 | 0 | memcpy(temp, data, length); |
544 | 0 | this->mData.reset(temp); |
545 | 0 | this->mDataLength = length; |
546 | 0 | } |
547 | 0 | } |
548 | | |
549 | 0 | inline void Sampler::Read(Value &obj, Asset & /*r*/) { |
550 | 0 | SetDefaults(); |
551 | |
|
552 | 0 | ReadMember(obj, "magFilter", magFilter); |
553 | 0 | ReadMember(obj, "minFilter", minFilter); |
554 | 0 | ReadMember(obj, "wrapS", wrapS); |
555 | 0 | ReadMember(obj, "wrapT", wrapT); |
556 | 0 | } |
557 | | |
558 | 0 | inline void Sampler::SetDefaults() { |
559 | 0 | magFilter = SamplerMagFilter_Linear; |
560 | 0 | minFilter = SamplerMinFilter_Linear; |
561 | 0 | wrapS = SamplerWrap_Repeat; |
562 | 0 | wrapT = SamplerWrap_Repeat; |
563 | 0 | } |
564 | | |
565 | 0 | inline void Texture::Read(Value &obj, Asset &r) { |
566 | 0 | const char *sourcestr; |
567 | 0 | if (ReadMember(obj, "source", sourcestr)) { |
568 | 0 | source = r.images.Get(sourcestr); |
569 | 0 | } |
570 | |
|
571 | 0 | const char *samplerstr; |
572 | 0 | if (ReadMember(obj, "sampler", samplerstr)) { |
573 | 0 | sampler = r.samplers.Get(samplerstr); |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | | namespace { |
578 | 0 | inline void ReadMaterialProperty(Asset &r, Value &vals, const char *propName, TexProperty &out) { |
579 | 0 | if (Value *prop = FindMember(vals, propName)) { |
580 | 0 | if (prop->IsString()) { |
581 | 0 | out.texture = r.textures.Get(prop->GetString()); |
582 | 0 | } else { |
583 | 0 | ReadValue(*prop, out.color); |
584 | 0 | } |
585 | 0 | } |
586 | 0 | } Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::ReadMaterialProperty(glTF::Asset&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, glTF::TexProperty&) Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::ReadMaterialProperty(glTF::Asset&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, glTF::TexProperty&) |
587 | | } // namespace |
588 | | |
589 | 0 | inline void Material::Read(Value &material, Asset &r) { |
590 | 0 | SetDefaults(); |
591 | |
|
592 | 0 | if (Value *values = FindObject(material, "values")) { |
593 | 0 | ReadMaterialProperty(r, *values, "ambient", this->ambient); |
594 | 0 | ReadMaterialProperty(r, *values, "diffuse", this->diffuse); |
595 | 0 | ReadMaterialProperty(r, *values, "specular", this->specular); |
596 | |
|
597 | 0 | ReadMember(*values, "transparency", transparency); |
598 | 0 | ReadMember(*values, "shininess", shininess); |
599 | 0 | } |
600 | |
|
601 | 0 | if (Value *extensions = FindObject(material, "extensions")) { |
602 | 0 | if (r.extensionsUsed.KHR_materials_common) { |
603 | 0 | if (Value *ext = FindObject(*extensions, "KHR_materials_common")) { |
604 | 0 | if (Value *tnq = FindString(*ext, "technique")) { |
605 | 0 | const char *t = tnq->GetString(); |
606 | 0 | if (strcmp(t, "BLINN") == 0) |
607 | 0 | technique = Technique_BLINN; |
608 | 0 | else if (strcmp(t, "PHONG") == 0) |
609 | 0 | technique = Technique_PHONG; |
610 | 0 | else if (strcmp(t, "LAMBERT") == 0) |
611 | 0 | technique = Technique_LAMBERT; |
612 | 0 | else if (strcmp(t, "CONSTANT") == 0) |
613 | 0 | technique = Technique_CONSTANT; |
614 | 0 | } |
615 | |
|
616 | 0 | if (Value *values = FindObject(*ext, "values")) { |
617 | 0 | ReadMaterialProperty(r, *values, "ambient", this->ambient); |
618 | 0 | ReadMaterialProperty(r, *values, "diffuse", this->diffuse); |
619 | 0 | ReadMaterialProperty(r, *values, "specular", this->specular); |
620 | |
|
621 | 0 | ReadMember(*values, "doubleSided", doubleSided); |
622 | 0 | ReadMember(*values, "transparent", transparent); |
623 | 0 | ReadMember(*values, "transparency", transparency); |
624 | 0 | ReadMember(*values, "shininess", shininess); |
625 | 0 | } |
626 | 0 | } |
627 | 0 | } |
628 | 0 | } |
629 | 0 | } |
630 | | |
631 | | namespace { |
632 | 0 | void SetVector(vec4 &v, float x, float y, float z, float w) { |
633 | 0 | v[0] = x; |
634 | 0 | v[1] = y; |
635 | 0 | v[2] = z; |
636 | 0 | v[3] = w; |
637 | 0 | } Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::SetVector(float (&) [4], float, float, float, float) Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::SetVector(float (&) [4], float, float, float, float) |
638 | | } // namespace |
639 | | |
640 | 0 | inline void Material::SetDefaults() { |
641 | 0 | SetVector(ambient.color, 0, 0, 0, 1); |
642 | 0 | SetVector(diffuse.color, 0, 0, 0, 1); |
643 | 0 | SetVector(specular.color, 0, 0, 0, 1); |
644 | 0 | SetVector(emission.color, 0, 0, 0, 1); |
645 | |
|
646 | 0 | doubleSided = false; |
647 | 0 | transparent = false; |
648 | 0 | transparency = 1.0; |
649 | 0 | shininess = 0.0; |
650 | |
|
651 | 0 | technique = Technique_undefined; |
652 | 0 | } |
653 | | |
654 | | namespace { |
655 | | |
656 | | template <int N> |
657 | 0 | inline int Compare(const char *attr, const char (&str)[N]) { |
658 | 0 | return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0; |
659 | 0 | } Unexecuted instantiation: glTFExporter.cpp:int glTF::(anonymous namespace)::Compare<9>(char const*, char const (&) [9]) Unexecuted instantiation: glTFExporter.cpp:int glTF::(anonymous namespace)::Compare<7>(char const*, char const (&) [7]) Unexecuted instantiation: glTFExporter.cpp:int glTF::(anonymous namespace)::Compare<6>(char const*, char const (&) [6]) Unexecuted instantiation: glTFExporter.cpp:int glTF::(anonymous namespace)::Compare<12>(char const*, char const (&) [12]) Unexecuted instantiation: glTFImporter.cpp:int glTF::(anonymous namespace)::Compare<9>(char const*, char const (&) [9]) Unexecuted instantiation: glTFImporter.cpp:int glTF::(anonymous namespace)::Compare<7>(char const*, char const (&) [7]) Unexecuted instantiation: glTFImporter.cpp:int glTF::(anonymous namespace)::Compare<6>(char const*, char const (&) [6]) Unexecuted instantiation: glTFImporter.cpp:int glTF::(anonymous namespace)::Compare<12>(char const*, char const (&) [12]) |
660 | | |
661 | 0 | inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) { |
662 | 0 | if ((pos = Compare(attr, "POSITION"))) { |
663 | 0 | v = &(p.attributes.position); |
664 | 0 | } else if ((pos = Compare(attr, "NORMAL"))) { |
665 | 0 | v = &(p.attributes.normal); |
666 | 0 | } else if ((pos = Compare(attr, "TEXCOORD"))) { |
667 | 0 | v = &(p.attributes.texcoord); |
668 | 0 | } else if ((pos = Compare(attr, "COLOR"))) { |
669 | 0 | v = &(p.attributes.color); |
670 | 0 | } else if ((pos = Compare(attr, "JOINT"))) { |
671 | 0 | v = &(p.attributes.joint); |
672 | 0 | } else if ((pos = Compare(attr, "JOINTMATRIX"))) { |
673 | 0 | v = &(p.attributes.jointmatrix); |
674 | 0 | } else if ((pos = Compare(attr, "WEIGHT"))) { |
675 | 0 | v = &(p.attributes.weight); |
676 | 0 | } else |
677 | 0 | return false; |
678 | 0 | return true; |
679 | 0 | } Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::GetAttribVector(glTF::Mesh::Primitive&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF::Accessor> > >*&, int&) Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::GetAttribVector(glTF::Mesh::Primitive&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF::Accessor> > >*&, int&) |
680 | | } // namespace |
681 | | |
682 | 0 | inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) { |
683 | | /****************** Mesh primitives ******************/ |
684 | 0 | Value *curPrimitives = FindArray(pJSON_Object, "primitives"); |
685 | 0 | if (nullptr != curPrimitives) { |
686 | 0 | this->primitives.resize(curPrimitives->Size()); |
687 | 0 | for (unsigned int i = 0; i < curPrimitives->Size(); ++i) { |
688 | 0 | Value &primitive = (*curPrimitives)[i]; |
689 | |
|
690 | 0 | Primitive &prim = this->primitives[i]; |
691 | 0 | prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES); |
692 | |
|
693 | 0 | if (Value *attrs = FindObject(primitive, "attributes")) { |
694 | 0 | for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) { |
695 | 0 | if (!it->value.IsString()) continue; |
696 | 0 | const char *attr = it->name.GetString(); |
697 | | // Valid attribute semantics include POSITION, NORMAL, TEXCOORD, COLOR, JOINT, JOINTMATRIX, |
698 | | // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc. |
699 | |
|
700 | 0 | int undPos = 0; |
701 | 0 | Mesh::AccessorList *vec = nullptr; |
702 | 0 | if (GetAttribVector(prim, attr, vec, undPos)) { |
703 | 0 | size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0; |
704 | 0 | if ((*vec).size() <= idx) (*vec).resize(idx + 1); |
705 | 0 | (*vec)[idx] = pAsset_Root.accessors.Get(it->value.GetString()); |
706 | 0 | } |
707 | 0 | } |
708 | 0 | } |
709 | |
|
710 | 0 | if (Value *indices = FindString(primitive, "indices")) { |
711 | 0 | prim.indices = pAsset_Root.accessors.Get(indices->GetString()); |
712 | 0 | } |
713 | |
|
714 | 0 | if (Value *material = FindString(primitive, "material")) { |
715 | 0 | prim.material = pAsset_Root.materials.Get(material->GetString()); |
716 | 0 | } |
717 | 0 | } |
718 | 0 | } |
719 | | |
720 | | /****************** Mesh extensions ******************/ |
721 | 0 | Value *json_extensions = FindObject(pJSON_Object, "extensions"); |
722 | |
|
723 | 0 | if (json_extensions == nullptr) goto mr_skip_extensions; |
724 | | |
725 | 0 | #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC |
726 | 0 | for (Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++) { |
727 | 0 | if (it_memb->name.GetString() == std::string("Open3DGC-compression")) { |
728 | | // Search for compressed data. |
729 | | // Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and |
730 | | // new data will replace old encoded part by request. In fact \"compressedData\" is kind of "accessor" structure. |
731 | 0 | Value *comp_data = FindObject(it_memb->value, "compressedData"); |
732 | |
|
733 | 0 | if (comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\"."); |
734 | | |
735 | 0 | ASSIMP_LOG_INFO("GLTF: Decompressing Open3DGC data."); |
736 | | |
737 | | /************** Read data from JSON-document **************/ |
738 | 0 | #define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \ |
739 | 0 | if (!ReadMember(*comp_data, pFieldName, pOut)) { \ |
740 | 0 | throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \ |
741 | 0 | } |
742 | |
|
743 | 0 | const char *mode_str; |
744 | 0 | const char *type_str; |
745 | 0 | ComponentType component_type; |
746 | 0 | SCompression_Open3DGC *ext_o3dgc = new SCompression_Open3DGC; |
747 | |
|
748 | 0 | MESH_READ_COMPRESSEDDATA_MEMBER("buffer", ext_o3dgc->Buffer); |
749 | 0 | MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", ext_o3dgc->Offset); |
750 | 0 | MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type); |
751 | 0 | MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str); |
752 | 0 | MESH_READ_COMPRESSEDDATA_MEMBER("count", ext_o3dgc->Count); |
753 | 0 | MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str); |
754 | 0 | MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", ext_o3dgc->IndicesCount); |
755 | 0 | MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", ext_o3dgc->VerticesCount); |
756 | |
|
757 | 0 | #undef MESH_READ_COMPRESSEDDATA_MEMBER |
758 | | |
759 | | // Check some values |
760 | 0 | if (strcmp(type_str, "SCALAR")) throw DeadlyImportError("GLTF: only \"SCALAR\" type is supported for compressed data."); |
761 | 0 | if (component_type != ComponentType_UNSIGNED_BYTE) throw DeadlyImportError("GLTF: only \"UNSIGNED_BYTE\" component type is supported for compressed data."); |
762 | | |
763 | | // Set read/write data mode. |
764 | 0 | if (strcmp(mode_str, "binary") == 0) |
765 | 0 | ext_o3dgc->Binary = true; |
766 | 0 | else if (strcmp(mode_str, "ascii") == 0) |
767 | 0 | ext_o3dgc->Binary = false; |
768 | 0 | else |
769 | 0 | throw DeadlyImportError("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"", mode_str, "\"."); |
770 | | |
771 | | /************************ Decoding ************************/ |
772 | 0 | Decode_O3DGC(*ext_o3dgc, pAsset_Root); |
773 | 0 | Extension.push_back(ext_o3dgc); // store info in mesh extensions list. |
774 | 0 | } // if(it_memb->name.GetString() == "Open3DGC-compression") |
775 | 0 | else { |
776 | 0 | throw DeadlyImportError("GLTF: Unknown mesh extension: \"", it_memb->name.GetString(), "\"."); |
777 | 0 | } |
778 | 0 | } // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++) |
779 | 0 | #endif |
780 | | |
781 | 0 | mr_skip_extensions: |
782 | |
|
783 | 0 | return; // After label some operators must be present. |
784 | 0 | } |
785 | | |
786 | | #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC |
787 | 0 | inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root) { |
788 | 0 | typedef unsigned short IndicesType; ///< \sa glTFExporter::ExportMeshes. |
789 | |
|
790 | 0 | o3dgc::SC3DMCDecoder<IndicesType> decoder; |
791 | 0 | o3dgc::IndexedFaceSet<IndicesType> ifs; |
792 | 0 | o3dgc::BinaryStream bstream; |
793 | 0 | uint8_t *decoded_data; |
794 | 0 | size_t decoded_data_size = 0; |
795 | 0 | Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer); |
796 | | |
797 | | // Read data from buffer and place it in BinaryStream for decoder. |
798 | | // Just "Count" because always is used type equivalent to uint8_t. |
799 | 0 | bstream.LoadFromBuffer(&buf->GetPointer()[pCompression_Open3DGC.Offset], static_cast<unsigned long>(pCompression_Open3DGC.Count)); |
800 | | |
801 | | // After decoding header we can get size of primitives. |
802 | 0 | if (decoder.DecodeHeader(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC header."); |
803 | | |
804 | | /****************** Get sizes of arrays and check sizes ******************/ |
805 | | // Note. See "Limitations for meshes when using Open3DGC-compression". |
806 | | |
807 | | // Indices |
808 | 0 | size_t size_coordindex = ifs.GetNCoordIndex() * 3; // See float attributes note. |
809 | |
|
810 | 0 | if (primitives[0].indices->count != size_coordindex) |
811 | 0 | throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (", ai_to_string(size_coordindex), |
812 | 0 | ") not equal to uncompressed (", ai_to_string(primitives[0].indices->count), ")."); |
813 | | |
814 | 0 | size_coordindex *= sizeof(IndicesType); |
815 | | // Coordinates |
816 | 0 | size_t size_coord = ifs.GetNCoord(); // See float attributes note. |
817 | |
|
818 | 0 | if (primitives[0].attributes.position[0]->count != size_coord) |
819 | 0 | throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (", ai_to_string(size_coord), |
820 | 0 | ") not equal to uncompressed (", ai_to_string(primitives[0].attributes.position[0]->count), ")."); |
821 | | |
822 | 0 | size_coord *= 3 * sizeof(float); |
823 | | // Normals |
824 | 0 | size_t size_normal = ifs.GetNNormal(); // See float attributes note. |
825 | |
|
826 | 0 | if (primitives[0].attributes.normal[0]->count != size_normal) |
827 | 0 | throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (", ai_to_string(size_normal), |
828 | 0 | ") not equal to uncompressed (", ai_to_string(primitives[0].attributes.normal[0]->count), ")."); |
829 | | |
830 | 0 | size_normal *= 3 * sizeof(float); |
831 | | // Additional attributes. |
832 | 0 | std::vector<size_t> size_floatattr; |
833 | 0 | std::vector<size_t> size_intattr; |
834 | |
|
835 | 0 | size_floatattr.resize(ifs.GetNumFloatAttributes()); |
836 | 0 | size_intattr.resize(ifs.GetNumIntAttributes()); |
837 | |
|
838 | 0 | decoded_data_size = size_coordindex + size_coord + size_normal; |
839 | 0 | for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) { |
840 | | // size = number_of_elements * components_per_element * size_of_component. |
841 | | // Note. But as you can see above, at first we are use this variable in meaning "count". After checking count of objects... |
842 | 0 | size_t tval = ifs.GetNFloatAttribute(static_cast<unsigned long>(idx)); |
843 | |
|
844 | 0 | switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) { |
845 | 0 | case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD: |
846 | | // Check situation when encoded data contain texture coordinates but primitive not. |
847 | 0 | if (idx_texcoord < primitives[0].attributes.texcoord.size()) { |
848 | 0 | if (primitives[0].attributes.texcoord[idx]->count != tval) |
849 | 0 | throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (", ai_to_string(tval), |
850 | 0 | ") not equal to uncompressed (", ai_to_string(primitives[0].attributes.texcoord[idx]->count), ")."); |
851 | | |
852 | 0 | idx_texcoord++; |
853 | 0 | } else { |
854 | 0 | ifs.SetNFloatAttribute(static_cast<unsigned long>(idx), 0ul); // Disable decoding this attribute. |
855 | 0 | } |
856 | | |
857 | 0 | break; |
858 | 0 | default: |
859 | 0 | throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx)))); |
860 | 0 | } |
861 | | |
862 | 0 | tval *= ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real); // After checking count of objects we can get size of array. |
863 | 0 | size_floatattr[idx] = tval; |
864 | 0 | decoded_data_size += tval; |
865 | 0 | } |
866 | | |
867 | 0 | for (size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) { |
868 | | // size = number_of_elements * components_per_element * size_of_component. See float attributes note. |
869 | 0 | size_t tval = ifs.GetNIntAttribute(static_cast<unsigned long>(idx)); |
870 | 0 | switch (ifs.GetIntAttributeType(static_cast<unsigned long>(idx))) { |
871 | 0 | case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN: |
872 | 0 | case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX: |
873 | 0 | case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID: |
874 | 0 | case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID: |
875 | 0 | break; |
876 | | |
877 | 0 | default: |
878 | 0 | throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx)))); |
879 | 0 | } |
880 | | |
881 | 0 | tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long); // See float attributes note. |
882 | 0 | size_intattr[idx] = tval; |
883 | 0 | decoded_data_size += tval; |
884 | 0 | } |
885 | | |
886 | | // Create array for decoded data. |
887 | 0 | decoded_data = new uint8_t[decoded_data_size]; |
888 | | |
889 | | /****************** Set right array regions for decoder ******************/ |
890 | |
|
891 | 0 | auto get_buf_offset = [](Ref<Accessor> &pAccessor) -> size_t { return pAccessor->byteOffset + pAccessor->bufferView->byteOffset; }; |
892 | | |
893 | | // Indices |
894 | 0 | ifs.SetCoordIndex((IndicesType *)(decoded_data + get_buf_offset(primitives[0].indices))); |
895 | | // Coordinates |
896 | 0 | ifs.SetCoord((o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.position[0]))); |
897 | | // Normals |
898 | 0 | if (size_normal) { |
899 | 0 | ifs.SetNormal((o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.normal[0]))); |
900 | 0 | } |
901 | |
|
902 | 0 | for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) { |
903 | 0 | switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) { |
904 | 0 | case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD: |
905 | 0 | if (idx_texcoord < primitives[0].attributes.texcoord.size()) { |
906 | | // See above about absent attributes. |
907 | 0 | ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx]))); |
908 | 0 | idx_texcoord++; |
909 | 0 | } |
910 | |
|
911 | 0 | break; |
912 | 0 | default: |
913 | 0 | throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx)))); |
914 | 0 | } |
915 | 0 | } |
916 | | |
917 | 0 | for (size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) { |
918 | 0 | switch (ifs.GetIntAttributeType(static_cast<unsigned int>(idx))) { |
919 | 0 | case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN: |
920 | 0 | case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX: |
921 | 0 | case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID: |
922 | 0 | case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID: |
923 | 0 | break; |
924 | | |
925 | | // ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint))); |
926 | 0 | default: |
927 | 0 | throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx)))); |
928 | 0 | } |
929 | 0 | } |
930 | | |
931 | | // |
932 | | // Decode data |
933 | | // |
934 | 0 | if (decoder.DecodePayload(ifs, bstream) != o3dgc::O3DGC_OK) { |
935 | 0 | throw DeadlyImportError("GLTF: can not decode Open3DGC data."); |
936 | 0 | } |
937 | | |
938 | | // Set encoded region for "buffer". |
939 | 0 | buf->EncodedRegion_Mark(pCompression_Open3DGC.Offset, pCompression_Open3DGC.Count, decoded_data, decoded_data_size, id); |
940 | | // No. Do not delete "output_data". After calling "EncodedRegion_Mark" bufferView is owner of "output_data". |
941 | | // "delete [] output_data;" |
942 | 0 | } |
943 | | #endif |
944 | | |
945 | 0 | inline void Camera::Read(Value &obj, Asset & /*r*/) { |
946 | 0 | type = MemberOrDefault(obj, "type", Camera::Perspective); |
947 | |
|
948 | 0 | const char *subobjId = (type == Camera::Orthographic) ? "orthographic" : "perspective"; |
949 | |
|
950 | 0 | Value *it = FindObject(obj, subobjId); |
951 | 0 | if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters"); |
952 | | |
953 | 0 | if (type == Camera::Perspective) { |
954 | 0 | perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f); |
955 | 0 | perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f / 2.f); |
956 | 0 | perspective.zfar = MemberOrDefault(*it, "zfar", 100.f); |
957 | 0 | perspective.znear = MemberOrDefault(*it, "znear", 0.01f); |
958 | 0 | } else { |
959 | 0 | ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f); |
960 | 0 | ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f); |
961 | 0 | ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f); |
962 | 0 | ortographic.znear = MemberOrDefault(*it, "znear", 0.01f); |
963 | 0 | } |
964 | 0 | } |
965 | | |
966 | 0 | inline void Light::Read(Value &obj, Asset & /*r*/) { |
967 | 0 | SetDefaults(); |
968 | |
|
969 | 0 | Value *curType = FindString(obj, "type"); |
970 | 0 | if (nullptr != curType) { |
971 | 0 | const char *t = curType->GetString(); |
972 | 0 | if (strcmp(t, "ambient") == 0) |
973 | 0 | this->type = Type_ambient; |
974 | 0 | else if (strcmp(t, "directional") == 0) |
975 | 0 | this->type = Type_directional; |
976 | 0 | else if (strcmp(t, "point") == 0) |
977 | 0 | this->type = Type_point; |
978 | 0 | else if (strcmp(t, "spot") == 0) |
979 | 0 | this->type = Type_spot; |
980 | |
|
981 | 0 | if (this->type != Type_undefined) { |
982 | 0 | if (Value *vals = FindString(obj, t)) { |
983 | 0 | ReadMember(*vals, "color", color); |
984 | |
|
985 | 0 | ReadMember(*vals, "constantAttenuation", constantAttenuation); |
986 | 0 | ReadMember(*vals, "linearAttenuation", linearAttenuation); |
987 | 0 | ReadMember(*vals, "quadraticAttenuation", quadraticAttenuation); |
988 | 0 | ReadMember(*vals, "distance", distance); |
989 | |
|
990 | 0 | ReadMember(*vals, "falloffAngle", falloffAngle); |
991 | 0 | ReadMember(*vals, "falloffExponent", falloffExponent); |
992 | 0 | } |
993 | 0 | } |
994 | 0 | } |
995 | 0 | } |
996 | | |
997 | 0 | inline void Light::SetDefaults() { |
998 | | #ifndef M_PI |
999 | | const float M_PI = 3.14159265358979323846f; |
1000 | | #endif |
1001 | |
|
1002 | 0 | type = Type_undefined; |
1003 | |
|
1004 | 0 | SetVector(color, 0.f, 0.f, 0.f, 1.f); |
1005 | |
|
1006 | 0 | constantAttenuation = 0.f; |
1007 | 0 | linearAttenuation = 1.f; |
1008 | 0 | quadraticAttenuation = 1.f; |
1009 | 0 | distance = 0.f; |
1010 | |
|
1011 | 0 | falloffAngle = static_cast<float>(M_PI / 2.f); |
1012 | 0 | falloffExponent = 0.f; |
1013 | 0 | } |
1014 | | |
1015 | 0 | inline void Node::Read(Value &obj, Asset &r) { |
1016 | 0 | if (name.empty()) { |
1017 | 0 | name = id; |
1018 | 0 | } |
1019 | |
|
1020 | 0 | Value *curChildren = FindArray(obj, "children"); |
1021 | 0 | if (nullptr != curChildren) { |
1022 | 0 | this->children.reserve(curChildren->Size()); |
1023 | 0 | for (unsigned int i = 0; i < curChildren->Size(); ++i) { |
1024 | 0 | Value &child = (*curChildren)[i]; |
1025 | 0 | if (child.IsString()) { |
1026 | | // get/create the child node |
1027 | 0 | Ref<Node> chn = r.nodes.Get(child.GetString()); |
1028 | 0 | if (chn) this->children.push_back(chn); |
1029 | 0 | } |
1030 | 0 | } |
1031 | 0 | } |
1032 | |
|
1033 | 0 | Value *curMatrix = FindArray(obj, "matrix"); |
1034 | 0 | if (nullptr != curMatrix) { |
1035 | 0 | ReadValue(*curMatrix, this->matrix); |
1036 | 0 | } else { |
1037 | 0 | ReadMember(obj, "translation", translation); |
1038 | 0 | ReadMember(obj, "scale", scale); |
1039 | 0 | ReadMember(obj, "rotation", rotation); |
1040 | 0 | } |
1041 | |
|
1042 | 0 | Value *curMeshes = FindArray(obj, "meshes"); |
1043 | 0 | if (nullptr != curMeshes) { |
1044 | 0 | unsigned int numMeshes = (unsigned int)curMeshes->Size(); |
1045 | |
|
1046 | 0 | std::vector<unsigned int> meshList; |
1047 | |
|
1048 | 0 | this->meshes.reserve(numMeshes); |
1049 | 0 | for (unsigned i = 0; i < numMeshes; ++i) { |
1050 | 0 | if ((*curMeshes)[i].IsString()) { |
1051 | 0 | Ref<Mesh> mesh = r.meshes.Get((*curMeshes)[i].GetString()); |
1052 | 0 | if (mesh) { |
1053 | 0 | this->meshes.push_back(mesh); |
1054 | 0 | } |
1055 | 0 | } |
1056 | 0 | } |
1057 | 0 | } |
1058 | |
|
1059 | 0 | Value *curCamera = FindString(obj, "camera"); |
1060 | 0 | if (nullptr != curCamera) { |
1061 | 0 | this->camera = r.cameras.Get(curCamera->GetString()); |
1062 | 0 | if (this->camera) { |
1063 | 0 | this->camera->id = this->id; |
1064 | 0 | } |
1065 | 0 | } |
1066 | | |
1067 | | // TODO load "skeletons", "skin", "jointName" |
1068 | |
|
1069 | 0 | if (Value *extensions = FindObject(obj, "extensions")) { |
1070 | 0 | if (r.extensionsUsed.KHR_materials_common) { |
1071 | |
|
1072 | 0 | if (Value *ext = FindObject(*extensions, "KHR_materials_common")) { |
1073 | 0 | Value *curLight = FindString(*ext, "light"); |
1074 | 0 | if (nullptr != curLight) { |
1075 | 0 | this->light = r.lights.Get(curLight->GetString()); |
1076 | 0 | } |
1077 | 0 | } |
1078 | 0 | } |
1079 | 0 | } |
1080 | 0 | } |
1081 | | |
1082 | 0 | inline void Scene::Read(Value &obj, Asset &r) { |
1083 | 0 | if (Value *array = FindArray(obj, "nodes")) { |
1084 | 0 | for (unsigned int i = 0; i < array->Size(); ++i) { |
1085 | 0 | if (!(*array)[i].IsString()) continue; |
1086 | 0 | Ref<Node> node = r.nodes.Get((*array)[i].GetString()); |
1087 | 0 | if (node) |
1088 | 0 | this->nodes.push_back(node); |
1089 | 0 | } |
1090 | 0 | } |
1091 | 0 | } |
1092 | | |
1093 | 0 | inline void AssetMetadata::Read(Document &doc) { |
1094 | | // read the version, etc. |
1095 | 0 | if (Value *obj = FindObject(doc, "asset")) { |
1096 | 0 | ReadMember(*obj, "copyright", copyright); |
1097 | 0 | ReadMember(*obj, "generator", generator); |
1098 | |
|
1099 | 0 | premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false); |
1100 | |
|
1101 | 0 | if (Value *versionString = FindString(*obj, "version")) { |
1102 | 0 | version = versionString->GetString(); |
1103 | 0 | } else if (Value *versionNumber = FindNumber(*obj, "version")) { |
1104 | 0 | char buf[4]; |
1105 | |
|
1106 | 0 | ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble()); |
1107 | |
|
1108 | 0 | version = buf; |
1109 | 0 | } |
1110 | |
|
1111 | 0 | Value *curProfile = FindObject(*obj, "profile"); |
1112 | 0 | if (nullptr != curProfile) { |
1113 | 0 | ReadMember(*curProfile, "api", this->profile.api); |
1114 | 0 | ReadMember(*curProfile, "version", this->profile.version); |
1115 | 0 | } |
1116 | 0 | } |
1117 | 0 | } |
1118 | | |
1119 | | // |
1120 | | // Asset methods implementation |
1121 | | // |
1122 | | |
1123 | 0 | inline void Asset::ReadBinaryHeader(IOStream &stream) { |
1124 | 0 | GLB_Header header; |
1125 | 0 | if (stream.Read(&header, sizeof(header), 1) != 1) { |
1126 | 0 | throw DeadlyImportError("GLTF: Unable to read the file header"); |
1127 | 0 | } |
1128 | | |
1129 | 0 | if (strncmp((char *)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) { |
1130 | 0 | throw DeadlyImportError("GLTF: Invalid binary glTF file"); |
1131 | 0 | } |
1132 | | |
1133 | 0 | AI_SWAP4(header.version); |
1134 | 0 | asset.version = ai_to_string(header.version); |
1135 | 0 | if (header.version != 1) { |
1136 | 0 | throw DeadlyImportError("GLTF: Unsupported binary glTF version"); |
1137 | 0 | } |
1138 | | |
1139 | 0 | AI_SWAP4(header.sceneFormat); |
1140 | 0 | if (header.sceneFormat != SceneFormat_JSON) { |
1141 | 0 | throw DeadlyImportError("GLTF: Unsupported binary glTF scene format"); |
1142 | 0 | } |
1143 | | |
1144 | 0 | AI_SWAP4(header.length); |
1145 | 0 | AI_SWAP4(header.sceneLength); |
1146 | |
|
1147 | 0 | static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits"); |
1148 | 0 | mSceneLength = static_cast<size_t>(header.sceneLength); // Can't be larger than 4GB (max. uint32_t) |
1149 | |
|
1150 | 0 | mBodyOffset = sizeof(header) + mSceneLength; |
1151 | 0 | mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4 |
1152 | |
|
1153 | 0 | mBodyLength = header.length - mBodyOffset; |
1154 | 0 | } |
1155 | | |
1156 | 39 | inline void Asset::Load(const std::string &pFile, bool isBinary) { |
1157 | 39 | mCurrentAssetDir.clear(); |
1158 | | |
1159 | | /*int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); |
1160 | | if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1);*/ |
1161 | 39 | if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) { |
1162 | 0 | mCurrentAssetDir = getCurrentAssetDir(pFile); |
1163 | 0 | } |
1164 | | |
1165 | 39 | shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true)); |
1166 | 39 | if (!stream) { |
1167 | 0 | throw DeadlyImportError("GLTF: Could not open file for reading"); |
1168 | 0 | } |
1169 | | |
1170 | | // is binary? then read the header |
1171 | 39 | if (isBinary) { |
1172 | 0 | SetAsBinary(); // also creates the body buffer |
1173 | 0 | ReadBinaryHeader(*stream); |
1174 | 39 | } else { |
1175 | 39 | mSceneLength = stream->FileSize(); |
1176 | 39 | mBodyLength = 0; |
1177 | 39 | } |
1178 | | |
1179 | | // Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later |
1180 | 39 | if (mSceneLength < 2) { |
1181 | 0 | throw DeadlyImportError("GLTF: No JSON file contents"); |
1182 | 0 | } |
1183 | | |
1184 | | // Binary format only supports up to 4GB of JSON so limit it there to avoid extreme memory allocation |
1185 | 39 | if (mSceneLength >= std::numeric_limits<uint32_t>::max()) { |
1186 | 0 | throw DeadlyImportError("GLTF: JSON size greater than 4GB"); |
1187 | 0 | } |
1188 | | |
1189 | | // read the scene data, ensure null termination |
1190 | 39 | std::vector<char> sceneData(mSceneLength + 1); |
1191 | 39 | sceneData[mSceneLength] = '\0'; |
1192 | | |
1193 | 39 | if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) { |
1194 | 0 | throw DeadlyImportError("GLTF: Could not read the file contents"); |
1195 | 0 | } |
1196 | | |
1197 | | // parse the JSON document |
1198 | | |
1199 | 39 | Document doc; |
1200 | 39 | doc.ParseInsitu(&sceneData[0]); |
1201 | | |
1202 | 39 | if (doc.HasParseError()) { |
1203 | 38 | char buffer[32]; |
1204 | 38 | ai_snprintf(buffer, 32, "%d", static_cast<int>(doc.GetErrorOffset())); |
1205 | 38 | throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError())); |
1206 | 38 | } |
1207 | | |
1208 | 1 | if (!doc.IsObject()) { |
1209 | 1 | throw DeadlyImportError("GLTF: JSON document root must be a JSON object"); |
1210 | 1 | } |
1211 | | |
1212 | | // Fill the buffer instance for the current file embedded contents |
1213 | 0 | if (mBodyLength > 0) { |
1214 | 0 | if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) { |
1215 | 0 | throw DeadlyImportError("GLTF: Unable to read gltf file"); |
1216 | 0 | } |
1217 | 0 | } |
1218 | | |
1219 | | // Load the metadata |
1220 | 0 | asset.Read(doc); |
1221 | 0 | if (!asset) { |
1222 | 0 | return; |
1223 | 0 | } |
1224 | | |
1225 | 0 | ReadExtensionsUsed(doc); |
1226 | | |
1227 | | // Prepare the dictionaries |
1228 | 0 | for (size_t i = 0; i < mDicts.size(); ++i) { |
1229 | 0 | mDicts[i]->AttachToDocument(doc); |
1230 | 0 | } |
1231 | | |
1232 | | // Read the "scene" property, which specifies which scene to load |
1233 | | // and recursively load everything referenced by it |
1234 | 0 | Value *curScene = FindString(doc, "scene"); |
1235 | 0 | if (nullptr != curScene) { |
1236 | 0 | this->scene = scenes.Get(curScene->GetString()); |
1237 | 0 | } |
1238 | | |
1239 | | // Clean up |
1240 | 0 | for (size_t i = 0; i < mDicts.size(); ++i) { |
1241 | 0 | mDicts[i]->DetachFromDocument(); |
1242 | 0 | } |
1243 | 0 | } |
1244 | | |
1245 | 0 | inline void Asset::SetAsBinary() { |
1246 | 0 | if (!extensionsUsed.KHR_binary_glTF) { |
1247 | 0 | extensionsUsed.KHR_binary_glTF = true; |
1248 | 0 | mBodyBuffer = buffers.Create("binary_glTF"); |
1249 | 0 | mBodyBuffer->MarkAsSpecial(); |
1250 | 0 | } |
1251 | 0 | } |
1252 | | |
1253 | 0 | inline void Asset::ReadExtensionsUsed(Document &doc) { |
1254 | 0 | Value *extsUsed = FindArray(doc, "extensionsUsed"); |
1255 | 0 | if (!extsUsed) return; |
1256 | | |
1257 | 0 | std::gltf_unordered_map<std::string, bool> exts; |
1258 | |
|
1259 | 0 | for (unsigned int i = 0; i < extsUsed->Size(); ++i) { |
1260 | 0 | if ((*extsUsed)[i].IsString()) { |
1261 | 0 | exts[(*extsUsed)[i].GetString()] = true; |
1262 | 0 | } |
1263 | 0 | } |
1264 | |
|
1265 | 0 | CHECK_EXT(KHR_binary_glTF); |
1266 | 0 | CHECK_EXT(KHR_materials_common); |
1267 | |
|
1268 | 0 | #undef CHECK_EXT |
1269 | 0 | } |
1270 | | |
1271 | 39 | inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool absolute) { |
1272 | 39 | #ifdef ASSIMP_API |
1273 | 39 | (void)absolute; |
1274 | 39 | return mIOSystem->Open(path, mode); |
1275 | | #else |
1276 | | if (path.size() < 2) return 0; |
1277 | | if (!absolute && path[1] != ':' && path[0] != '/') { // relative? |
1278 | | path = mCurrentAssetDir + path; |
1279 | | } |
1280 | | FILE *f = fopen(path.c_str(), mode); |
1281 | | return f ? new IOStream(f) : 0; |
1282 | | #endif |
1283 | 39 | } |
1284 | | |
1285 | 0 | inline std::string Asset::FindUniqueID(const std::string &str, const char *suffix) { |
1286 | 0 | std::string id = str; |
1287 | |
|
1288 | 0 | if (!id.empty()) { |
1289 | 0 | if (mUsedIds.find(id) == mUsedIds.end()) |
1290 | 0 | return id; |
1291 | | |
1292 | 0 | id += "_"; |
1293 | 0 | } |
1294 | | |
1295 | 0 | id += suffix; |
1296 | |
|
1297 | 0 | Asset::IdMap::iterator it = mUsedIds.find(id); |
1298 | 0 | if (it == mUsedIds.end()) |
1299 | 0 | return id; |
1300 | | |
1301 | 0 | char buffer[1024]; |
1302 | 0 | int offset = ai_snprintf(buffer, sizeof(buffer), "%s_", id.c_str()); |
1303 | 0 | for (int i = 0; it != mUsedIds.end(); ++i) { |
1304 | 0 | ai_snprintf(buffer + offset, sizeof(buffer) - offset, "%d", i); |
1305 | 0 | id = buffer; |
1306 | 0 | it = mUsedIds.find(id); |
1307 | 0 | } |
1308 | |
|
1309 | 0 | return id; |
1310 | 0 | } |
1311 | | |
1312 | | #if _MSC_VER |
1313 | | #pragma warning(pop) |
1314 | | #endif // _MSC_VER |
1315 | | |
1316 | | } // namespace glTF |