/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef GLTFIO_FFILAMENTASSET_H #define GLTFIO_FFILAMENTASSET_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "upcast.h" #include "DependencyGraph.h" #include "DracoCache.h" #include "FFilamentInstance.h" #include #include #include #ifdef NDEBUG #define GLTFIO_VERBOSE 0 #define GLTFIO_WARN(msg) #else #define GLTFIO_VERBOSE 1 #define GLTFIO_WARN(msg) slog.w << msg << io::endl #endif namespace utils { class NameComponentManager; class EntityManager; } namespace gltfio { class Animator; class Wireframe; class MorphHelper; // Encapsulates VertexBuffer::setBufferAt() or IndexBuffer::setBuffer(). struct BufferSlot { const cgltf_accessor* accessor; cgltf_attribute_type attribute; int bufferIndex; // for vertex buffers only filament::VertexBuffer* vertexBuffer; filament::IndexBuffer* indexBuffer; }; // Encapsulates a connection between Texture and MaterialInstance. struct TextureSlot { const cgltf_texture* texture; filament::MaterialInstance* materialInstance; const char* materialParameter; filament::TextureSampler sampler; bool srgb; }; // MeshCache // --------- // If a given glTF mesh is referenced by multiple glTF nodes, then it generates a separate Filament // renderable for each of those nodes. All renderables generated by a given mesh share a common set // of VertexBuffer and IndexBuffer objects. To achieve the sharing behavior, the loader maintains a // small cache. The cache keys are glTF mesh definitions and the cache entries are lists of // primitives, where a "primitive" is a reference to a Filament VertexBuffer and IndexBuffer. struct Primitive { filament::VertexBuffer* vertices = nullptr; filament::IndexBuffer* indices = nullptr; filament::Aabb aabb; // object-space bounding box UvMap uvmap; // mapping from each glTF UV set to either UV0 or UV1 (8 bytes) }; using MeshCache = tsl::robin_map>; // MatInstanceCache // ---------------- // Each glTF material definition corresponds to a single filament::MaterialInstance, which are // temporarily cached during loading. The filament::Material objects that are used to create instances are // cached in MaterialProvider. If a given glTF material is referenced by multiple glTF meshes, then // their corresponding filament primitives will share the same Filament MaterialInstance and UvMap. // The UvMap is a mapping from each texcoord slot in glTF to one of Filament's 2 texcoord sets. struct MaterialEntry { filament::MaterialInstance* instance; UvMap uvmap; }; using MatInstanceCache = tsl::robin_map; struct FFilamentAsset : public FilamentAsset { FFilamentAsset(filament::Engine* engine, utils::NameComponentManager* names, utils::EntityManager* entityManager, const cgltf_data* srcAsset) : mEngine(engine), mNameManager(names), mEntityManager(entityManager) { mSourceAsset.reset(new SourceAsset {(cgltf_data*)srcAsset}); } ~FFilamentAsset(); size_t getEntityCount() const noexcept { return mEntities.size(); } const utils::Entity* getEntities() const noexcept { return mEntities.empty() ? nullptr : mEntities.data(); } const utils::Entity* getLightEntities() const noexcept { return mLightEntities.empty() ? nullptr : mLightEntities.data(); } size_t getLightEntityCount() const noexcept { return mLightEntities.size(); } const utils::Entity* getCameraEntities() const noexcept { return mCameraEntities.empty() ? nullptr : mCameraEntities.data(); } size_t getCameraEntityCount() const noexcept { return mCameraEntities.size(); } utils::Entity getRoot() const noexcept { return mRoot; } size_t popRenderables(utils::Entity* entities, size_t count) noexcept { return mDependencyGraph.popRenderables(entities, count); } size_t getMaterialInstanceCount() const noexcept { return mMaterialInstances.size(); } const filament::MaterialInstance* const* getMaterialInstances() const noexcept { return mMaterialInstances.data(); } filament::MaterialInstance* const* getMaterialInstances() noexcept { return mMaterialInstances.data(); } size_t getResourceUriCount() const noexcept { return mResourceUris.size(); } const char* const* getResourceUris() const noexcept { return mResourceUris.data(); } filament::Aabb getBoundingBox() const noexcept { return mBoundingBox; } const char* getName(utils::Entity entity) const noexcept; const char* getExtras(utils::Entity entity) const noexcept; utils::Entity getFirstEntityByName(const char* name) noexcept; size_t getEntitiesByName(const char* name, utils::Entity* entities, size_t maxCount) const noexcept; size_t getEntitiesByPrefix(const char* prefix, utils::Entity* entities, size_t maxCount) const noexcept; Animator* getAnimator() noexcept; void setMorphWeights(utils::Entity entity , const float* weights, size_t count) noexcept; int getMorphTargetCount(utils::Entity entity) noexcept; utils::Entity getWireframe() noexcept; filament::Engine* getEngine() const noexcept { return mEngine; } void releaseSourceData() noexcept; const void* getSourceAsset() const noexcept { return mSourceAsset.get() ? mSourceAsset->hierarchy : nullptr; } FilamentInstance** getAssetInstances() noexcept { return (FilamentInstance**) mInstances.data(); } size_t getAssetInstanceCount() const noexcept { return mInstances.size(); } void takeOwnership(filament::Texture* texture) { mTextures.push_back(texture); } void bindTexture(const TextureSlot& tb, filament::Texture* texture) { tb.materialInstance->setParameter(tb.materialParameter, texture, tb.sampler); mDependencyGraph.addEdge(texture, tb.materialInstance, tb.materialParameter); } bool isInstanced() const { return mInstances.size() > 0; } filament::Engine* mEngine; utils::NameComponentManager* mNameManager; utils::EntityManager* mEntityManager; std::vector mEntities; std::vector mLightEntities; std::vector mCameraEntities; std::vector mMaterialInstances; std::vector mVertexBuffers; std::vector mBufferObjects; std::vector mIndexBuffers; std::vector mTextures; filament::Aabb mBoundingBox; utils::Entity mRoot; std::vector mInstances; SkinVector mSkins; // unused for instanced assets Animator* mAnimator = nullptr; MorphHelper* mMorpher = nullptr; Wireframe* mWireframe = nullptr; bool mResourcesLoaded = false; DependencyGraph mDependencyGraph; tsl::htrie_map> mNameToEntity; tsl::robin_map mNodeExtras; utils::CString mAssetExtras; // Sentinels for situations where ResourceLoader needs to generate data. const cgltf_accessor mGenerateNormals = {}; const cgltf_accessor mGenerateTangents = {}; // Encapsulates reference-counted source data, which includes the cgltf hierachy // and potentially also includes buffer data that can be uploaded to the GPU. struct SourceAsset { ~SourceAsset() { cgltf_free(hierarchy); } cgltf_data* hierarchy; DracoCache dracoCache; utils::FixedCapacityVector glbData; }; // We used shared ownership for the raw cgltf data in order to permit ResourceLoader to // complete various asynchronous work (e.g. uploading buffers to the GPU) even after the asset // or ResourceLoader have been destroyed. using SourceHandle = std::shared_ptr; SourceHandle mSourceAsset; // Transient source data that can freed via releaseSourceData: std::vector mBufferSlots; std::vector mTextureSlots; std::vector mResourceUris; NodeMap mNodeMap; // unused for instanced assets std::vector > mPrimitives; MatInstanceCache mMatInstanceCache; MeshCache mMeshCache; }; FILAMENT_UPCAST(FilamentAsset) } // namespace gltfio #endif // GLTFIO_FFILAMENTASSET_H