diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a5be825..2e693e80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,8 @@ endif() include(CheckCXXSymbolExists) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake_modules/") @@ -233,6 +235,10 @@ set(SOURCES "launcher/scenery_scanner.cpp" "vr/vr_interface.cpp" + entitysystem/components/BasicComponents.h + entitysystem/ecs.cpp + entitysystem/ecs.h + entitysystem/components/RenderComponents.h ) set(DEFINITIONS) diff --git a/entitysystem/components/BasicComponents.h b/entitysystem/components/BasicComponents.h new file mode 100644 index 00000000..1555d193 --- /dev/null +++ b/entitysystem/components/BasicComponents.h @@ -0,0 +1,50 @@ +/* + * Basic components used by almost everything + */ +#ifndef EU07_BASICCOMPONENTS_H +#define EU07_BASICCOMPONENTS_H +#include "entt/entity/entity.hpp" +#include "glm/vec3.hpp" +#include "glm/gtc/quaternion.hpp" +#include +#include + +namespace ECSComponent +{ +///< summary> +/// Basic component for storing transform of entities +/// +struct Transform +{ + glm::vec3 Position{0.f}; // object position + glm::quat Rotation{1.f, 0.f, 0.f, 0.f}; // object rotation + glm::vec3 Scale{1.f}; // object scale +}; + +///< summary> +/// Basic component for naming entities +/// in future for scenery hierarchy +/// +struct Identification +{ + std::string Name; // object name - may contain slashes for editor hierarchy "directories" + std::uint64_t Id{0}; // id in scene +}; + +///< summary> +/// Basic component for parent-child relationships between entities +/// +struct Parent +{ + entt::entity value{entt::null}; +}; + +///< summary> +/// Empty component for entities that are disabled and should not be processed by systems +/// +struct Disabled +{ +}; +} // namespace ECSComponent + +#endif // EU07_BASICCOMPONENTS_H diff --git a/entitysystem/components/RenderComponents.h b/entitysystem/components/RenderComponents.h new file mode 100644 index 00000000..df18f70b --- /dev/null +++ b/entitysystem/components/RenderComponents.h @@ -0,0 +1,25 @@ +#ifndef EU07_RENDERCOMPONENTS_H +#define EU07_RENDERCOMPONENTS_H + +namespace ECSComponent +{ +/// +/// Component for entities that can be rendered. +/// +/// Currently empty +/// TODO: Add component members +/// +struct MeshRenderer +{ +}; + +/// +/// Component for entities that can cast shadows. +/// +/// Currently empty +/// TODO: Add component members +/// +struct SpotLight{}; + +} // namespace ECSComponent +#endif // EU07_RENDERCOMPONENTS_H diff --git a/entitysystem/ecs.cpp b/entitysystem/ecs.cpp new file mode 100644 index 00000000..423a5134 --- /dev/null +++ b/entitysystem/ecs.cpp @@ -0,0 +1,61 @@ +// +// Created by Hirek on 3/14/2026. +// + +#include "ecs.h" + +void ECS::ClearWorld() +{ + world_.clear(); +} + +entt::entity ECS::CreateObject() +{ + const auto e = world_.create(); + world_.emplace(e); + world_.emplace(e); + return e; +} + +void ECS::DestroyObject(entt::entity Entity) +{ + if (Entity == entt::null) // check if Entity is not null + return; + if (!world_.valid(Entity)) // check if exist + return; + world_.destroy(Entity); +} + +bool ECS::ValidObject(entt::entity entity) const +{ + return entity != entt::null && world_.valid(entity); +} + +entt::entity ECS::FindById(std::uint64_t id) +{ + auto view = world_.view(); + for (auto e : view) + { + const auto &ident = view.get(e); + if (ident.Id == id) + return e; + } + return entt::null; +} + +std::vector ECS::FindByName(std::string_view name) +{ + std::vector result; + + auto view = world_.view(); + for (auto e : view) + { + const auto &ident = view.get(e); + if (ident.Name == name) + { + result.push_back(e); + } + } + + return result; +} \ No newline at end of file diff --git a/entitysystem/ecs.h b/entitysystem/ecs.h new file mode 100644 index 00000000..1ed2f948 --- /dev/null +++ b/entitysystem/ecs.h @@ -0,0 +1,148 @@ +// +// Created by Hirek on 3/14/2026. +// + +#ifndef EU07_ECS_H +#define EU07_ECS_H +#include "components/BasicComponents.h" +#include "entt/entity/registry.hpp" +#include +#include +#include +#include +class ECS final +{ + private: + entt::registry world_; + + public: + // + // World lifecycle + // + + /// + /// Clears the world, removing all entities and components + /// + void ClearWorld(); + + // + // Objects + // + + /// + /// Creates new object with basic components (Transform, Identification) and returns its entity handle. + /// + /// Entity handle of created object + entt::entity CreateObject(); + + /// + /// Destroys object with it's all components + /// + /// Entity to be removed + void DestroyObject(entt::entity Entity); + + /// + /// Checks if object with given entity handle exists in the registry + /// + /// Entity handle to check + /// true if object exists, false otherwise + bool ValidObject(entt::entity entity) const; + + // + // Identification lookups + // + + /// + /// Finds object with given UID. Returns null entity if not found. + /// + /// UID of object + entt::entity FindById(std::uint64_t id); + + /// + /// Finds objects with given name. Returns empty vector if not found. + /// + /// Name of object + /// May return more than 1 as many objects can have the same name + std::vector FindByName(std::string_view name); + + // + // Components + // + + /// + /// Adds component of type T to entity, forwarding provided arguments to component constructor. If component already exists, it will be replaced. + /// + /// Component type + /// Entity to which component will be added + /// Arguments forwarded to component constructor + /// Reference to added component + template T &Add(entt::entity entity, Args &&...args) + { + return world_.emplace(entity, std::forward(args)...); + } + + /// + /// Adds component of type T to entity, forwarding provided arguments to component constructor. If component already exists, it will be replaced. + /// + /// Component type + /// Entity to which component will be added + /// Reference to added component + template T &Get(entt::entity entity) + { + return world_.get(entity); + } + + /// + /// Adds component of type T to entity, forwarding provided arguments to component constructor. If component already exists, it will be replaced. + /// + /// Component type + /// Entity to which component will be added + /// Reference to added component + template const T &Get(entt::entity entity) const + { + return world_.get(entity); + } + + /// + /// Tries to get component of type T from entity. Returns nullptr if component does not exist. + /// + /// Component type + /// Entity from which component will be retrieved + /// Pointer to component if exists, nullptr otherwise + template T *TryGet(entt::entity entity) + { + return world_.try_get(entity); + } + + /// + /// Tries to get component of type T from entity. Returns nullptr if component does not exist. + /// + /// Component type + /// Entity from which component will be retrieved + /// Pointer to component if exists, nullptr otherwise + template const T *TryGet(entt::entity entity) const + { + return world_.try_get(entity); + } + + /// + /// Checks if entity has component of type T. + /// + /// Component type + /// Entity to check + /// true if entity has component, false otherwise + template bool Has(entt::entity entity) const + { + return world_.all_of(entity); + } + + /// + /// Removes component of type T from entity. Does nothing if component does not exist. + /// Component type + /// Entity from which component will be removed + template void Remove(entt::entity entity) + { + world_.remove(entity); + } +}; +#endif // EU07_ECS_H