mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 17:56:17 +03:00
244 lines
6.4 KiB
C++
244 lines
6.4 KiB
C++
#pragma once
|
|
|
|
#include "component.h"
|
|
#include "scene_node.h"
|
|
|
|
namespace engine
|
|
{
|
|
// Simple scene graph implement.
|
|
class Scene : public AssetInterface
|
|
{
|
|
REGISTER_BODY_DECLARE(AssetInterface);
|
|
|
|
friend SceneNode;
|
|
|
|
public:
|
|
Scene() = default;
|
|
explicit Scene(const AssetSaveInfo& saveInfo);
|
|
|
|
virtual ~Scene() = default;
|
|
static const Scene* getCDO();
|
|
|
|
public:
|
|
// ~AssetInterface.
|
|
virtual EAssetType getType() const override { return EAssetType::darkscene; }
|
|
virtual void onPostAssetConstruct() override;
|
|
virtual VulkanImage* getSnapshotImage() override;
|
|
static const AssetReflectionInfo& uiGetAssetReflectionInfo();
|
|
|
|
static bool assetIsScene(const char* ext);
|
|
|
|
protected:
|
|
virtual bool saveImpl() override;
|
|
virtual void unloadImpl() override;
|
|
// ~AssetInterface.
|
|
|
|
public:
|
|
// Tick every frame.
|
|
void tick(const RuntimeModuleTickData& tickData);
|
|
|
|
void onGameBegin();
|
|
void onGamePause();
|
|
void onGameContinue();
|
|
void onGameStop();
|
|
|
|
// Get root node.
|
|
std::shared_ptr<SceneNode> getRootNode() { return m_root; }
|
|
|
|
public:
|
|
// ~Scene node operator.
|
|
|
|
// Root node id.
|
|
static const size_t kRootId = 0;
|
|
|
|
// How many node exist.
|
|
size_t getNodeCount() const { return m_sceneNodes.size(); }
|
|
|
|
// Delete one node, also include it's child nodes.
|
|
void deleteNode(std::shared_ptr<SceneNode> node);
|
|
|
|
// Create node.
|
|
std::shared_ptr<SceneNode> createNode(const std::string& name, std::shared_ptr<SceneNode> parent = nullptr);
|
|
|
|
// Add child for root node.
|
|
void addChild(std::shared_ptr<SceneNode> child);
|
|
|
|
// Set node's parent relationship.
|
|
bool setParent(std::shared_ptr<SceneNode> parent, std::shared_ptr<SceneNode> son);
|
|
|
|
// post-order loop.
|
|
void loopNodeDownToTop(const std::function<void(std::shared_ptr<SceneNode>)>& func, std::shared_ptr<SceneNode> node);
|
|
|
|
// pre-order loop.
|
|
void loopNodeTopToDown(const std::function<void(std::shared_ptr<SceneNode>)>& func, std::shared_ptr<SceneNode> node);
|
|
|
|
// loop the whole graph to find first same name scene node, this is a slow function.
|
|
std::shared_ptr<SceneNode> findNode(const std::string& name) const;
|
|
|
|
// find all same name nodes, this is a slow function.
|
|
std::vector<std::shared_ptr<SceneNode>> findNodes(const std::string& name) const;
|
|
|
|
// update whole graph's transform.
|
|
void flushSceneNodeTransform();
|
|
|
|
// Node is exist or not.
|
|
bool existNode(size_t id) const;
|
|
|
|
// Get node with check.
|
|
std::shared_ptr<SceneNode> getNode(size_t id) const;
|
|
|
|
protected:
|
|
// require guid of scene node in this scene.
|
|
size_t requireSceneNodeId();
|
|
|
|
// Create scene node.
|
|
std::shared_ptr<SceneNode> createNode(size_t id, const std::string& name);
|
|
|
|
public:
|
|
// ~Component operator
|
|
|
|
// Get components.
|
|
inline const std::vector<std::weak_ptr<Component>>& getComponents(const std::string& id) const
|
|
{
|
|
return m_components.at(id);
|
|
}
|
|
|
|
template <typename T>
|
|
inline const std::vector<std::weak_ptr<Component>>& getComponents() const
|
|
{
|
|
std::string type = rttr::type::get<T>().get_name().data();
|
|
return getComponents(type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline std::vector<std::weak_ptr<Component>>& getComponents()
|
|
{
|
|
std::string type = rttr::type::get<T>().get_name().data();
|
|
return m_components.at(type);
|
|
}
|
|
|
|
// Check exist component or not.
|
|
inline bool hasComponent(const std::string& id) const
|
|
{
|
|
auto component = m_components.find(id);
|
|
return (component != m_components.end() && !component->second.empty());
|
|
}
|
|
|
|
// Loop scene's components.
|
|
template<typename T> void loopComponents(std::function<bool(std::shared_ptr<T>)>&& func);
|
|
|
|
// Add component for node.
|
|
template<typename T> bool addComponent(std::shared_ptr<T> component, std::shared_ptr<SceneNode> node);
|
|
bool addComponent(const std::string& type, std::shared_ptr<Component> component, std::shared_ptr<SceneNode> node);
|
|
|
|
template <typename T>
|
|
bool hasComponent() const
|
|
{
|
|
static_assert(std::is_base_of_v<Component, T>, "T must derive from Component.");
|
|
std::string type = rttr::type::get<T>().get_name().data();
|
|
|
|
return hasComponent(type);
|
|
}
|
|
|
|
template<typename T>
|
|
bool removeComponent(std::shared_ptr<SceneNode> node)
|
|
{
|
|
static_assert(std::is_base_of_v<Component, T>, "T must derive from Component.");
|
|
std::string type = rttr::type::get<T>().get_name().data();
|
|
|
|
return removeComponent(type);
|
|
}
|
|
|
|
bool removeComponent(std::shared_ptr<SceneNode> node, const std::string& type);
|
|
|
|
private:
|
|
// Cache scene node index. use for runtime guid.
|
|
size_t m_currentId = kRootId;
|
|
|
|
// Owner of the root node.
|
|
std::shared_ptr<SceneNode> m_root = nullptr;
|
|
|
|
// Cache scene components, no include transform.
|
|
std::unordered_map<std::string, std::vector<std::weak_ptr<Component>>> m_components;
|
|
|
|
// Cache scene node maps.
|
|
mutable std::unordered_map<size_t, std::weak_ptr<SceneNode>> m_sceneNodes;
|
|
};
|
|
|
|
|
|
template<typename T>
|
|
inline void Scene::loopComponents(std::function<bool(std::shared_ptr<T>)>&& func)
|
|
{
|
|
static_assert(std::is_base_of_v<Component, T>, "T must derive from Component.");
|
|
if (!hasComponent<T>())
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto& compWeakPtrs = getComponents<T>();
|
|
|
|
// Loop all component.
|
|
size_t unvalidComponentNum = 0U;
|
|
for (auto& p : compWeakPtrs)
|
|
{
|
|
if (auto pShared = p.lock())
|
|
{
|
|
// Some function require pre-return after find first component.
|
|
if (func(std::static_pointer_cast<T>(pShared)))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unvalidComponentNum++;
|
|
}
|
|
}
|
|
|
|
// Try shrink scene components if need.
|
|
static const size_t kShrinkComponentNumMin = 10U;
|
|
if (unvalidComponentNum > kShrinkComponentNumMin)
|
|
{
|
|
compWeakPtrs.erase(std::remove_if(compWeakPtrs.begin(), compWeakPtrs.end(),
|
|
[](const std::weak_ptr<Component>& p)
|
|
{
|
|
return !p.lock();
|
|
}),
|
|
compWeakPtrs.end());
|
|
}
|
|
}
|
|
|
|
inline bool Scene::addComponent(
|
|
const std::string& type,
|
|
std::shared_ptr<Component> component,
|
|
std::shared_ptr<SceneNode> node)
|
|
{
|
|
if (component && !node->hasComponent(type))
|
|
{
|
|
node->setComponent(type, component);
|
|
m_components[type].push_back(component);
|
|
markDirty();
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
inline bool Scene::addComponent(std::shared_ptr<T> component, std::shared_ptr<SceneNode> node)
|
|
{
|
|
static_assert(std::is_base_of_v<Component, T>, "T must derive from Component.");
|
|
|
|
if (component && !node->hasComponent<T>())
|
|
{
|
|
node->setComponent(component);
|
|
std::string type = rttr::type::get<T>().get_name().data();
|
|
|
|
m_components[type].push_back(component);
|
|
markDirty();
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
} |