Skip to content

Commit

Permalink
Merge pull request #111 from AGH-Code-Industry/scene
Browse files Browse the repository at this point in the history
Scenes + Hierarchies
  • Loading branch information
Chris-plusplus authored Nov 21, 2024
2 parents 45fe52a + e830113 commit 10edc14
Show file tree
Hide file tree
Showing 16 changed files with 881 additions and 3 deletions.
6 changes: 6 additions & 0 deletions include/Hier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include <hier/ChildNode.h>
#include <hier/ChildrenIterator.h>
#include <hier/HierarchyIterator.h>
#include <hier/HierarchyNode.h>
42 changes: 42 additions & 0 deletions include/Scene.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <Ecs.h>
#include <Hier.h>

namespace arch {

class Scene {
public:

/// @brief Hierarchy node class
using Node = hier::HierarchyNode;

/// @brief Default constructor
Scene() noexcept;

/// @brief Creates new entity
/// @see arch::ecs::Domain::newEntity()
ecs::Entity newEntity() noexcept;
/// @brief Kills entity
/// @see arch::ecs::Domain::kill(const ecs::Entity)
void removeEntity(const ecs::Entity entity) noexcept;

/// @brief Returns ecs::Domain of this scene
ecs::Domain& domain() noexcept;
/// @brief Returns readonly ecs::Domain of this scene
const ecs::Domain& domain() const noexcept;

/// @brief Returns root entity
ecs::Entity root() const noexcept;
/// @brief Returns root node
Node& rootNode() noexcept;
/// @brief Returns readonly root node
const Node& rootNode() const noexcept;

private:

ecs::Domain _domain;
Node* _rootNode;
};

} // namespace arch
2 changes: 1 addition & 1 deletion include/ecs/ComponentPool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ POOL_C::GetReference POOL_C::addComponent(const EntityT entity, Args&&... args)
if constexpr (Traits::flag) {
return true;
} else {
return Traits::constructAt(_componentAssure(id), std::forward<Args>(args)...);
return Traits::constructAt(_componentAssure(ETraits::Id::part(sparseEntity)), std::forward<Args>(args)...);
}
}

Expand Down
6 changes: 4 additions & 2 deletions include/ecs/Domain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,16 @@ Domain::ConstGetReference<std::remove_const_t<C>> Domain::getComponent(const Ent
template<class C>
requires(!_details::ComponentTraits<C>::flag && !std::is_const_v<C>)
std::optional<std::reference_wrapper<C>> Domain::tryGetComponent(const Entity entity) noexcept {
return _getCPool<C>().tryGet(entity);
auto cpool = _tryGetCPool<C>();
return cpool ? cpool->tryGet(entity) : std::nullopt;
}

template<class C>
requires(!_details::ComponentTraits<std::remove_const_t<C>>::flag)
std::optional<std::reference_wrapper<const std::remove_const_t<C>>> Domain::tryGetComponent(const Entity entity
) const noexcept {
return _getCPool<std::remove_const_t<C>>().tryGet(entity);
auto cpool = _tryGetCPool<std::remove_const_t<C>>();
return cpool ? cpool->tryGet(entity) : std::nullopt;
}

template<class C>
Expand Down
6 changes: 6 additions & 0 deletions include/ecs/EntityTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,9 @@ struct EntityTraits {
};

} // namespace arch::ecs::_details

namespace arch::ecs {

static inline constexpr Entity nullEntity = _details::EntityTraits::Ent::null;

}
20 changes: 20 additions & 0 deletions include/hier/ChildNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <ecs/EntityTraits.h>

namespace arch::hier {

struct HierarchyNode;

/// @brief Base class of HierarchyNode, also type of sentinel.
struct ChildNode {
/// @brief Previous sibling
ChildNode* _prev;
/// @brief Next sibling
ChildNode* _next;

/// @brief Entity value
ecs::Entity _entity = ecs::nullEntity;
};

} // namespace arch::hier
58 changes: 58 additions & 0 deletions include/hier/ChildrenIterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#pragma once

#include "ChildNode.h"
#include <ecs/Domain.h>

