Note that this API is on the loader rather than the asset. This is because the loader knows how to create Filament entities by traversing a cgltf node hierarchy. Animation on dynamically added instances is not yet supported. We did not add destroyInstance() because gltfio favors flat arrays for long term storage of entity lists and instance lists, which would be slow to shift. We also wish to discourage create/destroy churn since it is more efficient to pre-allocate instances and selectively add them into the scene. Fixes #3137.
123 lines
4.4 KiB
C++
123 lines
4.4 KiB
C++
/*
|
|
* Copyright (C) 2020 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_DEPENDENCY_GRAPH_H
|
|
#define GLTFIO_DEPENDENCY_GRAPH_H
|
|
|
|
#include <utils/Entity.h>
|
|
|
|
#include <tsl/robin_map.h>
|
|
#include <tsl/robin_set.h>
|
|
|
|
#include <queue>
|
|
#include <string>
|
|
|
|
namespace filament {
|
|
class MaterialInstance;
|
|
class Texture;
|
|
}
|
|
|
|
namespace gltfio {
|
|
|
|
/**
|
|
* Internal graph that enables FilamentAsset to discover "ready-to-render" entities by tracking
|
|
* the loading status of Texture objects that each entity depends on.
|
|
*
|
|
* Renderables connect to a set of material instances, which in turn connect to a set of parameter
|
|
* names, which in turn connect to a set of texture objects. These relationships are not easily
|
|
* inspectable using the Filament API or ECS.
|
|
*
|
|
* One graph corresponds to a single glTF asset. The graph only contains weak references, it does
|
|
* not have ownership over any Filament objects. Here's an example:
|
|
*
|
|
* Entity Entity Entity Entity
|
|
* | / \ | /
|
|
* | / \ | /
|
|
* Material Material Material
|
|
* / | \ |
|
|
* / | \ |
|
|
* Param Param Param Param
|
|
* \ / | |
|
|
* \ / | |
|
|
* Texture Texture Texture
|
|
*
|
|
* Note that the left-most entity in the above graph has no textures, so it becomes ready as soon as
|
|
* finalize is called.
|
|
*/
|
|
class DependencyGraph {
|
|
public:
|
|
using Material = filament::MaterialInstance;
|
|
using Entity = utils::Entity;
|
|
|
|
// Pops up to "count" ready-to-render entities off the queue.
|
|
// If "result" is non-null, returns the number of written items.
|
|
// If "result" is null, returns the number of available entities.
|
|
size_t popRenderables(Entity* result, size_t count) noexcept;
|
|
|
|
// These are called during the initial asset loader phase.
|
|
void addEdge(Entity entity, Material* material);
|
|
void addEdge(Material* material, const char* parameter);
|
|
|
|
// This is called at the end of the initial asset loading phase.
|
|
// Makes a guarantee that no new material nodes or parameter nodes will be added to the graph.
|
|
void finalize();
|
|
|
|
// This can be called after finalization to allow for dynamic addition of entities.
|
|
// It is slower than finalize() because it checks the readiness of existing materials.
|
|
void refinalize();
|
|
|
|
// These are called after textures have created and decoded.
|
|
void addEdge(filament::Texture* texture, Material* material, const char* parameter);
|
|
void markAsReady(filament::Texture* texture);
|
|
|
|
private:
|
|
struct TextureNode {
|
|
filament::Texture* texture;
|
|
bool ready;
|
|
};
|
|
|
|
struct MaterialNode {
|
|
tsl::robin_map<std::string, TextureNode*> params;
|
|
};
|
|
|
|
struct EntityNode {
|
|
tsl::robin_set<Material*> materials;
|
|
size_t numReadyMaterials = 0;
|
|
};
|
|
|
|
void checkReadiness(Material* material);
|
|
void markAsReady(Material* material);
|
|
TextureNode* getStatus(filament::Texture* texture);
|
|
|
|
// The following maps contain the directed edges in the graph.
|
|
tsl::robin_map<Entity, EntityNode> mEntityToMaterial;
|
|
tsl::robin_map<Material*, tsl::robin_set<Entity>> mMaterialToEntity;
|
|
tsl::robin_map<Material*, MaterialNode> mMaterialToTexture;
|
|
tsl::robin_map<filament::Texture*, tsl::robin_set<Material*>> mTextureToMaterial;
|
|
|
|
// Each texture (and its readiness flag) can be referenced from multiple nodes, so we own
|
|
// a collection of wrapper objects in the following map. This uses std::unique_ptr to allow
|
|
// nodes to refer to a texture wrapper using a stable weak pointer.
|
|
tsl::robin_map<filament::Texture*, std::unique_ptr<TextureNode>> mTextureNodes;
|
|
|
|
std::queue<Entity> mReadyRenderables;
|
|
bool mFinalized = false;
|
|
};
|
|
|
|
} // namespace gltfio
|
|
|
|
#endif // GLTFIO_DEPENDENCY_GRAPH_H
|