/** * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ #pragma once #include #include "FBX2glTF.h" #include "gltf/properties/AccessorData.hpp" #include "gltf/properties/AnimationData.hpp" #include "gltf/properties/BufferData.hpp" #include "gltf/properties/BufferViewData.hpp" #include "gltf/properties/CameraData.hpp" #include "gltf/properties/ImageData.hpp" #include "gltf/properties/MaterialData.hpp" #include "gltf/properties/MeshData.hpp" #include "gltf/properties/NodeData.hpp" #include "gltf/properties/PrimitiveData.hpp" #include "gltf/properties/SamplerData.hpp" #include "gltf/properties/SceneData.hpp" #include "gltf/properties/SkinData.hpp" #include "gltf/properties/TextureData.hpp" /** * glTF 2.0 is based on the idea that data structs within a file are referenced by index; an accessor will * point to the n:th buffer view, and so on. The Holder class takes a freshly instantiated class, and then * creates, stored, and returns a shared_ptr for it. * * The idea is that every glTF resource in the file will live as long as the Holder does, and the Holders * are all kept in the GLTFData struct. Clients may certainly cnhoose to perpetuate the full shared_ptr * reference counting type, but generally speaking we pass around simple T& and T* types because the GLTFData * struct will, by design, outlive all other activity that takes place during in a single conversion run. */ template class Holder { public: std::shared_ptr hold(T *ptr) { ptr->ix = ptrs.size(); ptrs.emplace_back(ptr); return ptrs.back(); } std::vector> ptrs; }; class GltfModel { public: explicit GltfModel(const GltfOptions &options) : binary(new std::vector) , isGlb(options.outputBinary) , defaultSampler(nullptr) , defaultBuffer(buffers.hold(buildDefaultBuffer(options))) { defaultSampler = samplers.hold(buildDefaultSampler()); } std::shared_ptr GetAlignedBufferView(BufferData &buffer, const BufferViewData::GL_ArrayType target); std::shared_ptr AddRawBufferView(BufferData &buffer, const char *source, uint32_t bytes); std::shared_ptr AddBufferViewForFile(BufferData &buffer, const std::string &filename); template std::shared_ptr AddAccessorWithView( BufferViewData &bufferView, const GLType &type, const std::vector &source, std::string name) { auto accessor = accessors.hold(new AccessorData(bufferView, type, name)); accessor->appendAsBinaryArray(source, *binary); bufferView.byteLength = accessor->byteLength(); return accessor; } template std::shared_ptr AddAccessorAndView( BufferData &buffer, const GLType &type, const std::vector &source) { auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE); return AddAccessorWithView(*bufferView, type, source, std::string("")); } template std::shared_ptr AddAccessorAndView( BufferData &buffer, const GLType &type, const std::vector &source, std::string name) { auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE); return AddAccessorWithView(*bufferView, type, source, name); } template std::shared_ptr AddAttributeToPrimitive( BufferData &buffer, const RawModel &surfaceModel, PrimitiveData &primitive, const AttributeDefinition &attrDef) { // copy attribute data into vector std::vector attribArr; surfaceModel.GetAttributeArray(attribArr, attrDef.rawAttributeIx); std::shared_ptr accessor; if (attrDef.dracoComponentType != draco::DT_INVALID && primitive.dracoMesh != nullptr) { primitive.AddDracoAttrib(attrDef, attribArr); accessor = accessors.hold(new AccessorData(attrDef.glType)); accessor->count = attribArr.size(); } else { auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER); accessor = AddAccessorWithView(*bufferView, attrDef.glType, attribArr, std::string("")); } primitive.AddAttrib(attrDef.gltfName, *accessor); return accessor; }; template void serializeHolder(json &glTFJson, std::string key, const Holder holder) { if (!holder.ptrs.empty()) { std::vector bits; for (const auto &ptr : holder.ptrs) { bits.push_back(ptr->serialize()); } glTFJson[key] = bits; } } void serializeHolders(json &glTFJson); const bool isGlb; // cache BufferViewData instances that've already been created from a given filename std::map> filenameToBufferView; std::shared_ptr> binary; Holder buffers; Holder bufferViews; Holder accessors; Holder images; Holder samplers; Holder textures; Holder materials; Holder meshes; Holder skins; Holder animations; Holder cameras; Holder nodes; Holder scenes; std::shared_ptr defaultSampler; std::shared_ptr defaultBuffer; private: SamplerData *buildDefaultSampler() { return new SamplerData(); } BufferData *buildDefaultBuffer(const GltfOptions &options) { return options.outputBinary ? new BufferData(binary) : new BufferData(extBufferFilename, binary, options.embedResources); } };