namespace arch::hier {

/// @brief Simple hierarchy iterator, providing access to children of an entity
/// @details Models std::bidirectional_iterator
class ChildrenIterator {
public:

/// @brief Default constructor
ChildrenIterator() noexcept = default;
/// @brief Node constructor
/// @param node - node to point to
ChildrenIterator(const ChildNode* node) noexcept;
/// @brief Copy constructor
ChildrenIterator(const ChildrenIterator&) noexcept = default;
/// @brief Move constructor
ChildrenIterator(ChildrenIterator&&) noexcept = default;

/// @brief Copy-assignment operator
ChildrenIterator& operator=(const ChildrenIterator&) noexcept = default;
/// @brief Move-assignment operator
ChildrenIterator& operator=(ChildrenIterator&&) noexcept = default;

/// @brief Equality operator
bool operator==(const ChildrenIterator&) const noexcept = default;

/// @brief Dereference operator
ecs::Entity operator*() const noexcept;

/// @brief Prefix increment operator
ChildrenIterator& operator++() noexcept;
/// @brief Postfix increment operator
ChildrenIterator operator++(int) noexcept;

/// @brief Prefix decrement operator
ChildrenIterator& operator--() noexcept;
/// @brief Postfix decrement operator
ChildrenIterator operator--(int) noexcept;

private:

const ChildNode* _current;
};

} // namespace arch::hier

template<>
struct std::iterator_traits<arch::hier::ChildrenIterator> {
using difference_type = std::ptrdiff_t;
using value_type = arch::ecs::Entity;
using pointer = void;
using reference = void;
using iterator_category = std::bidirectional_iterator_tag;
};
64 changes: 64 additions & 0 deletions include/hier/HierarchyIterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

#include <ecs/Entity.h>

namespace arch::hier {

class HierarchyNode;
class ChildNode;

namespace _details { // NOLINT

/// @brief Simple hierarchy iterator, providing recursive access to descendants of an entity
/// @details Models std::bidirectional_iterator
class HierarchyIterator {
public:

/// @brief Default constructor
HierarchyIterator() noexcept = default;
/// @brief Node constructor
/// @param node - node to point to
HierarchyIterator(const ChildNode* node) noexcept;
/// @brief Copy constructor
HierarchyIterator(const HierarchyIterator&) noexcept = default;
/// @brief Move constructor
HierarchyIterator(HierarchyIterator&&) noexcept = default;

/// @brief Copy-assignment operator
HierarchyIterator& operator=(const HierarchyIterator&) noexcept = default;
/// @brief Move-assignment operator
HierarchyIterator& operator=(HierarchyIterator&&) noexcept = default;

/// @brief Equality operator
bool operator==(const HierarchyIterator&) const noexcept = default;

/// @brief Dereference operator
ecs::Entity operator*() const noexcept;

/// @brief Prefix increment operator
HierarchyIterator& operator++() noexcept;
/// @brief Postfix increment operator
HierarchyIterator operator++(int) noexcept;

/// @brief Prefix decrement operator
HierarchyIterator& operator--() noexcept;
/// @brief Postfix decrement operator
HierarchyIterator operator--(int) noexcept;

private:

const ChildNode* _current;
};

} // namespace _details

} // namespace arch::hier

template<>
struct std::iterator_traits<arch::hier::_details::HierarchyIterator> {
using difference_type = std::ptrdiff_t;
using value_type = arch::ecs::Entity;
using pointer = void;
using reference = void;
using iterator_category = std::bidirectional_iterator_tag;
};
121 changes: 121 additions & 0 deletions include/hier/HierarchyNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#pragma once

#include <ranges>

#include "ChildNode.h"
#include "ChildrenIterator.h"
#include "HierarchyIterator.h"
#include <ecs/ComponentTraits.h>
#include <utils/OptRef.h>

namespace arch {

class Scene;

}

