Files
cup_edit/ios/src/FFilamentAsset.h
2022-02-06 13:28:28 +08:00

290 lines
9.4 KiB
C++

/*
* 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 <gltfio/FilamentAsset.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/Texture.h>
#include <filament/TextureSampler.h>
#include <filament/TransformManager.h>
#include <filament/VertexBuffer.h>
#include <gltfio/MaterialProvider.h>
#include <math/mat4.h>
#include <utils/FixedCapacityVector.h>
#include <utils/CString.h>
#include <utils/Entity.h>
#include <cgltf.h>
#include "upcast.h"
#include "DependencyGraph.h"
#include "DracoCache.h"
#include "FFilamentInstance.h"
#include <tsl/robin_map.h>
#include <tsl/htrie_map.h>
#include <vector>
#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<const cgltf_mesh*, std::vector<Primitive>>;
// 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<intptr_t, MaterialEntry>;
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<utils::Entity> mEntities;
std::vector<utils::Entity> mLightEntities;
std::vector<utils::Entity> mCameraEntities;
std::vector<filament::MaterialInstance*> mMaterialInstances;
std::vector<filament::VertexBuffer*> mVertexBuffers;
std::vector<filament::BufferObject*> mBufferObjects;
std::vector<filament::IndexBuffer*> mIndexBuffers;
std::vector<filament::Texture*> mTextures;
filament::Aabb mBoundingBox;
utils::Entity mRoot;
std::vector<FFilamentInstance*> mInstances;
SkinVector mSkins; // unused for instanced assets
Animator* mAnimator = nullptr;
MorphHelper* mMorpher = nullptr;
Wireframe* mWireframe = nullptr;
bool mResourcesLoaded = false;
DependencyGraph mDependencyGraph;
tsl::htrie_map<char, std::vector<utils::Entity>> mNameToEntity;
tsl::robin_map<utils::Entity, utils::CString> 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<uint8_t> 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<SourceAsset>;
SourceHandle mSourceAsset;
// Transient source data that can freed via releaseSourceData:
std::vector<BufferSlot> mBufferSlots;
std::vector<TextureSlot> mTextureSlots;
std::vector<const char*> mResourceUris;
NodeMap mNodeMap; // unused for instanced assets
std::vector<std::pair<const cgltf_primitive*, filament::VertexBuffer*> > mPrimitives;
MatInstanceCache mMatInstanceCache;
MeshCache mMeshCache;
};
FILAMENT_UPCAST(FilamentAsset)
} // namespace gltfio
#endif // GLTFIO_FFILAMENTASSET_H