#ifndef ENGINE_INCLUDE_SCENE_H_ #define ENGINE_INCLUDE_SCENE_H_ #include #include #include #include #include #include #include "ecs_system.h" #include "event_system.h" namespace engine { class Application; class Scene { 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 */ uint32_t CreateEntity(const std::string& tag, uint32_t parent = 0, const glm::vec3& pos = glm::vec3{0.0f, 0.0f, 0.0f}); uint32_t GetEntity(const std::string& tag, uint32_t parent = 0); size_t GetComponentSignaturePosition(size_t hash); template 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>()); 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 T* GetComponent(uint32_t entity) { auto array = GetComponentArray(); return array->GetData(entity); } template T* AddComponent(uint32_t entity) { size_t hash = typeid(T).hash_code(); auto array = GetComponentArray(); array->InsertData(entity, T{}); // 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 void RegisterSystem() { size_t hash = typeid(T).hash_code(); ecs_systems_.emplace_back(hash, std::make_unique(this)); } template 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(found_system); if (casted_ptr == nullptr) { throw std::runtime_error("Failed to cast system pointer!"); } return casted_ptr; } private: Application* const app_; uint32_t next_entity_id_ = 1; // 0 is not a valid entity uint64_t framecount_ = 0; /* ecs stuff */ size_t next_signature_position_ = 0; // maps component hashes to signature positions std::unordered_map component_signature_positions_{}; // maps entity ids to their signatures std::unordered_map> signatures_{}; // maps component hashes to their arrays std::unordered_map> component_arrays_{}; // hashes and associated systems std::vector>> ecs_systems_{}; template ComponentArray* 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*>(ptr); assert(casted_ptr != nullptr); return casted_ptr; } std::unique_ptr event_system_{}; }; } // namespace engine #endif