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