diff --git a/android/gltfio-android/CMakeLists.txt b/android/gltfio-android/CMakeLists.txt index 12949c7a03..765581a25d 100644 --- a/android/gltfio-android/CMakeLists.txt +++ b/android/gltfio-android/CMakeLists.txt @@ -40,30 +40,33 @@ set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl, set(GLTFIO_SRCS ${GLTFIO_DIR}/include/gltfio/Animator.h ${GLTFIO_DIR}/include/gltfio/AssetLoader.h - ${GLTFIO_DIR}/include/gltfio/MaterialProvider.h - ${GLTFIO_DIR}/include/gltfio/ResourceLoader.h ${GLTFIO_DIR}/include/gltfio/FilamentAsset.h ${GLTFIO_DIR}/include/gltfio/FilamentInstance.h + ${GLTFIO_DIR}/include/gltfio/MaterialProvider.h + ${GLTFIO_DIR}/include/gltfio/NodeManager.h + ${GLTFIO_DIR}/include/gltfio/ResourceLoader.h ${GLTFIO_DIR}/include/gltfio/TextureProvider.h ${GLTFIO_DIR}/include/gltfio/math.h ${GLTFIO_DIR}/src/Animator.cpp ${GLTFIO_DIR}/src/AssetLoader.cpp - ${GLTFIO_DIR}/src/DracoCache.cpp - ${GLTFIO_DIR}/src/DracoCache.h ${GLTFIO_DIR}/src/DependencyGraph.cpp ${GLTFIO_DIR}/src/DependencyGraph.h + ${GLTFIO_DIR}/src/DracoCache.cpp + ${GLTFIO_DIR}/src/DracoCache.h ${GLTFIO_DIR}/src/FFilamentAsset.h - ${GLTFIO_DIR}/src/FilamentAsset.cpp ${GLTFIO_DIR}/src/FFilamentInstance.h + ${GLTFIO_DIR}/src/FilamentAsset.cpp ${GLTFIO_DIR}/src/FilamentInstance.cpp + ${GLTFIO_DIR}/src/FNodeManager.h ${GLTFIO_DIR}/src/GltfEnums.h ${GLTFIO_DIR}/src/Ktx2Provider.cpp ${GLTFIO_DIR}/src/MaterialProvider.cpp + ${GLTFIO_DIR}/src/NodeManager.cpp ${GLTFIO_DIR}/src/ResourceLoader.cpp ${GLTFIO_DIR}/src/StbProvider.cpp - ${GLTFIO_DIR}/src/TangentsJob.h ${GLTFIO_DIR}/src/TangentsJob.cpp + ${GLTFIO_DIR}/src/TangentsJob.h ${GLTFIO_DIR}/src/UbershaderLoader.cpp ${GLTFIO_DIR}/src/Wireframe.cpp ${GLTFIO_DIR}/src/Wireframe.h diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentAsset.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentAsset.java index 747db67333..ed7af8e0dc 100644 --- a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentAsset.java +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentAsset.java @@ -30,9 +30,9 @@ import com.google.android.filament.MaterialInstance; * *

For usage instructions, see the documentation for {@link AssetLoader}.

* - *

This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity has - * a TransformManager component, and some entities also have - * NameComponentManager and/or RenderableManager components.

+ *

This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity + * has a TransformManager component, and some entities also have compnents managed by + * NameComponentManager, RenderableManager, and others.

* *

In addition to the aforementioned entities, an asset has strong ownership over a list of * VertexBuffer, IndexBuffer, MaterialInstance, and diff --git a/libs/gltfio/CMakeLists.txt b/libs/gltfio/CMakeLists.txt index ee0347b916..c55f2d648b 100644 --- a/libs/gltfio/CMakeLists.txt +++ b/libs/gltfio/CMakeLists.txt @@ -10,10 +10,11 @@ set(PUBLIC_HDR_DIR include) set(PUBLIC_HDRS include/gltfio/Animator.h include/gltfio/AssetLoader.h - include/gltfio/MaterialProvider.h - include/gltfio/ResourceLoader.h include/gltfio/FilamentAsset.h include/gltfio/FilamentInstance.h + include/gltfio/MaterialProvider.h + include/gltfio/NodeManager.h + include/gltfio/ResourceLoader.h include/gltfio/TextureProvider.h include/gltfio/math.h ) @@ -23,19 +24,21 @@ set(SRCS src/AssetLoader.cpp src/DependencyGraph.cpp src/DependencyGraph.h - src/DracoCache.h src/DracoCache.cpp + src/DracoCache.h src/FFilamentAsset.h - src/FilamentAsset.cpp src/FFilamentInstance.h + src/FilamentAsset.cpp src/FilamentInstance.cpp + src/FNodeManager.h src/GltfEnums.h src/Ktx2Provider.cpp src/MaterialProvider.cpp + src/NodeManager.cpp src/ResourceLoader.cpp src/StbProvider.cpp - src/TangentsJob.h src/TangentsJob.cpp + src/TangentsJob.h src/UbershaderLoader.cpp src/Wireframe.cpp src/Wireframe.h diff --git a/libs/gltfio/include/gltfio/AssetLoader.h b/libs/gltfio/include/gltfio/AssetLoader.h index 90491c9852..91dc557faf 100644 --- a/libs/gltfio/include/gltfio/AssetLoader.h +++ b/libs/gltfio/include/gltfio/AssetLoader.h @@ -36,6 +36,8 @@ namespace utils { */ namespace gltfio { +class NodeManager; + /** * \struct AssetConfiguration AssetLoader.h gltfio/AssetLoader.h * \brief Construction parameters for AssetLoader. @@ -70,7 +72,8 @@ struct AssetConfiguration { * object, which is a bundle of Filament entities, material instances, textures, vertex buffers, * and index buffers. * - * Clients must use AssetLoader to create and destroy FilamentAsset objects. + * Clients must use AssetLoader to create and destroy FilamentAsset objects. This is similar to + * how filament::Engine is used to create and destroy core objects like VertexBuffer. * * AssetLoader does not fetch external buffer data or create textures on its own. Clients can use * ResourceLoader for this, which obtains the URI list from the asset. This is demonstrated in the @@ -226,7 +229,9 @@ public: utils::NameComponentManager* getNames() const noexcept; - MaterialProvider* getMaterialProvider() const noexcept; + NodeManager& getNodeManager() noexcept; + + MaterialProvider& getMaterialProvider() noexcept; /*! \cond PRIVATE */ protected: diff --git a/libs/gltfio/include/gltfio/FilamentAsset.h b/libs/gltfio/include/gltfio/FilamentAsset.h index b6f4c2ae7c..c3dd8da477 100644 --- a/libs/gltfio/include/gltfio/FilamentAsset.h +++ b/libs/gltfio/include/gltfio/FilamentAsset.h @@ -42,7 +42,7 @@ class FilamentInstance; * * This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity has * a filament::TransformManager component, and some entities also have \c Name, \c Renderable, - * \c Light, or \c Camera components. + * \c Light, \c Camera, or \c Node components. * * In addition to the aforementioned entities, an asset has strong ownership over a list of * filament::VertexBuffer, filament::IndexBuffer, filament::MaterialInstance, filament::Texture, diff --git a/libs/gltfio/include/gltfio/NodeManager.h b/libs/gltfio/include/gltfio/NodeManager.h new file mode 100644 index 0000000000..7d97083511 --- /dev/null +++ b/libs/gltfio/include/gltfio/NodeManager.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 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_NODEMANAGER_H +#define GLTFIO_NODEMANAGER_H + +#include + +#include +#include +#include +#include +#include + +namespace utils { +class Entity; +} // namespace utils + +namespace gltfio { + +class FNodeManager; + +/** + * NodeManager is used to add annotate entities with glTF-specific information. + * + * Node components are created by gltfio and exposed to users to allow inspection. + * + * Nodes do not store the glTF hierarchy or names; see TransformManager and NameComponentManager. + */ +class UTILS_PUBLIC NodeManager { +public: + using Instance = utils::EntityInstance; + using Entity = utils::Entity; + using CString = utils::CString; + + /** + * Returns whether a particular Entity is associated with a component of this NodeManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(Entity e) const noexcept; + + /** + * Gets an Instance representing the node component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the node component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(Entity e) const noexcept; + + /** + * Creates a node component and associates it with the given entity. + * @param entity An Entity to associate a node component with. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(Entity e) was called. + * + * @see destroy() + */ + void create(Entity entity); + + /** + * Destroys this component from the given entity. + * @param e An entity. + * + * @see create() + */ + void destroy(Entity e) noexcept; + + void setMorphTargetNames(Instance ci, utils::FixedCapacityVector names) noexcept; + const utils::FixedCapacityVector& getMorphTargetNames(Instance ci) const noexcept; + + void setExtras(Instance ci, CString extras) noexcept; + const CString& getExtras(Instance ci) const noexcept; + + void setSceneMembership(Instance ci, utils::bitset32 scenes) noexcept; + utils::bitset32 getSceneMembership(Instance ci) const noexcept; + +protected: + NodeManager() noexcept = default; + ~NodeManager() = default; + +public: + NodeManager(NodeManager const&) = delete; + NodeManager(NodeManager&&) = delete; + NodeManager& operator=(NodeManager const&) = delete; + NodeManager& operator=(NodeManager&&) = delete; +}; + +} // namespace gltfio + + +#endif // GLTFIO_NODEMANAGER_H diff --git a/libs/gltfio/src/AssetLoader.cpp b/libs/gltfio/src/AssetLoader.cpp index 6ac421428b..2bc8447b6c 100644 --- a/libs/gltfio/src/AssetLoader.cpp +++ b/libs/gltfio/src/AssetLoader.cpp @@ -20,6 +20,7 @@ #include #include "FFilamentAsset.h" +#include "FNodeManager.h" #include "GltfEnums.h" #include @@ -93,8 +94,8 @@ struct FAssetLoader : public AssetLoader { mRenderableManager(config.engine->getRenderableManager()), mNameManager(config.names), mTransformManager(config.engine->getTransformManager()), - mMaterials(config.materials), - mEngine(config.engine), + mMaterials(*config.materials), + mEngine(*config.engine), mDefaultNodeName(config.defaultNodeName) {} FFilamentAsset* createAssetFromJson(const uint8_t* bytes, uint32_t nbytes); @@ -113,15 +114,19 @@ struct FAssetLoader : public AssetLoader { } size_t getMaterialsCount() const noexcept { - return mMaterials->getMaterialsCount(); + return mMaterials.getMaterialsCount(); } NameComponentManager* getNames() const noexcept { return mNameManager; } + NodeManager& getNodeManager() noexcept { + return mNodeManager; + } + const Material* const* getMaterials() const noexcept { - return mMaterials->getMaterials(); + return mMaterials.getMaterials(); } void createAsset(const cgltf_data* srcAsset, size_t numInstances); @@ -147,10 +152,11 @@ struct FAssetLoader : public AssetLoader { EntityManager& mEntityManager; RenderableManager& mRenderableManager; - NameComponentManager* mNameManager; + NameComponentManager* const mNameManager; TransformManager& mTransformManager; - MaterialProvider* mMaterials; - Engine* mEngine; + MaterialProvider& mMaterials; + Engine& mEngine; + FNodeManager mNodeManager; // Transient state used only for the asset currently being loaded: FFilamentAsset* mResult; @@ -270,7 +276,7 @@ void FAssetLoader::createAsset(const cgltf_data* srcAsset, size_t numInstances) } #endif - mResult = new FFilamentAsset(mEngine, mNameManager, &mEntityManager, srcAsset); + mResult = new FFilamentAsset(&mEngine, mNameManager, &mEntityManager, &mNodeManager, srcAsset); mDummyBufferObject = nullptr; // If there is no default scene specified, then the default is the first one. @@ -321,7 +327,7 @@ void FAssetLoader::createAsset(const cgltf_data* srcAsset, size_t numInstances) // Sort the entities so that the renderable ones come first. This allows us to expose // a "renderables only" pointer without storing a separate list. - const auto& rm = mEngine->getRenderableManager(); + const auto& rm = mEngine.getRenderableManager(); std::partition(mResult->mEntities.begin(), mResult->mEntities.end(), [&rm](Entity a) { return rm.hasComponent(a); }); @@ -383,6 +389,7 @@ FFilamentInstance* FAssetLoader::createInstance(FFilamentAsset* primary, void FAssetLoader::createEntity(const cgltf_data* srcAsset, const cgltf_node* node, Entity parent, bool enableLight, FFilamentInstance* instance) { Entity entity = mEntityManager.create(); + mNodeManager.create(entity); // Always create a transform component to reflect the original hierarchy. mat4f localTransform; @@ -402,8 +409,8 @@ void FAssetLoader::createEntity(const cgltf_data* srcAsset, const cgltf_node* no const cgltf_size extras_size = node->extras.end_offset - node->extras.start_offset; if (extras_size > 0) { const cgltf_data* srcAsset = mResult->mSourceAsset->hierarchy; - mResult->mNodeExtras[entity] = CString( - srcAsset->json + node->extras.start_offset, extras_size); + mNodeManager.setExtras(mNodeManager.getInstance(entity), + {srcAsset->json + node->extras.start_offset, extras_size}); } // Update the asset's entity list and private node mapping. @@ -525,12 +532,12 @@ void FAssetLoader::createRenderable(const cgltf_data* srcAsset, const cgltf_node } } - auto& morphTargetNames = mResult->mMorphTargetNames[entity]; - assert_invariant(morphTargetNames.empty()); - morphTargetNames = FixedCapacityVector(numMorphTargets); + FixedCapacityVector morphTargetNames(numMorphTargets); for (cgltf_size i = 0, c = mesh->target_names_count; i < c; ++i) { - morphTargetNames[i] = StaticString::make(mesh->target_names[i]); + morphTargetNames[i] = CString(mesh->target_names[i]); } + mNodeManager.setMorphTargetNames(mNodeManager.getInstance(entity), + std::move(morphTargetNames)); const Aabb transformed = aabb.transform(worldTransform); @@ -556,7 +563,7 @@ void FAssetLoader::createRenderable(const cgltf_data* srcAsset, const cgltf_node .culling(true) .castShadows(true) .receiveShadows(true) - .build(*mEngine, entity); + .build(mEngine, entity); // According to the spec, the mesh may or may not specify default weights, regardless of whether // it actually has morph targets. If it has morphing enabled then the default weights are 0. If @@ -630,7 +637,7 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out indices = IndexBuffer::Builder() .indexCount(accessor->count) .bufferType(indexType) - .build(*mEngine); + .build(mEngine); BufferSlot slot = { accessor }; slot.indexBuffer = indices; @@ -642,7 +649,7 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out indices = IndexBuffer::Builder() .indexCount(vertexCount) .bufferType(IndexBuffer::IndexType::UINT) - .build(*mEngine); + .build(mEngine); const size_t indexDataSize = vertexCount * sizeof(uint32_t); uint32_t* indexData = (uint32_t*) malloc(indexDataSize); @@ -650,7 +657,7 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out indexData[i] = i; } IndexBuffer::BufferDescriptor bd(indexData, indexDataSize, FREE_CALLBACK); - indices->setBuffer(*mEngine, std::move(bd)); + indices->setBuffer(mEngine, std::move(bd)); } mResult->mIndexBuffers.push_back(indices); @@ -822,21 +829,21 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out // the sizes match. bool needsDummyData = false; - if (mMaterials->needsDummyData(VertexAttribute::UV0) && !hasUv0) { + if (mMaterials.needsDummyData(VertexAttribute::UV0) && !hasUv0) { needsDummyData = true; hasUv0 = true; vbb.attribute(VertexAttribute::UV0, slot, VertexBuffer::AttributeType::USHORT2); vbb.normalized(VertexAttribute::UV0); } - if (mMaterials->needsDummyData(VertexAttribute::UV1) && !hasUv1) { + if (mMaterials.needsDummyData(VertexAttribute::UV1) && !hasUv1) { hasUv1 = true; needsDummyData = true; vbb.attribute(VertexAttribute::UV1, slot, VertexBuffer::AttributeType::USHORT2); vbb.normalized(VertexAttribute::UV1); } - if (mMaterials->needsDummyData(VertexAttribute::COLOR) && !hasVertexColor) { + if (mMaterials.needsDummyData(VertexAttribute::COLOR) && !hasVertexColor) { needsDummyData = true; vbb.attribute(VertexAttribute::COLOR, slot, VertexBuffer::AttributeType::UBYTE4); vbb.normalized(VertexAttribute::COLOR); @@ -859,7 +866,7 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out vbb.bufferCount(needsDummyData ? slot + 1 : slot); - VertexBuffer* vertices = vbb.build(*mEngine); + VertexBuffer* vertices = vbb.build(mEngine); outPrim->indices = indices; outPrim->vertices = vertices; @@ -874,7 +881,7 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out MorphTargetBuffer* targets = MorphTargetBuffer::Builder() .vertexCount(vertexCount) .count(targetsCount) - .build(*mEngine); + .build(mEngine); outPrim->targets = targets; mResult->mMorphTargetBuffers.push_back(targets); const cgltf_accessor* previous = nullptr; @@ -902,14 +909,14 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out if (needsDummyData) { const uint32_t requiredSize = sizeof(ubyte4) * vertexCount; if (mDummyBufferObject == nullptr || requiredSize > mDummyBufferObject->getByteCount()) { - mDummyBufferObject = BufferObject::Builder().size(requiredSize).build(*mEngine); + mDummyBufferObject = BufferObject::Builder().size(requiredSize).build(mEngine); mResult->mBufferObjects.push_back(mDummyBufferObject); uint32_t* dummyData = (uint32_t*) malloc(requiredSize); memset(dummyData, 0xff, requiredSize); VertexBuffer::BufferDescriptor bd(dummyData, requiredSize, FREE_CALLBACK); - mDummyBufferObject->setBuffer(*mEngine, std::move(bd)); + mDummyBufferObject->setBuffer(mEngine, std::move(bd)); } - vertices->setBufferObjectAt(*mEngine, slot, mDummyBufferObject); + vertices->setBufferObjectAt(mEngine, slot, mDummyBufferObject); } return true; @@ -947,12 +954,12 @@ void FAssetLoader::createLight(const cgltf_light* light, Entity entity) { builder.falloff(light->range); } - builder.build(*mEngine, entity); + builder.build(mEngine, entity); mResult->mLightEntities.push_back(entity); } void FAssetLoader::createCamera(const cgltf_camera* camera, Entity entity) { - Camera* filamentCamera = mEngine->createCamera(entity); + Camera* filamentCamera = mEngine.createCamera(entity); if (camera->type == cgltf_camera_type_perspective) { auto& projection = camera->data.perspective; @@ -1115,7 +1122,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse // This not only creates a material instance, it modifies the material key according to our // rendering constraints. For example, Filament only supports 2 sets of texture coordinates. - MaterialInstance* mi = mMaterials->createMaterialInstance(&matkey, uvmap, inputMat->name, + MaterialInstance* mi = mMaterials.createMaterialInstance(&matkey, uvmap, inputMat->name, extras.c_str()); if (!mi) { slog.e << "No material with the specified requirements exists." << io::endl; @@ -1420,7 +1427,7 @@ const Material* const* AssetLoader::getMaterials() const noexcept { return upcast(this)->getMaterials(); } -MaterialProvider* AssetLoader::getMaterialProvider() const noexcept { +MaterialProvider& AssetLoader::getMaterialProvider() noexcept { return upcast(this)->mMaterials; } diff --git a/libs/gltfio/src/FFilamentAsset.h b/libs/gltfio/src/FFilamentAsset.h index 0c78e5688a..986971a716 100644 --- a/libs/gltfio/src/FFilamentAsset.h +++ b/libs/gltfio/src/FFilamentAsset.h @@ -18,6 +18,7 @@ #define GLTFIO_FFILAMENTASSET_H #include +#include #include #include @@ -116,8 +117,10 @@ 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) { + utils::EntityManager* entityManager, NodeManager* nodeManager, + const cgltf_data* srcAsset) : + mEngine(engine), mNameManager(names), mEntityManager(entityManager), + mNodeManager(nodeManager) { mSourceAsset.reset(new SourceAsset {(cgltf_data*)srcAsset}); } @@ -255,9 +258,10 @@ struct FFilamentAsset : public FilamentAsset { void createAnimators(); - filament::Engine* mEngine; - utils::NameComponentManager* mNameManager; - utils::EntityManager* mEntityManager; + filament::Engine* const mEngine; + utils::NameComponentManager* const mNameManager; + utils::EntityManager* const mEntityManager; + NodeManager* const mNodeManager; std::vector mEntities; // sorted such that renderables come first std::vector mLightEntities; std::vector mCameraEntities; @@ -278,8 +282,6 @@ struct FFilamentAsset : public FilamentAsset { bool mResourcesLoaded = false; DependencyGraph mDependencyGraph; tsl::htrie_map> mNameToEntity; - tsl::robin_map mNodeExtras; - tsl::robin_map> mMorphTargetNames; utils::CString mAssetExtras; // Sentinels for situations where ResourceLoader needs to generate data. diff --git a/libs/gltfio/src/FNodeManager.h b/libs/gltfio/src/FNodeManager.h new file mode 100644 index 0000000000..98a402e3ac --- /dev/null +++ b/libs/gltfio/src/FNodeManager.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2022 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_FNODEMANAGER_H +#define GLTFIO_FNODEMANAGER_H + +#include "upcast.h" + +#include + +#include +#include +#include +#include + +namespace gltfio { + +class UTILS_PRIVATE FNodeManager : public NodeManager { +public: + using Instance = NodeManager::Instance; + + FNodeManager() noexcept {} + + ~FNodeManager() noexcept { + assert_invariant(mManager.getComponentCount() == 0); + } + + void terminate() noexcept; + + bool hasComponent(utils::Entity e) const noexcept { + return mManager.hasComponent(e); + } + + Instance getInstance(utils::Entity e) const noexcept { + return Instance(mManager.getInstance(e)); + } + + void create(utils::Entity entity) { + if (UTILS_UNLIKELY(mManager.hasComponent(entity))) { + destroy(entity); + } + Instance ci = mManager.addComponent(entity); + assert_invariant(ci); + } + + void destroy(utils::Entity e) noexcept { + if (Instance ci = mManager.getInstance(e); ci) { + mManager.removeComponent(e); + } + } + + void gc(utils::EntityManager& em) noexcept { + mManager.gc(em); + } + + void setMorphTargetNames(Instance ci, utils::FixedCapacityVector names) noexcept { + assert_invariant(ci.isValid()); + mManager[ci].morphTargetNames = std::move(names); + } + + const utils::FixedCapacityVector& getMorphTargetNames(Instance ci) const noexcept { + return mManager[ci].morphTargetNames; + } + + void setExtras(Instance ci, CString extras) noexcept { + mManager[ci].extras = std::move(extras); + } + + const CString& getExtras(Instance ci) const noexcept { + return mManager[ci].extras; + } + + void setSceneMembership(Instance ci, utils::bitset32 scenes) noexcept { + mManager[ci].scenes = scenes; + } + + utils::bitset32 getSceneMembership(Instance ci) const noexcept { + return mManager[ci].scenes; + } + +private: + enum { + MORPH_TARGET_NAMES, + EXTRAS_STRING, + SCENE_MEMBERSHIP, + }; + + using Base = utils::SingleInstanceComponentManager< // 24 bytes + utils::FixedCapacityVector, // 16 + CString, // 8 + utils::bitset32>; // 4 + + struct Sim : public Base { + using Base::gc; + using Base::swap; + + typename Base::SoA& getSoA() { return mData; } + + struct Proxy { + UTILS_ALWAYS_INLINE + Proxy(Base& sim, utils::EntityInstanceBase::Type i) noexcept : + morphTargetNames{ sim, i } { } + + union { + Field morphTargetNames; + Field extras; + Field scenes; + }; + }; + + UTILS_ALWAYS_INLINE Proxy operator[](Instance i) noexcept { + return { *this, i }; + } + UTILS_ALWAYS_INLINE const Proxy operator[](Instance i) const noexcept { + return { const_cast(*this), i }; + } + }; + + Sim mManager; +}; + +FILAMENT_UPCAST(NodeManager) + +} // namespace gltfio + +#endif // GLTFIO_FNODEMANAGER_H diff --git a/libs/gltfio/src/FilamentAsset.cpp b/libs/gltfio/src/FilamentAsset.cpp index 4c97aa77c1..e2bbb9dedf 100644 --- a/libs/gltfio/src/FilamentAsset.cpp +++ b/libs/gltfio/src/FilamentAsset.cpp @@ -54,6 +54,8 @@ FFilamentAsset::~FFilamentAsset() { if (mNameManager) { mNameManager->removeComponent(entity); } + // Destroy the node component. + mNodeManager->destroy(entity); // Destroy the actual entity. mEntityManager->destroy(entity); } @@ -81,8 +83,7 @@ const char* FFilamentAsset::getExtras(utils::Entity entity) const noexcept { if (entity.isNull()) { return mAssetExtras.c_str(); } - const auto iter = mNodeExtras.find(entity); - return iter == mNodeExtras.cend() ? nullptr : iter->second.c_str(); + return mNodeManager->getExtras(mNodeManager->getInstance(entity)).c_str(); } void FFilamentAsset::createAnimators() { @@ -124,17 +125,12 @@ const char* FFilamentAsset::getMorphTargetNameAt(utils::Entity entity, return nullptr; } - const auto iter = mMorphTargetNames.find(entity); - if (iter == mMorphTargetNames.end()) { + const auto& names = mNodeManager->getMorphTargetNames(mNodeManager->getInstance(entity)); + if (targetIndex >= names.size()) { return nullptr; } - const auto& morphTargetNames = iter->second; - if (targetIndex >= morphTargetNames.size()) { - return nullptr; - } - - return morphTargetNames[targetIndex].c_str(); + return names[targetIndex].c_str(); } size_t FFilamentAsset::getMorphTargetCountAt(utils::Entity entity) const noexcept { @@ -142,12 +138,8 @@ size_t FFilamentAsset::getMorphTargetCountAt(utils::Entity entity) const noexcep return 0; } - const auto iter = mMorphTargetNames.find(entity); - if (iter == mMorphTargetNames.end()) { - return 0; - } - - return iter->second.size(); + const auto& names = mNodeManager->getMorphTargetNames(mNodeManager->getInstance(entity)); + return names.size(); } size_t FFilamentAsset::getMaterialVariantCount() const noexcept { diff --git a/libs/gltfio/src/NodeManager.cpp b/libs/gltfio/src/NodeManager.cpp new file mode 100644 index 0000000000..d6a337479e --- /dev/null +++ b/libs/gltfio/src/NodeManager.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "FNodeManager.h" + +#include + +#include "upcast.h" + +using namespace utils; + +namespace gltfio { + +using Instance = NodeManager::Instance; + +void FNodeManager::terminate() noexcept { + auto& manager = mManager; + if (!manager.empty()) { +#ifndef NDEBUG + utils::slog.d << "cleaning up " << manager.getComponentCount() + << " leaked node components" << utils::io::endl; +#endif + while (!manager.empty()) { + Instance ci = manager.end() - 1; + manager.removeComponent(manager.getEntity(ci)); + } + } +} + +bool NodeManager::hasComponent(Entity e) const noexcept { + return upcast(this)->hasComponent(e); +} + +Instance NodeManager::getInstance(Entity e) const noexcept { + return upcast(this)->getInstance(e); +} + +void NodeManager::create(Entity entity) { + upcast(this)->create(entity); +} + +void NodeManager::destroy(Entity e) noexcept { + upcast(this)->destroy(e); +} + +void NodeManager::setMorphTargetNames(Instance ci, FixedCapacityVector names) noexcept { + upcast(this)->setMorphTargetNames(ci, std::move(names)); +} + +const FixedCapacityVector& NodeManager::getMorphTargetNames(Instance ci) const noexcept { + return upcast(this)->getMorphTargetNames(ci); +} + +void NodeManager::setExtras(Instance ci, CString extras) noexcept { + return upcast(this)->setExtras(ci, std::move(extras)); +} + +const CString& NodeManager::getExtras(Instance ci) const noexcept { + return upcast(this)->getExtras(ci); +} + +void NodeManager::setSceneMembership(Instance ci, bitset32 scenes) noexcept { + upcast(this)->setSceneMembership(ci, scenes); +} + +bitset32 NodeManager::getSceneMembership(Instance ci) const noexcept { + return upcast(this)->getSceneMembership(ci); +} + +} // namespace gltfio