/src/assimp/code/AssetLib/glTF/glTFAssetWriter.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/Base64.hpp> |
43 | | |
44 | | #include <rapidjson/stringbuffer.h> |
45 | | #include <rapidjson/writer.h> |
46 | | #include <rapidjson/prettywriter.h> |
47 | | |
48 | | #if _MSC_VER |
49 | | # pragma warning(push) |
50 | | # pragma warning( disable : 4706) |
51 | | #endif // _MSC_VER |
52 | | |
53 | | namespace glTF { |
54 | | |
55 | | using rapidjson::StringBuffer; |
56 | | using rapidjson::PrettyWriter; |
57 | | using rapidjson::Writer; |
58 | | using rapidjson::StringRef; |
59 | | using rapidjson::StringRef; |
60 | | |
61 | | namespace { |
62 | | |
63 | | template<typename T, size_t N> |
64 | | inline |
65 | 0 | Value& MakeValue(Value& val, T(&r)[N], MemoryPoolAllocator<>& al) { |
66 | 0 | val.SetArray(); |
67 | 0 | val.Reserve(N, al); |
68 | 0 | for (decltype(N) i = 0; i < N; ++i) { |
69 | 0 | val.PushBack(r[i], al); |
70 | 0 | } |
71 | 0 | return val; |
72 | 0 | } Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 16ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [16ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 4ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [4ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 16ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [16ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<float, 3ul>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, float (&) [3ul], rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) |
73 | | |
74 | | template<typename T> |
75 | | inline |
76 | 0 | Value& MakeValue(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) { |
77 | 0 | val.SetArray(); |
78 | 0 | val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al); |
79 | 0 | for (unsigned int i = 0; i < r.size(); ++i) { |
80 | 0 | val.PushBack(r[i], al); |
81 | 0 | } |
82 | 0 | return val; |
83 | 0 | } Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<double, std::__1::allocator<double> > const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValue<double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<double, std::__1::allocator<double> > const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) |
84 | | |
85 | | template<typename C, typename T> |
86 | 0 | inline Value& MakeValueCast(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) { |
87 | 0 | val.SetArray(); |
88 | 0 | val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al); |
89 | 0 | for (unsigned int i = 0; i < r.size(); ++i) { |
90 | 0 | val.PushBack(static_cast<C>(r[i]), al); |
91 | 0 | } |
92 | 0 | return val; |
93 | 0 | } Unexecuted instantiation: glTFExporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValueCast<long, double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<double, std::__1::allocator<double> > const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFImporter.cpp:rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >& glTF::(anonymous namespace)::MakeValueCast<long, double>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<double, std::__1::allocator<double> > const&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) |
94 | | |
95 | | template<class T> |
96 | 0 | inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) { |
97 | 0 | if (v.empty()) return; |
98 | 0 | Value lst; |
99 | 0 | lst.SetArray(); |
100 | 0 | lst.Reserve(unsigned(v.size()), al); |
101 | 0 | for (size_t i = 0; i < v.size(); ++i) { |
102 | 0 | lst.PushBack(StringRef(v[i]->id), al); |
103 | 0 | } |
104 | 0 | obj.AddMember(StringRef(fieldId), lst, al); |
105 | 0 | } Unexecuted instantiation: glTFExporter.cpp:void glTF::(anonymous namespace)::AddRefsVector<glTF::Node>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Node>, std::__1::allocator<glTFCommon::Ref<glTF::Node> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFExporter.cpp:void glTF::(anonymous namespace)::AddRefsVector<glTF::Mesh>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Mesh>, std::__1::allocator<glTFCommon::Ref<glTF::Mesh> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFImporter.cpp:void glTF::(anonymous namespace)::AddRefsVector<glTF::Node>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Node>, std::__1::allocator<glTFCommon::Ref<glTF::Node> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFImporter.cpp:void glTF::(anonymous namespace)::AddRefsVector<glTF::Mesh>(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, char const*, std::__1::vector<glTFCommon::Ref<glTF::Mesh>, std::__1::allocator<glTFCommon::Ref<glTF::Mesh> > >&, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) |
106 | | |
107 | | |
108 | | } |
109 | | |
110 | | inline void Write(Value& obj, Accessor& a, AssetWriter& w) |
111 | 0 | { |
112 | 0 | obj.AddMember("bufferView", Value(a.bufferView->id, w.mAl).Move(), w.mAl); |
113 | 0 | obj.AddMember("byteOffset", a.byteOffset, w.mAl); |
114 | 0 | obj.AddMember("byteStride", a.byteStride, w.mAl); |
115 | 0 | obj.AddMember("componentType", int(a.componentType), w.mAl); |
116 | 0 | obj.AddMember("count", a.count, w.mAl); |
117 | 0 | obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl); |
118 | |
|
119 | 0 | Value vTmpMax, vTmpMin; |
120 | 0 | if (a.componentType == ComponentType_FLOAT) { |
121 | 0 | obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl); |
122 | 0 | obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl); |
123 | 0 | } else { |
124 | 0 | obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl); |
125 | 0 | obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl); |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | | inline void Write(Value& obj, Animation& a, AssetWriter& w) |
130 | 0 | { |
131 | | /****************** Channels *******************/ |
132 | 0 | Value channels; |
133 | 0 | channels.SetArray(); |
134 | 0 | channels.Reserve(unsigned(a.Channels.size()), w.mAl); |
135 | |
|
136 | 0 | for (size_t i = 0; i < unsigned(a.Channels.size()); ++i) { |
137 | 0 | Animation::AnimChannel& c = a.Channels[i]; |
138 | 0 | Value valChannel; |
139 | 0 | valChannel.SetObject(); |
140 | 0 | { |
141 | 0 | valChannel.AddMember("sampler", c.sampler, w.mAl); |
142 | |
|
143 | 0 | Value valTarget; |
144 | 0 | valTarget.SetObject(); |
145 | 0 | { |
146 | 0 | valTarget.AddMember("id", StringRef(c.target.id->id), w.mAl); |
147 | 0 | valTarget.AddMember("path", c.target.path, w.mAl); |
148 | 0 | } |
149 | 0 | valChannel.AddMember("target", valTarget, w.mAl); |
150 | 0 | } |
151 | 0 | channels.PushBack(valChannel, w.mAl); |
152 | 0 | } |
153 | 0 | obj.AddMember("channels", channels, w.mAl); |
154 | | |
155 | | /****************** Parameters *******************/ |
156 | 0 | Value valParameters; |
157 | 0 | valParameters.SetObject(); |
158 | 0 | { |
159 | 0 | if (a.Parameters.TIME) { |
160 | 0 | valParameters.AddMember("TIME", StringRef(a.Parameters.TIME->id), w.mAl); |
161 | 0 | } |
162 | 0 | if (a.Parameters.rotation) { |
163 | 0 | valParameters.AddMember("rotation", StringRef(a.Parameters.rotation->id), w.mAl); |
164 | 0 | } |
165 | 0 | if (a.Parameters.scale) { |
166 | 0 | valParameters.AddMember("scale", StringRef(a.Parameters.scale->id), w.mAl); |
167 | 0 | } |
168 | 0 | if (a.Parameters.translation) { |
169 | 0 | valParameters.AddMember("translation", StringRef(a.Parameters.translation->id), w.mAl); |
170 | 0 | } |
171 | 0 | } |
172 | 0 | obj.AddMember("parameters", valParameters, w.mAl); |
173 | | |
174 | | /****************** Samplers *******************/ |
175 | 0 | Value valSamplers; |
176 | 0 | valSamplers.SetObject(); |
177 | |
|
178 | 0 | for (size_t i = 0; i < unsigned(a.Samplers.size()); ++i) { |
179 | 0 | Animation::AnimSampler& s = a.Samplers[i]; |
180 | 0 | Value valSampler; |
181 | 0 | valSampler.SetObject(); |
182 | 0 | { |
183 | 0 | valSampler.AddMember("input", s.input, w.mAl); |
184 | 0 | valSampler.AddMember("interpolation", s.interpolation, w.mAl); |
185 | 0 | valSampler.AddMember("output", s.output, w.mAl); |
186 | 0 | } |
187 | 0 | valSamplers.AddMember(StringRef(s.id), valSampler, w.mAl); |
188 | 0 | } |
189 | 0 | obj.AddMember("samplers", valSamplers, w.mAl); |
190 | 0 | } |
191 | | |
192 | | inline void Write(Value& obj, Buffer& b, AssetWriter& w) |
193 | 0 | { |
194 | 0 | const char* type; |
195 | 0 | switch (b.type) { |
196 | 0 | case Buffer::Type_text: |
197 | 0 | type = "text"; break; |
198 | 0 | default: |
199 | 0 | type = "arraybuffer"; |
200 | 0 | } |
201 | | |
202 | 0 | obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl); |
203 | 0 | obj.AddMember("type", StringRef(type), w.mAl); |
204 | 0 | obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl); |
205 | 0 | } |
206 | | |
207 | | inline void Write(Value& obj, BufferView& bv, AssetWriter& w) |
208 | 0 | { |
209 | 0 | obj.AddMember("buffer", Value(bv.buffer->id, w.mAl).Move(), w.mAl); |
210 | 0 | obj.AddMember("byteOffset", static_cast<uint64_t>(bv.byteOffset), w.mAl); |
211 | 0 | obj.AddMember("byteLength", static_cast<uint64_t>(bv.byteLength), w.mAl); |
212 | 0 | if (bv.target != BufferViewTarget_NONE) { |
213 | 0 | obj.AddMember("target", int(bv.target), w.mAl); |
214 | 0 | } |
215 | 0 | } |
216 | | |
217 | | inline void Write(Value& /*obj*/, Camera& /*c*/, AssetWriter& /*w*/) |
218 | 0 | { |
219 | |
|
220 | 0 | } |
221 | | |
222 | | inline void Write(Value& obj, Image& img, AssetWriter& w) |
223 | 0 | { |
224 | 0 | std::string uri; |
225 | 0 | if (w.mAsset.extensionsUsed.KHR_binary_glTF && img.bufferView) { |
226 | 0 | Value exts, ext; |
227 | 0 | exts.SetObject(); |
228 | 0 | ext.SetObject(); |
229 | |
|
230 | 0 | ext.AddMember("bufferView", StringRef(img.bufferView->id), w.mAl); |
231 | |
|
232 | 0 | if (!img.mimeType.empty()) |
233 | 0 | ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl); |
234 | |
|
235 | 0 | exts.AddMember("KHR_binary_glTF", ext, w.mAl); |
236 | 0 | obj.AddMember("extensions", exts, w.mAl); |
237 | 0 | return; |
238 | 0 | } |
239 | 0 | else if (img.HasData()) { |
240 | 0 | uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); |
241 | 0 | uri += ";base64,"; |
242 | 0 | Base64::Encode(img.GetData(), img.GetDataLength(), uri); |
243 | 0 | } |
244 | 0 | else { |
245 | 0 | uri = img.uri; |
246 | 0 | } |
247 | | |
248 | 0 | obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl); |
249 | 0 | } |
250 | | |
251 | | namespace { |
252 | | inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al) |
253 | 0 | { |
254 | 0 | if (prop.texture) |
255 | 0 | obj.AddMember(StringRef(propName), Value(prop.texture->id, al).Move(), al); |
256 | 0 | else { |
257 | 0 | Value col; |
258 | 0 | obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al); |
259 | 0 | } |
260 | 0 | } Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::WriteColorOrTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF::TexProperty&, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::WriteColorOrTex(rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, glTF::TexProperty&, char const*, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>&) |
261 | | } |
262 | | |
263 | | inline void Write(Value& obj, Material& m, AssetWriter& w) |
264 | 0 | { |
265 | 0 | Value v; |
266 | 0 | v.SetObject(); |
267 | 0 | { |
268 | 0 | WriteColorOrTex(v, m.ambient, "ambient", w.mAl); |
269 | 0 | WriteColorOrTex(v, m.diffuse, "diffuse", w.mAl); |
270 | 0 | WriteColorOrTex(v, m.specular, "specular", w.mAl); |
271 | 0 | WriteColorOrTex(v, m.emission, "emission", w.mAl); |
272 | |
|
273 | 0 | if (m.transparent) |
274 | 0 | v.AddMember("transparency", m.transparency, w.mAl); |
275 | |
|
276 | 0 | v.AddMember("shininess", m.shininess, w.mAl); |
277 | 0 | } |
278 | 0 | obj.AddMember("values", v, w.mAl); |
279 | 0 | } |
280 | | |
281 | | namespace { |
282 | | inline void WriteAttrs(AssetWriter& w, Value& attrs, Mesh::AccessorList& lst, |
283 | | const char* semantic, bool forceNumber = false) |
284 | 0 | { |
285 | 0 | if (lst.empty()) return; |
286 | 0 | if (lst.size() == 1 && !forceNumber) { |
287 | 0 | attrs.AddMember(StringRef(semantic), Value(lst[0]->id, w.mAl).Move(), w.mAl); |
288 | 0 | } |
289 | 0 | else { |
290 | 0 | for (size_t i = 0; i < lst.size(); ++i) { |
291 | 0 | char buffer[32]; |
292 | 0 | ai_snprintf(buffer, 32, "%s_%d", semantic, int(i)); |
293 | 0 | attrs.AddMember(Value(buffer, w.mAl).Move(), Value(lst[i]->id, w.mAl).Move(), w.mAl); |
294 | 0 | } |
295 | 0 | } |
296 | 0 | } Unexecuted instantiation: glTFExporter.cpp:glTF::(anonymous namespace)::WriteAttrs(glTF::AssetWriter&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<glTFCommon::Ref<glTF::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF::Accessor> > >&, char const*, bool) Unexecuted instantiation: glTFImporter.cpp:glTF::(anonymous namespace)::WriteAttrs(glTF::AssetWriter&, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >&, std::__1::vector<glTFCommon::Ref<glTF::Accessor>, std::__1::allocator<glTFCommon::Ref<glTF::Accessor> > >&, char const*, bool) |
297 | | } |
298 | | |
299 | | inline void Write(Value& obj, Mesh& m, AssetWriter& w) |
300 | 0 | { |
301 | | /********************* Name **********************/ |
302 | 0 | obj.AddMember("name", m.name, w.mAl); |
303 | | |
304 | | /**************** Mesh extensions ****************/ |
305 | 0 | if(m.Extension.size() > 0) |
306 | 0 | { |
307 | 0 | Value json_extensions; |
308 | |
|
309 | 0 | json_extensions.SetObject(); |
310 | 0 | #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC |
311 | 0 | for(Mesh::SExtension* ptr_ext : m.Extension) |
312 | 0 | { |
313 | 0 | switch(ptr_ext->Type) |
314 | 0 | { |
315 | 0 | case Mesh::SExtension::EType::Compression_Open3DGC: |
316 | 0 | { |
317 | 0 | Value json_comp_data; |
318 | 0 | Mesh::SCompression_Open3DGC* ptr_ext_comp = (Mesh::SCompression_Open3DGC*)ptr_ext; |
319 | | |
320 | | // filling object "compressedData" |
321 | 0 | json_comp_data.SetObject(); |
322 | 0 | json_comp_data.AddMember("buffer", ptr_ext_comp->Buffer, w.mAl); |
323 | 0 | json_comp_data.AddMember("byteOffset", static_cast<uint64_t>(ptr_ext_comp->Offset), w.mAl); |
324 | 0 | json_comp_data.AddMember("componentType", 5121, w.mAl); |
325 | 0 | json_comp_data.AddMember("type", "SCALAR", w.mAl); |
326 | 0 | json_comp_data.AddMember("count", static_cast<uint64_t>(ptr_ext_comp->Count), w.mAl); |
327 | 0 | if(ptr_ext_comp->Binary) |
328 | 0 | json_comp_data.AddMember("mode", "binary", w.mAl); |
329 | 0 | else |
330 | 0 | json_comp_data.AddMember("mode", "ascii", w.mAl); |
331 | |
|
332 | 0 | json_comp_data.AddMember("indicesCount", static_cast<uint64_t>(ptr_ext_comp->IndicesCount), w.mAl); |
333 | 0 | json_comp_data.AddMember("verticesCount", static_cast<uint64_t>(ptr_ext_comp->VerticesCount), w.mAl); |
334 | | // filling object "Open3DGC-compression" |
335 | 0 | Value json_o3dgc; |
336 | |
|
337 | 0 | json_o3dgc.SetObject(); |
338 | 0 | json_o3dgc.AddMember("compressedData", json_comp_data, w.mAl); |
339 | | // add member to object "extensions" |
340 | 0 | json_extensions.AddMember("Open3DGC-compression", json_o3dgc, w.mAl); |
341 | 0 | } |
342 | |
|
343 | 0 | break; |
344 | 0 | default: |
345 | 0 | throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported."); |
346 | 0 | }// switch(ptr_ext->Type) |
347 | 0 | }// for(Mesh::SExtension* ptr_ext : m.Extension) |
348 | 0 | #endif |
349 | | |
350 | | // Add extensions to mesh |
351 | 0 | obj.AddMember("extensions", json_extensions, w.mAl); |
352 | 0 | }// if(m.Extension.size() > 0) |
353 | | |
354 | | /****************** Primitives *******************/ |
355 | 0 | Value primitives; |
356 | 0 | primitives.SetArray(); |
357 | 0 | primitives.Reserve(unsigned(m.primitives.size()), w.mAl); |
358 | |
|
359 | 0 | for (size_t i = 0; i < m.primitives.size(); ++i) { |
360 | 0 | Mesh::Primitive& p = m.primitives[i]; |
361 | 0 | Value prim; |
362 | 0 | prim.SetObject(); |
363 | 0 | { |
364 | 0 | prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl); |
365 | |
|
366 | 0 | if (p.material) |
367 | 0 | prim.AddMember("material", p.material->id, w.mAl); |
368 | |
|
369 | 0 | if (p.indices) |
370 | 0 | prim.AddMember("indices", Value(p.indices->id, w.mAl).Move(), w.mAl); |
371 | |
|
372 | 0 | Value attrs; |
373 | 0 | attrs.SetObject(); |
374 | 0 | { |
375 | 0 | WriteAttrs(w, attrs, p.attributes.position, "POSITION"); |
376 | 0 | WriteAttrs(w, attrs, p.attributes.normal, "NORMAL"); |
377 | 0 | WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true); |
378 | 0 | WriteAttrs(w, attrs, p.attributes.color, "COLOR"); |
379 | 0 | WriteAttrs(w, attrs, p.attributes.joint, "JOINT"); |
380 | 0 | WriteAttrs(w, attrs, p.attributes.jointmatrix, "JOINTMATRIX"); |
381 | 0 | WriteAttrs(w, attrs, p.attributes.weight, "WEIGHT"); |
382 | 0 | } |
383 | 0 | prim.AddMember("attributes", attrs, w.mAl); |
384 | 0 | } |
385 | 0 | primitives.PushBack(prim, w.mAl); |
386 | 0 | } |
387 | |
|
388 | 0 | obj.AddMember("primitives", primitives, w.mAl); |
389 | 0 | } |
390 | | |
391 | | inline void Write(Value& obj, Node& n, AssetWriter& w) |
392 | 0 | { |
393 | |
|
394 | 0 | if (n.matrix.isPresent) { |
395 | 0 | Value val; |
396 | 0 | obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl); |
397 | 0 | } |
398 | |
|
399 | 0 | if (n.translation.isPresent) { |
400 | 0 | Value val; |
401 | 0 | obj.AddMember("translation", MakeValue(val, n.translation.value, w.mAl).Move(), w.mAl); |
402 | 0 | } |
403 | |
|
404 | 0 | if (n.scale.isPresent) { |
405 | 0 | Value val; |
406 | 0 | obj.AddMember("scale", MakeValue(val, n.scale.value, w.mAl).Move(), w.mAl); |
407 | 0 | } |
408 | 0 | if (n.rotation.isPresent) { |
409 | 0 | Value val; |
410 | 0 | obj.AddMember("rotation", MakeValue(val, n.rotation.value, w.mAl).Move(), w.mAl); |
411 | 0 | } |
412 | |
|
413 | 0 | AddRefsVector(obj, "children", n.children, w.mAl); |
414 | |
|
415 | 0 | AddRefsVector(obj, "meshes", n.meshes, w.mAl); |
416 | |
|
417 | 0 | AddRefsVector(obj, "skeletons", n.skeletons, w.mAl); |
418 | |
|
419 | 0 | if (n.skin) { |
420 | 0 | obj.AddMember("skin", Value(n.skin->id, w.mAl).Move(), w.mAl); |
421 | 0 | } |
422 | |
|
423 | 0 | if (!n.jointName.empty()) { |
424 | 0 | obj.AddMember("jointName", n.jointName, w.mAl); |
425 | 0 | } |
426 | 0 | } |
427 | | |
428 | | inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/) |
429 | 0 | { |
430 | 0 |
|
431 | 0 | } |
432 | | |
433 | | inline void Write(Value& obj, Sampler& b, AssetWriter& w) |
434 | 0 | { |
435 | 0 | if (b.wrapS) { |
436 | 0 | obj.AddMember("wrapS", b.wrapS, w.mAl); |
437 | 0 | } |
438 | 0 | if (b.wrapT) { |
439 | 0 | obj.AddMember("wrapT", b.wrapT, w.mAl); |
440 | 0 | } |
441 | 0 | if (b.magFilter) { |
442 | 0 | obj.AddMember("magFilter", b.magFilter, w.mAl); |
443 | 0 | } |
444 | 0 | if (b.minFilter) { |
445 | 0 | obj.AddMember("minFilter", b.minFilter, w.mAl); |
446 | 0 | } |
447 | 0 | } |
448 | | |
449 | | inline void Write(Value& scene, Scene& s, AssetWriter& w) |
450 | 0 | { |
451 | 0 | AddRefsVector(scene, "nodes", s.nodes, w.mAl); |
452 | 0 | } |
453 | | |
454 | | inline void Write(Value& /*obj*/, Shader& /*b*/, AssetWriter& /*w*/) |
455 | 0 | { |
456 | 0 |
|
457 | 0 | } |
458 | | |
459 | | inline void Write(Value& obj, Skin& b, AssetWriter& w) |
460 | 0 | { |
461 | | /****************** jointNames *******************/ |
462 | 0 | Value vJointNames; |
463 | 0 | vJointNames.SetArray(); |
464 | 0 | vJointNames.Reserve(unsigned(b.jointNames.size()), w.mAl); |
465 | |
|
466 | 0 | for (size_t i = 0; i < unsigned(b.jointNames.size()); ++i) { |
467 | 0 | vJointNames.PushBack(StringRef(b.jointNames[i]->jointName), w.mAl); |
468 | 0 | } |
469 | 0 | obj.AddMember("jointNames", vJointNames, w.mAl); |
470 | |
|
471 | 0 | if (b.bindShapeMatrix.isPresent) { |
472 | 0 | Value val; |
473 | 0 | obj.AddMember("bindShapeMatrix", MakeValue(val, b.bindShapeMatrix.value, w.mAl).Move(), w.mAl); |
474 | 0 | } |
475 | |
|
476 | 0 | if (b.inverseBindMatrices) { |
477 | 0 | obj.AddMember("inverseBindMatrices", Value(b.inverseBindMatrices->id, w.mAl).Move(), w.mAl); |
478 | 0 | } |
479 | |
|
480 | 0 | } |
481 | | |
482 | | inline void Write(Value& /*obj*/, Technique& /*b*/, AssetWriter& /*w*/) |
483 | 0 | { |
484 | 0 |
|
485 | 0 | } |
486 | | |
487 | | inline void Write(Value& obj, Texture& tex, AssetWriter& w) |
488 | 0 | { |
489 | 0 | if (tex.source) { |
490 | 0 | obj.AddMember("source", Value(tex.source->id, w.mAl).Move(), w.mAl); |
491 | 0 | } |
492 | 0 | if (tex.sampler) { |
493 | 0 | obj.AddMember("sampler", Value(tex.sampler->id, w.mAl).Move(), w.mAl); |
494 | 0 | } |
495 | 0 | } |
496 | | |
497 | | inline void Write(Value& /*obj*/, Light& /*b*/, AssetWriter& /*w*/) |
498 | 0 | { |
499 | |
|
500 | 0 | } |
501 | | |
502 | | |
503 | | inline AssetWriter::AssetWriter(Asset& a) |
504 | 0 | : mDoc() |
505 | 0 | , mAsset(a) |
506 | 0 | , mAl(mDoc.GetAllocator()) |
507 | 0 | { |
508 | 0 | mDoc.SetObject(); |
509 | |
|
510 | 0 | WriteMetadata(); |
511 | 0 | WriteExtensionsUsed(); |
512 | | |
513 | | // Dump the contents of the dictionaries |
514 | 0 | for (size_t i = 0; i < a.mDicts.size(); ++i) { |
515 | 0 | a.mDicts[i]->WriteObjects(*this); |
516 | 0 | } |
517 | | |
518 | | // Add the target scene field |
519 | 0 | if (mAsset.scene) { |
520 | 0 | mDoc.AddMember("scene", StringRef(mAsset.scene->id), mAl); |
521 | 0 | } |
522 | 0 | } |
523 | | |
524 | | inline void AssetWriter::WriteFile(const char* path) |
525 | 0 | { |
526 | 0 | std::unique_ptr<IOStream> jsonOutFile(mAsset.OpenFile(path, "wt", true)); |
527 | |
|
528 | 0 | if (jsonOutFile == nullptr) { |
529 | 0 | throw DeadlyExportError("Could not open output file: " + std::string(path)); |
530 | 0 | } |
531 | | |
532 | 0 | StringBuffer docBuffer; |
533 | |
|
534 | 0 | PrettyWriter<StringBuffer> writer(docBuffer); |
535 | 0 | if (!mDoc.Accept(writer)) { |
536 | 0 | throw DeadlyExportError("Failed to write scene data!"); |
537 | 0 | } |
538 | | |
539 | 0 | if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { |
540 | 0 | throw DeadlyExportError("Failed to write scene data!"); |
541 | 0 | } |
542 | | |
543 | | // Write buffer data to separate .bin files |
544 | 0 | for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) { |
545 | 0 | Ref<Buffer> b = mAsset.buffers.Get(i); |
546 | |
|
547 | 0 | std::string binPath = b->GetURI(); |
548 | |
|
549 | 0 | std::unique_ptr<IOStream> binOutFile(mAsset.OpenFile(binPath, "wb", true)); |
550 | |
|
551 | 0 | if (binOutFile == nullptr) { |
552 | 0 | throw DeadlyExportError("Could not open output file: " + binPath); |
553 | 0 | } |
554 | | |
555 | 0 | if (b->byteLength > 0) { |
556 | 0 | if (binOutFile->Write(b->GetPointer(), b->byteLength, 1) != 1) { |
557 | 0 | throw DeadlyExportError("Failed to write binary file: " + binPath); |
558 | 0 | } |
559 | 0 | } |
560 | 0 | } |
561 | 0 | } |
562 | | |
563 | | inline void AssetWriter::WriteGLBFile(const char* path) |
564 | 0 | { |
565 | 0 | std::unique_ptr<IOStream> outfile(mAsset.OpenFile(path, "wb", true)); |
566 | |
|
567 | 0 | if (outfile == nullptr) { |
568 | 0 | throw DeadlyExportError("Could not open output file: " + std::string(path)); |
569 | 0 | } |
570 | | |
571 | | // we will write the header later, skip its size |
572 | 0 | outfile->Seek(sizeof(GLB_Header), aiOrigin_SET); |
573 | |
|
574 | 0 | StringBuffer docBuffer; |
575 | 0 | Writer<StringBuffer> writer(docBuffer); |
576 | 0 | if (!mDoc.Accept(writer)) { |
577 | 0 | throw DeadlyExportError("Failed to write scene data!"); |
578 | 0 | } |
579 | | |
580 | 0 | if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { |
581 | 0 | throw DeadlyExportError("Failed to write scene data!"); |
582 | 0 | } |
583 | | |
584 | 0 | WriteBinaryData(outfile.get(), docBuffer.GetSize()); |
585 | 0 | } |
586 | | |
587 | | inline void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength) |
588 | 0 | { |
589 | | // |
590 | | // write the body data |
591 | | // |
592 | |
|
593 | 0 | size_t bodyLength = 0; |
594 | 0 | if (Ref<Buffer> b = mAsset.GetBodyBuffer()) { |
595 | 0 | bodyLength = b->byteLength; |
596 | |
|
597 | 0 | if (bodyLength > 0) { |
598 | 0 | size_t bodyOffset = sizeof(GLB_Header) + sceneLength; |
599 | 0 | bodyOffset = (bodyOffset + 3) & ~3; // Round up to next multiple of 4 |
600 | |
|
601 | 0 | outfile->Seek(bodyOffset, aiOrigin_SET); |
602 | |
|
603 | 0 | if (outfile->Write(b->GetPointer(), b->byteLength, 1) != 1) { |
604 | 0 | throw DeadlyExportError("Failed to write body data!"); |
605 | 0 | } |
606 | 0 | } |
607 | 0 | } |
608 | | |
609 | | // |
610 | | // write the header |
611 | | // |
612 | | |
613 | 0 | GLB_Header header; |
614 | 0 | memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)); |
615 | |
|
616 | 0 | header.version = 1; |
617 | 0 | AI_SWAP4(header.version); |
618 | |
|
619 | 0 | header.length = uint32_t(sizeof(header) + sceneLength + bodyLength); |
620 | 0 | AI_SWAP4(header.length); |
621 | |
|
622 | 0 | header.sceneLength = uint32_t(sceneLength); |
623 | 0 | AI_SWAP4(header.sceneLength); |
624 | |
|
625 | 0 | header.sceneFormat = SceneFormat_JSON; |
626 | 0 | AI_SWAP4(header.sceneFormat); |
627 | |
|
628 | 0 | outfile->Seek(0, aiOrigin_SET); |
629 | |
|
630 | 0 | if (outfile->Write(&header, 1, sizeof(header)) != sizeof(header)) { |
631 | 0 | throw DeadlyExportError("Failed to write the header!"); |
632 | 0 | } |
633 | 0 | } |
634 | | |
635 | | |
636 | | inline void AssetWriter::WriteMetadata() |
637 | 0 | { |
638 | 0 | Value asset; |
639 | 0 | asset.SetObject(); |
640 | 0 | asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl); |
641 | 0 | asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl); |
642 | 0 | if (!mAsset.asset.copyright.empty()) |
643 | 0 | asset.AddMember("copyright", Value(mAsset.asset.copyright, mAl).Move(), mAl); |
644 | |
|
645 | 0 | mDoc.AddMember("asset", asset, mAl); |
646 | 0 | } |
647 | | |
648 | | inline void AssetWriter::WriteExtensionsUsed() |
649 | 0 | { |
650 | 0 | Value exts; |
651 | 0 | exts.SetArray(); |
652 | 0 | { |
653 | 0 | if (false) |
654 | 0 | exts.PushBack(StringRef("KHR_binary_glTF"), mAl); |
655 | |
|
656 | 0 | if (false) |
657 | 0 | exts.PushBack(StringRef("KHR_materials_common"), mAl); |
658 | 0 | } |
659 | |
|
660 | 0 | if (!exts.Empty()) |
661 | 0 | mDoc.AddMember("extensionsUsed", exts, mAl); |
662 | 0 | } |
663 | | |
664 | | template<class T> |
665 | | void AssetWriter::WriteObjects(LazyDict<T>& d) |
666 | 0 | { |
667 | 0 | if (d.mObjs.empty()) return; |
668 | | |
669 | 0 | Value* container = &mDoc; |
670 | |
|
671 | 0 | if (d.mExtId) { |
672 | 0 | Value* exts = FindObject(mDoc, "extensions"); |
673 | 0 | if (!exts) { |
674 | 0 | mDoc.AddMember("extensions", Value().SetObject().Move(), mDoc.GetAllocator()); |
675 | 0 | exts = FindObject(mDoc, "extensions"); |
676 | 0 | } |
677 | |
|
678 | 0 | if (!(container = FindObject(*exts, d.mExtId))) { |
679 | 0 | exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator()); |
680 | 0 | container = FindObject(*exts, d.mExtId); |
681 | 0 | } |
682 | 0 | } |
683 | |
|
684 | 0 | Value* dict; |
685 | 0 | if (!(dict = FindObject(*container, d.mDictId))) { |
686 | 0 | container->AddMember(StringRef(d.mDictId), Value().SetObject().Move(), mDoc.GetAllocator()); |
687 | 0 | dict = FindObject(*container, d.mDictId); |
688 | 0 | } |
689 | |
|
690 | 0 | for (size_t i = 0; i < d.mObjs.size(); ++i) { |
691 | 0 | if (d.mObjs[i]->IsSpecial()) continue; |
692 | | |
693 | 0 | Value obj; |
694 | 0 | obj.SetObject(); |
695 | |
|
696 | 0 | if (!d.mObjs[i]->name.empty()) { |
697 | 0 | obj.AddMember("name", StringRef(d.mObjs[i]->name.c_str()), mAl); |
698 | 0 | } |
699 | |
|
700 | 0 | Write(obj, *d.mObjs[i], *this); |
701 | |
|
702 | 0 | dict->AddMember(StringRef(d.mObjs[i]->id), obj, mAl); |
703 | 0 | } |
704 | 0 | } Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Accessor>(glTF::LazyDict<glTF::Accessor>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Animation>(glTF::LazyDict<glTF::Animation>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Buffer>(glTF::LazyDict<glTF::Buffer>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::BufferView>(glTF::LazyDict<glTF::BufferView>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Camera>(glTF::LazyDict<glTF::Camera>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Image>(glTF::LazyDict<glTF::Image>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Material>(glTF::LazyDict<glTF::Material>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Mesh>(glTF::LazyDict<glTF::Mesh>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Node>(glTF::LazyDict<glTF::Node>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Sampler>(glTF::LazyDict<glTF::Sampler>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Scene>(glTF::LazyDict<glTF::Scene>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Skin>(glTF::LazyDict<glTF::Skin>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Texture>(glTF::LazyDict<glTF::Texture>&) Unexecuted instantiation: void glTF::AssetWriter::WriteObjects<glTF::Light>(glTF::LazyDict<glTF::Light>&) |
705 | | |
706 | | template<class T> |
707 | | void WriteLazyDict(LazyDict<T>& d, AssetWriter& w) |
708 | 0 | { |
709 | 0 | w.WriteObjects(d); |
710 | 0 | } Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Accessor>(glTF::LazyDict<glTF::Accessor>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Animation>(glTF::LazyDict<glTF::Animation>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Buffer>(glTF::LazyDict<glTF::Buffer>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::BufferView>(glTF::LazyDict<glTF::BufferView>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Camera>(glTF::LazyDict<glTF::Camera>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Image>(glTF::LazyDict<glTF::Image>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Material>(glTF::LazyDict<glTF::Material>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Mesh>(glTF::LazyDict<glTF::Mesh>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Node>(glTF::LazyDict<glTF::Node>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Sampler>(glTF::LazyDict<glTF::Sampler>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Scene>(glTF::LazyDict<glTF::Scene>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Skin>(glTF::LazyDict<glTF::Skin>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Texture>(glTF::LazyDict<glTF::Texture>&, glTF::AssetWriter&) Unexecuted instantiation: void glTF::WriteLazyDict<glTF::Light>(glTF::LazyDict<glTF::Light>&, glTF::AssetWriter&) |
711 | | |
712 | | #if _MSC_VER |
713 | | # pragma warning(pop) |
714 | | #endif // _WIN32 |
715 | | |
716 | | } |