namespace arch::hier {

namespace _details {

class HierarchyIterator;
class ChildrenIterator;

} // namespace _details

/// @brief Main node class, implementing hierarchies
/// @details An in-place component
class HierarchyNode: public ChildNode {
using Self = HierarchyNode;

public:

/// @brief Makes HierarchyNode immovable in ecs storage, to preserve internal pointers
static constexpr bool inPlaceComponent = true;

/// @brief Entity constructor
HierarchyNode(const ecs::Entity entity) noexcept;

/// @brief Iterator type
using Iterator = ChildrenIterator;
/// @brief ReverseIterator type
using ReverseIterator = std::reverse_iterator<ChildrenIterator>;

bool setParent(Self& newParent) noexcept;
bool isChildOf(const Self& other) const noexcept;

Self& ancestor(u32 which = 1) noexcept;
const Self& ancestor(u32 which = 1) const noexcept;
i64 ancestry(const Self& other) const noexcept;

Self& parent() noexcept;
const Self& parent() const noexcept;

Self& child(u32 which = 1) noexcept;
const Self& child(u32 which = 1) const noexcept;
OptRef<Self> childOpt(u32 which = 1) noexcept;
OptRef<const Self> childOpt(u32 which = 1) const noexcept;
Self& firstChild() noexcept;
const Self& firstChild() const noexcept;
OptRef<Self> firstChildOpt() noexcept;
OptRef<const Self> firstChildOpt() const noexcept;
Self& lastChild() noexcept;
const Self& lastChild() const noexcept;
OptRef<Self> lastChildOpt() noexcept;
OptRef<const Self> lastChildOpt() const noexcept;
u32 childrenCount() const noexcept;

ecs::Entity entity() const noexcept;
u32 depth() const noexcept;

/// @brief Returns iterator to first child
Iterator begin() const noexcept;
/// @brief Returns iterator to first child
Iterator cbegin() const noexcept;
/// @brief Returns iterator to sentinel
Iterator end() const noexcept;
/// @brief Returns iterator to sentinel
Iterator cend() const noexcept;
/// @brief Returns reverse iterator to last child
ReverseIterator rbegin() const noexcept;
/// @brief Returns reverse iterator to last child
ReverseIterator crbegin() const noexcept;
/// @brief Returns reverse iterator to sentinel
ReverseIterator rend() const noexcept;
/// @brief Returns reverse iterator to sentinel
ReverseIterator crend() const noexcept;

/// @brief Return view with recursive iterators
auto recursiveIterable() noexcept
-> decltype(std::ranges::subrange(_details::HierarchyIterator(nullptr), _details::HierarchyIterator(nullptr)));
/// @brief Return readonly view with recursive iterators
auto recursiveIterable() const noexcept
-> decltype(std::ranges::subrange(_details::HierarchyIterator(nullptr), _details::HierarchyIterator(nullptr)));

private:

friend class ::arch::Scene;
friend class _details::ChildrenIterator;
friend class _details::HierarchyIterator;

void _unparent() noexcept;
void _setParentUnchecked(Self& newParent) noexcept;

using ChildNode::_entity;
using ChildNode::_next;
using ChildNode::_prev;
/// @brief Sentinel node, before first and after the last
ChildNode _sentinel{ &_sentinel, &_sentinel, ecs::nullEntity };
/// @brief First child node
ChildNode* _first = nullptr;
/// @brief Last child node
ChildNode* _last = nullptr;
/// @brief Children count
u32 _count = 0;
/// @brief Hierarchy depth (distance to root)
u32 _depth = 0;
/// @brief Parent node
Self* _parent = nullptr;
};

} // namespace arch::hier
44 changes: 44 additions & 0 deletions include/utils/OptRef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <optional>

namespace arch {

/// @brief std::optional equivalent for references
template<class T>
class OptRef {
public:

OptRef() noexcept = default;
OptRef(std::nullopt_t) noexcept;
OptRef(const OptRef&) noexcept = default;
OptRef(OptRef&&) noexcept = default;
OptRef(T& ref) noexcept;

T& operator*() noexcept;
const T& operator*() const noexcept requires(!std::is_const_v<T>);
operator T&() noexcept;
operator const T&() const noexcept requires(!std::is_const_v<T>);
T& get() noexcept;
const T& get() const noexcept requires(!std::is_const_v<T>);
T* operator->() noexcept;
const T* operator->() const noexcept requires(!std::is_const_v<T>);

operator bool() const noexcept;
bool hasValue() const noexcept;

T& tryGet();
const T& tryGet() const requires(!std::is_const_v<T>);
T& getOr(T& other) noexcept;
const T& getOr(const T& other) const noexcept requires(!std::is_const_v<T>);

void swap(OptRef& other) noexcept;

private:

T* _ptr = nullptr;
};

} // namespace arch

#include "OptRef.hpp"
Loading

0 comments on commit 10edc14

Please sign in to comment.