engine/include/scene.h

175 lines
5.6 KiB
C
Raw Normal View History

2024-03-31 10:11:22 +00:00
#pragma once
2022-11-30 00:46:03 +00:00
2023-04-29 14:22:25 +00:00
#include <cassert>
#include <cstdint>
#include <map>
2023-05-24 17:52:06 +00:00
#include <stdexcept>
2023-04-29 14:22:25 +00:00
#include <typeinfo>
2022-12-15 10:07:22 +00:00
2023-07-04 16:08:28 +00:00
#include <glm/vec3.hpp>
2023-10-01 10:38:27 +00:00
#include <glm/ext/quaternion_float.hpp>
2023-07-04 16:08:28 +00:00
2023-09-19 07:40:45 +00:00
#include "ecs.h"
2023-05-01 13:13:35 +00:00
#include "event_system.h"
2024-03-14 04:25:02 +00:00
#include "components/transform.h"
2023-01-02 17:24:20 +00:00
2022-11-30 00:46:03 +00:00
namespace engine {
2023-04-29 14:22:25 +00:00
class Application;
class Scene {
2024-03-14 04:25:02 +00:00
public:
Scene(Application* app);
Scene(const Scene&) = delete;
Scene& operator=(const Scene&) = delete;
~Scene();
void Update(float ts);
Application* app() { return app_; }
EventSystem* event_system() { return event_system_.get(); }
/* ecs stuff */
Entity CreateEntity(const std::string& tag, Entity parent = 0, const glm::vec3& pos = glm::vec3{0.0f, 0.0f, 0.0f},
const glm::quat& rot = glm::quat{1.0f, 0.0f, 0.0f, 0.0f}, const glm::vec3& scl = glm::vec3{1.0f, 1.0f, 1.0f});
Entity GetEntity(const std::string& tag, Entity parent = 0);
size_t GetComponentSignaturePosition(size_t hash);
template <typename T>
void RegisterComponent()
{
size_t hash = typeid(T).hash_code();
assert(component_arrays_.contains(hash) == false && "Registering component type more than once.");
component_arrays_.emplace(hash, std::make_unique<ComponentArray<T>>());
size_t signature_position = next_signature_position_;
++next_signature_position_;
assert(signature_position < kMaxComponents && "Registering too many components!");
assert(component_signature_positions_.contains(hash) == false);
component_signature_positions_.emplace(hash, signature_position);
}
template <typename T>
T* GetComponent(Entity entity)
{
// check if component exists on entity:
size_t hash = typeid(T).hash_code();
size_t signature_position = component_signature_positions_.at(hash);
const auto& entity_signature = signatures_.at(entity);
if (entity_signature.test(signature_position) == false) {
return nullptr;
}
auto array = GetComponentArray<T>();
return array->GetData(entity);
}
// because GetComponent<Transformzzzzzz takes too long
2024-03-31 10:11:22 +00:00
TransformComponent* GetTransform(Entity entity) { return GetComponent<TransformComponent>(entity); }
2023-04-29 14:22:25 +00:00
2024-03-31 10:11:22 +00:00
glm::vec3& GetPosition(Entity entity) { return GetTransform(entity)->position; }
2024-03-14 04:25:02 +00:00
2024-03-31 10:11:22 +00:00
glm::quat& GetRotation(Entity entity) { return GetTransform(entity)->rotation; }
2024-03-14 04:25:02 +00:00
2024-03-31 10:11:22 +00:00
glm::vec3& GetScale(Entity entity) { return GetTransform(entity)->scale; }
2024-03-14 04:25:02 +00:00
template <typename T>
T* AddComponent(Entity entity, const T& comp = T{})
{
size_t hash = typeid(T).hash_code();
auto array = GetComponentArray<T>();
array->InsertData(entity, comp); // errors if entity already exists in array
// set the component bit for this entity
size_t signature_position = component_signature_positions_.at(hash);
auto& signature_ref = signatures_.at(entity);
signature_ref.set(signature_position);
for (auto& [system_hash, system] : ecs_systems_) {
if (system->entities_.contains(entity)) continue;
if ((system->signature_ & signature_ref) == system->signature_) {
system->entities_.insert(entity);
system->OnComponentInsert(entity);
}
}
return array->GetData(entity);
}
template <typename T>
void RegisterSystem()
{
size_t hash = typeid(T).hash_code();
ecs_systems_.emplace_back(hash, std::make_unique<T>(this));
}
2024-04-29 17:51:52 +00:00
/* Pushes old systems starting at 'index' along by 1 */
template <typename T>
void RegisterSystemAtIndex(size_t index)
{
size_t hash = typeid(T).hash_code();
ecs_systems_.emplace(ecs_systems_.begin() + index, hash, std::make_unique<T>(this));
}
2024-03-14 04:25:02 +00:00
template <typename T>
T* GetSystem()
{
size_t hash = typeid(T).hash_code();
System* found_system = nullptr;
for (auto& [system_hash, system] : ecs_systems_) {
if (hash == system_hash) found_system = system.get();
}
if (found_system == nullptr) {
throw std::runtime_error("Unable to find system");
}
T* casted_ptr = dynamic_cast<T*>(found_system);
if (casted_ptr == nullptr) {
throw std::runtime_error("Failed to cast system pointer!");
}
return casted_ptr;
}
private:
Application* const app_;
public:
Entity next_entity_id_ = 1; // 0 is not a valid entity
private:
uint64_t framecount_ = 0;
/* ecs stuff */
size_t next_signature_position_ = 0;
// maps component hashes to signature positions
std::unordered_map<size_t, size_t> component_signature_positions_{};
// maps entity ids to their signatures
std::unordered_map<Entity, std::bitset<kMaxComponents>> signatures_{};
// maps component hashes to their arrays
std::unordered_map<size_t, std::unique_ptr<IComponentArray>> component_arrays_{};
// hashes and associated systems
std::vector<std::pair<size_t, std::unique_ptr<System>>> ecs_systems_{};
template <typename T>
ComponentArray<T>* GetComponentArray()
{
size_t hash = typeid(T).hash_code();
auto it = component_arrays_.find(hash);
if (it == component_arrays_.end()) {
throw std::runtime_error("Cannot find component array.");
}
auto ptr = it->second.get();
auto casted_ptr = dynamic_cast<ComponentArray<T>*>(ptr);
assert(casted_ptr != nullptr);
return casted_ptr;
2023-04-29 14:22:25 +00:00
}
2024-03-14 04:25:02 +00:00
std::unique_ptr<EventSystem> event_system_{};
2023-04-29 14:22:25 +00:00
};
2024-03-31 10:11:22 +00:00
} // namespace engine