1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14copyright notice, this list of conditions and the
15following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18copyright notice, this list of conditions and the
19following disclaimer in the documentation and/or other
20materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23contributors may be used to endorse or promote products
24derived from this software without specific prior
25written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42#include <rapidjson/stringbuffer.h>
43#include <rapidjson/writer.h>
44#include <rapidjson/prettywriter.h>
45
46namespace glTF2 {
47
48 using rapidjson::StringBuffer;
49 using rapidjson::PrettyWriter;
50 using rapidjson::Writer;
51 using rapidjson::StringRef;
52 using rapidjson::StringRef;
53
54 namespace {
55
56 template<size_t N>
57 inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
58 val.SetArray();
59 val.Reserve(N, al);
60 for (decltype(N) i = 0; i < N; ++i) {
61 val.PushBack(r[i], al);
62 }
63 return val;
64 }
65
66 inline Value& MakeValue(Value& val, const std::vector<float> & r, MemoryPoolAllocator<>& al) {
67 val.SetArray();
68 val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
69 for (unsigned int i = 0; i < r.size(); ++i) {
70 val.PushBack(r[i], al);
71 }
72 return val;
73 }
74
75 inline Value& MakeValue(Value& val, float r, MemoryPoolAllocator<>& /*al*/) {
76 val.SetDouble(r);
77
78 return val;
79 }
80
81 template<class T>
82 inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
83 if (v.empty()) return;
84 Value lst;
85 lst.SetArray();
86 lst.Reserve(unsigned(v.size()), al);
87 for (size_t i = 0; i < v.size(); ++i) {
88 lst.PushBack(v[i]->index, al);
89 }
90 obj.AddMember(StringRef(fieldId), lst, al);
91 }
92
93
94 }
95
96 inline void Write(Value& obj, Accessor& a, AssetWriter& w)
97 {
98 obj.AddMember("bufferView", a.bufferView->index, w.mAl);
99 obj.AddMember("byteOffset", a.byteOffset, w.mAl);
100
101 obj.AddMember("componentType", int(a.componentType), w.mAl);
102 obj.AddMember("count", a.count, w.mAl);
103 obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
104
105 Value vTmpMax, vTmpMin;
106 obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl);
107 obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
108 }
109
110 inline void Write(Value& obj, Animation& a, AssetWriter& w)
111 {
112 /****************** Channels *******************/
113 Value channels;
114 channels.SetArray();
115 channels.Reserve(unsigned(a.Channels.size()), w.mAl);
116
117 for (size_t i = 0; i < unsigned(a.Channels.size()); ++i) {
118 Animation::AnimChannel& c = a.Channels[i];
119 Value valChannel;
120 valChannel.SetObject();
121 {
122 valChannel.AddMember("sampler", c.sampler, w.mAl);
123
124 Value valTarget;
125 valTarget.SetObject();
126 {
127 valTarget.AddMember("node", c.target.node->index, w.mAl);
128 valTarget.AddMember("path", c.target.path, w.mAl);
129 }
130 valChannel.AddMember("target", valTarget, w.mAl);
131 }
132 channels.PushBack(valChannel, w.mAl);
133 }
134 obj.AddMember("channels", channels, w.mAl);
135
136 /****************** Samplers *******************/
137 Value valSamplers;
138 valSamplers.SetArray();
139
140 for (size_t i = 0; i < unsigned(a.Samplers.size()); ++i) {
141 Animation::AnimSampler& s = a.Samplers[i];
142 Value valSampler;
143 valSampler.SetObject();
144 {
145 Ref<Accessor> inputAccessor = a.GetAccessor(s.input);
146 Ref<Accessor> outputAccessor = a.GetAccessor(s.output);
147 valSampler.AddMember("input", inputAccessor->index, w.mAl);
148 valSampler.AddMember("interpolation", s.interpolation, w.mAl);
149 valSampler.AddMember("output", outputAccessor->index, w.mAl);
150 }
151 valSamplers.PushBack(valSampler, w.mAl);
152 }
153 obj.AddMember("samplers", valSamplers, w.mAl);
154 }
155
156 inline void Write(Value& obj, Buffer& b, AssetWriter& w)
157 {
158 obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl);
159 obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl);
160 }
161
162 inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
163 {
164 obj.AddMember("buffer", bv.buffer->index, w.mAl);
165 obj.AddMember("byteOffset", static_cast<uint64_t>(bv.byteOffset), w.mAl);
166 obj.AddMember("byteLength", static_cast<uint64_t>(bv.byteLength), w.mAl);
167 if (bv.byteStride != 0) {
168 obj.AddMember("byteStride", bv.byteStride, w.mAl);
169 }
170 obj.AddMember("target", int(bv.target), w.mAl);
171 }
172
173 inline void Write(Value& /*obj*/, Camera& /*c*/, AssetWriter& /*w*/)
174 {
175
176 }
177
178 inline void Write(Value& obj, Image& img, AssetWriter& w)
179 {
180 std::string uri;
181 if (img.HasData()) {
182 uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType);
183 uri += ";base64,";
184 Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri);
185 }
186 else {
187 uri = img.uri;
188 }
189
190 obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl);
191 }
192
193 namespace {
194 inline void SetTexBasic(TextureInfo t, Value& tex, MemoryPoolAllocator<>& al)
195 {
196 tex.SetObject();
197 tex.AddMember("index", t.texture->index, al);
198
199 if (t.texCoord != 0) {
200 tex.AddMember("texCoord", t.texCoord, al);
201 }
202 }
203
204 inline void WriteTex(Value& obj, TextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
205 {
206
207 if (t.texture) {
208 Value tex;
209
210 SetTexBasic(t, tex, al);
211
212 obj.AddMember(StringRef(propName), tex, al);
213 }
214 }
215
216 inline void WriteTex(Value& obj, NormalTextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
217 {
218
219 if (t.texture) {
220 Value tex;
221
222 SetTexBasic(t, tex, al);
223
224 if (t.scale != 1) {
225 tex.AddMember("scale", t.scale, al);
226 }
227
228 obj.AddMember(StringRef(propName), tex, al);
229 }
230 }
231
232 inline void WriteTex(Value& obj, OcclusionTextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
233 {
234
235 if (t.texture) {
236 Value tex;
237
238 SetTexBasic(t, tex, al);
239
240 if (t.strength != 1) {
241 tex.AddMember("strength", t.strength, al);
242 }
243
244 obj.AddMember(StringRef(propName), tex, al);
245 }
246 }
247
248 template<size_t N>
249 inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, MemoryPoolAllocator<>& al)
250 {
251 Value arr;
252 obj.AddMember(StringRef(propName), MakeValue(arr, prop, al), al);
253 }
254
255 template<size_t N>
256 inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, const float(&defaultVal)[N], MemoryPoolAllocator<>& al)
257 {
258 if (!std::equal(std::begin(prop), std::end(prop), std::begin(defaultVal))) {
259 WriteVec(obj, prop, propName, al);
260 }
261 }
262
263 inline void WriteFloat(Value& obj, float prop, const char* propName, MemoryPoolAllocator<>& al)
264 {
265 Value num;
266 obj.AddMember(StringRef(propName), MakeValue(num, prop, al), al);
267 }
268 }
269
270 inline void Write(Value& obj, Material& m, AssetWriter& w)
271 {
272 Value pbrMetallicRoughness;
273 pbrMetallicRoughness.SetObject();
274 {
275 WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorTexture, "baseColorTexture", w.mAl);
276 WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicRoughnessTexture, "metallicRoughnessTexture", w.mAl);
277 WriteVec(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorFactor, "baseColorFactor", defaultBaseColor, w.mAl);
278
279 if (m.pbrMetallicRoughness.metallicFactor != 1) {
280 WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicFactor, "metallicFactor", w.mAl);
281 }
282
283 if (m.pbrMetallicRoughness.roughnessFactor != 1) {
284 WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.roughnessFactor, "roughnessFactor", w.mAl);
285 }
286 }
287
288 if (!pbrMetallicRoughness.ObjectEmpty()) {
289 obj.AddMember("pbrMetallicRoughness", pbrMetallicRoughness, w.mAl);
290 }
291
292 WriteTex(obj, m.normalTexture, "normalTexture", w.mAl);
293 WriteTex(obj, m.emissiveTexture, "emissiveTexture", w.mAl);
294 WriteTex(obj, m.occlusionTexture, "occlusionTexture", w.mAl);
295 WriteVec(obj, m.emissiveFactor, "emissiveFactor", defaultEmissiveFactor, w.mAl);
296
297 if (m.alphaCutoff != 0.5) {
298 WriteFloat(obj, m.alphaCutoff, "alphaCutoff", w.mAl);
299 }
300
301 if (m.alphaMode != "OPAQUE") {
302 obj.AddMember("alphaMode", Value(m.alphaMode, w.mAl).Move(), w.mAl);
303 }
304
305 if (m.doubleSided) {
306 obj.AddMember("doubleSided", m.doubleSided, w.mAl);
307 }
308
309 Value exts;
310 exts.SetObject();
311
312 if (m.pbrSpecularGlossiness.isPresent) {
313 Value pbrSpecularGlossiness;
314 pbrSpecularGlossiness.SetObject();
315
316 PbrSpecularGlossiness &pbrSG = m.pbrSpecularGlossiness.value;
317
318 //pbrSpecularGlossiness
319 WriteVec(pbrSpecularGlossiness, pbrSG.diffuseFactor, "diffuseFactor", defaultDiffuseFactor, w.mAl);
320 WriteVec(pbrSpecularGlossiness, pbrSG.specularFactor, "specularFactor", defaultSpecularFactor, w.mAl);
321
322 if (pbrSG.glossinessFactor != 1) {
323 WriteFloat(obj, pbrSG.glossinessFactor, "glossinessFactor", w.mAl);
324 }
325
326 WriteTex(pbrSpecularGlossiness, pbrSG.diffuseTexture, "diffuseTexture", w.mAl);
327 WriteTex(pbrSpecularGlossiness, pbrSG.specularGlossinessTexture, "specularGlossinessTexture", w.mAl);
328
329 if (!pbrSpecularGlossiness.ObjectEmpty()) {
330 exts.AddMember("KHR_materials_pbrSpecularGlossiness", pbrSpecularGlossiness, w.mAl);
331 }
332 }
333
334 if (!exts.ObjectEmpty()) {
335 obj.AddMember("extensions", exts, w.mAl);
336 }
337 }
338
339 namespace {
340 inline void WriteAttrs(AssetWriter& w, Value& attrs, Mesh::AccessorList& lst,
341 const char* semantic, bool forceNumber = false)
342 {
343 if (lst.empty()) return;
344 if (lst.size() == 1 && !forceNumber) {
345 attrs.AddMember(StringRef(semantic), lst[0]->index, w.mAl);
346 }
347 else {
348 for (size_t i = 0; i < lst.size(); ++i) {
349 char buffer[32];
350 ai_snprintf(buffer, 32, "%s_%d", semantic, int(i));
351 attrs.AddMember(Value(buffer, w.mAl).Move(), lst[i]->index, w.mAl);
352 }
353 }
354 }
355 }
356
357 inline void Write(Value& obj, Mesh& m, AssetWriter& w)
358 {
359 /****************** Primitives *******************/
360 Value primitives;
361 primitives.SetArray();
362 primitives.Reserve(unsigned(m.primitives.size()), w.mAl);
363
364 for (size_t i = 0; i < m.primitives.size(); ++i) {
365 Mesh::Primitive& p = m.primitives[i];
366 Value prim;
367 prim.SetObject();
368 {
369 prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl);
370
371 if (p.material)
372 prim.AddMember("material", p.material->index, w.mAl);
373
374 if (p.indices)
375 prim.AddMember("indices", p.indices->index, w.mAl);
376
377 Value attrs;
378 attrs.SetObject();
379 {
380 WriteAttrs(w, attrs, p.attributes.position, "POSITION");
381 WriteAttrs(w, attrs, p.attributes.normal, "NORMAL");
382 WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true);
383 WriteAttrs(w, attrs, p.attributes.color, "COLOR", true);
384 WriteAttrs(w, attrs, p.attributes.joint, "JOINTS", true);
385 WriteAttrs(w, attrs, p.attributes.weight, "WEIGHTS", true);
386 }
387 prim.AddMember("attributes", attrs, w.mAl);
388 }
389 primitives.PushBack(prim, w.mAl);
390 }
391
392 obj.AddMember("primitives", primitives, w.mAl);
393 }
394
395 inline void Write(Value& obj, Node& n, AssetWriter& w)
396 {
397
398 if (n.matrix.isPresent) {
399 Value val;
400 obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl);
401 }
402
403 if (n.translation.isPresent) {
404 Value val;
405 obj.AddMember("translation", MakeValue(val, n.translation.value, w.mAl).Move(), w.mAl);
406 }
407
408 if (n.scale.isPresent) {
409 Value val;
410 obj.AddMember("scale", MakeValue(val, n.scale.value, w.mAl).Move(), w.mAl);
411 }
412 if (n.rotation.isPresent) {
413 Value val;
414 obj.AddMember("rotation", MakeValue(val, n.rotation.value, w.mAl).Move(), w.mAl);
415 }
416
417 AddRefsVector(obj, "children", n.children, w.mAl);
418
419 if (!n.meshes.empty()) {
420 obj.AddMember("mesh", n.meshes[0]->index, w.mAl);
421 }
422
423 AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
424
425 if (n.skin) {
426 obj.AddMember("skin", n.skin->index, w.mAl);
427 }
428
429 if (!n.jointName.empty()) {
430 obj.AddMember("jointName", n.jointName, w.mAl);
431 }
432 }
433
434 inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/)
435 {
436
437 }
438
439 inline void Write(Value& obj, Sampler& b, AssetWriter& w)
440 {
441 if (!b.name.empty()) {
442 obj.AddMember("name", b.name, w.mAl);
443 }
444
445 if (b.wrapS != SamplerWrap::UNSET && b.wrapS != SamplerWrap::Repeat) {
446 obj.AddMember("wrapS", static_cast<unsigned int>(b.wrapS), w.mAl);
447 }
448
449 if (b.wrapT != SamplerWrap::UNSET && b.wrapT != SamplerWrap::Repeat) {
450 obj.AddMember("wrapT", static_cast<unsigned int>(b.wrapT), w.mAl);
451 }
452
453 if (b.magFilter != SamplerMagFilter::UNSET) {
454 obj.AddMember("magFilter", static_cast<unsigned int>(b.magFilter), w.mAl);
455 }
456
457 if (b.minFilter != SamplerMinFilter::UNSET) {
458 obj.AddMember("minFilter", static_cast<unsigned int>(b.minFilter), w.mAl);
459 }
460 }
461
462 inline void Write(Value& scene, Scene& s, AssetWriter& w)
463 {
464 AddRefsVector(scene, "nodes", s.nodes, w.mAl);
465 }
466
467 inline void Write(Value& /*obj*/, Shader& /*b*/, AssetWriter& /*w*/)
468 {
469
470 }
471
472 inline void Write(Value& obj, Skin& b, AssetWriter& w)
473 {
474 /****************** jointNames *******************/
475 Value vJointNames;
476 vJointNames.SetArray();
477 vJointNames.Reserve(unsigned(b.jointNames.size()), w.mAl);
478
479 for (size_t i = 0; i < unsigned(b.jointNames.size()); ++i) {
480 vJointNames.PushBack(b.jointNames[i]->index, w.mAl);
481 }
482 obj.AddMember("joints", vJointNames, w.mAl);
483
484 if (b.bindShapeMatrix.isPresent) {
485 Value val;
486 obj.AddMember("bindShapeMatrix", MakeValue(val, b.bindShapeMatrix.value, w.mAl).Move(), w.mAl);
487 }
488
489 if (b.inverseBindMatrices) {
490 obj.AddMember("inverseBindMatrices", b.inverseBindMatrices->index, w.mAl);
491 }
492
493 }
494
495 inline void Write(Value& obj, Texture& tex, AssetWriter& w)
496 {
497 if (tex.source) {
498 obj.AddMember("source", tex.source->index, w.mAl);
499 }
500 if (tex.sampler) {
501 obj.AddMember("sampler", tex.sampler->index, w.mAl);
502 }
503 }
504
505
506 inline AssetWriter::AssetWriter(Asset& a)
507 : mDoc()
508 , mAsset(a)
509 , mAl(mDoc.GetAllocator())
510 {
511 mDoc.SetObject();
512
513 WriteMetadata();
514 WriteExtensionsUsed();
515
516 // Dump the contents of the dictionaries
517 for (size_t i = 0; i < a.mDicts.size(); ++i) {
518 a.mDicts[i]->WriteObjects(*this);
519 }
520
521 // Add the target scene field
522 if (mAsset.scene) {
523 mDoc.AddMember("scene", mAsset.scene->index, mAl);
524 }
525 }
526
527 inline void AssetWriter::WriteFile(const char* path)
528 {
529 std::unique_ptr<IOStream> jsonOutFile(mAsset.OpenFile(path, "wt", true));
530
531 if (jsonOutFile == 0) {
532 throw DeadlyExportError("Could not open output file: " + std::string(path));
533 }
534
535 StringBuffer docBuffer;
536
537 PrettyWriter<StringBuffer> writer(docBuffer);
538 mDoc.Accept(writer);
539
540 if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
541 throw DeadlyExportError("Failed to write scene data!");
542 }
543
544 // Write buffer data to separate .bin files
545 for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) {
546 Ref<Buffer> b = mAsset.buffers.Get(i);
547
548 std::string binPath = b->GetURI();
549
550 std::unique_ptr<IOStream> binOutFile(mAsset.OpenFile(binPath, "wb", true));
551
552 if (binOutFile == 0) {
553 throw DeadlyExportError("Could not open output file: " + binPath);
554 }
555
556 if (b->byteLength > 0) {
557 if (binOutFile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
558 throw DeadlyExportError("Failed to write binary file: " + binPath);
559 }
560 }
561 }
562 }
563
564 inline void AssetWriter::WriteMetadata()
565 {
566 Value asset;
567 asset.SetObject();
568 asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
569 asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
570 mDoc.AddMember("asset", asset, mAl);
571 }
572
573 inline void AssetWriter::WriteExtensionsUsed()
574 {
575 Value exts;
576 exts.SetArray();
577 {
578 // This is used to export pbrSpecularGlossiness materials with GLTF 2.
579 if (this->mAsset.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
580 exts.PushBack(StringRef("KHR_materials_pbrSpecularGlossiness"), mAl);
581 }
582 }
583
584 if (!exts.Empty())
585 mDoc.AddMember("extensionsUsed", exts, mAl);
586 }
587
588 template<class T>
589 void AssetWriter::WriteObjects(LazyDict<T>& d)
590 {
591 if (d.mObjs.empty()) return;
592
593 Value* container = &mDoc;
594
595 if (d.mExtId) {
596 Value* exts = FindObject(mDoc, "extensions");
597 if (!exts) {
598 mDoc.AddMember("extensions", Value().SetObject().Move(), mDoc.GetAllocator());
599 exts = FindObject(mDoc, "extensions");
600 }
601
602 if (!(container = FindObject(*exts, d.mExtId))) {
603 exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator());
604 container = FindObject(*exts, d.mExtId);
605 }
606 }
607
608 Value* dict;
609 if (!(dict = FindArray(*container, d.mDictId))) {
610 container->AddMember(StringRef(d.mDictId), Value().SetArray().Move(), mDoc.GetAllocator());
611 dict = FindArray(*container, d.mDictId);
612 }
613
614 for (size_t i = 0; i < d.mObjs.size(); ++i) {
615 if (d.mObjs[i]->IsSpecial()) continue;
616
617 Value obj;
618 obj.SetObject();
619
620 if (!d.mObjs[i]->name.empty()) {
621 obj.AddMember("name", StringRef(d.mObjs[i]->name.c_str()), mAl);
622 }
623
624 Write(obj, *d.mObjs[i], *this);
625
626 dict->PushBack(obj, mAl);
627 }
628 }
629
630 template<class T>
631 void WriteLazyDict(LazyDict<T>& d, AssetWriter& w)
632 {
633 w.WriteObjects(d);
634 }
635
636}
637
638
639