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