Compare commits
6 Commits
curle/asse
...
curle/ecs
Author | SHA1 | Date | |
---|---|---|---|
cb545da50f | |||
4ab31de209 | |||
5c4137506b | |||
cc5400587c | |||
33b27fc9a1 | |||
387bc84985 |
|
@ -7,12 +7,14 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
|||
|
||||
FILE(GLOB_RECURSE SOURCES
|
||||
core/src/*.cpp
|
||||
shadow-entity/src/*.cpp
|
||||
shadow-renderer/src/*.cpp
|
||||
shadow-reflection/src/*.cpp
|
||||
shadow-utility/src/*.cpp
|
||||
)
|
||||
FILE(GLOB_RECURSE HEADERS
|
||||
core/inc/*.h
|
||||
shadow-entity/inc/*.h
|
||||
shadow-renderer/inc/*.h
|
||||
shadow-reflection/inc/*.h
|
||||
shadow-utility/inc/*.h
|
||||
|
@ -24,6 +26,7 @@ target_include_directories(shadow-engine
|
|||
PRIVATE ${SDL2_INCLUDE_DIRS}
|
||||
PUBLIC
|
||||
core/inc
|
||||
shadow-entity/inc
|
||||
shadow-renderer/inc
|
||||
shadow-reflection/inc
|
||||
shadow-utility/inc
|
||||
|
|
64
projs/shadow/shadow-engine/core/inc/id/UUID.h
Normal file
64
projs/shadow/shadow-engine/core/inc/id/UUID.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
// ShadowEntity temporary namespace
|
||||
namespace SE {
|
||||
|
||||
/**
|
||||
* Universally Unique ID.
|
||||
* 128 Bits.
|
||||
*
|
||||
* Unique per runtime only - the suitability for serialization is undetermined.
|
||||
*/
|
||||
|
||||
class UUID {
|
||||
|
||||
/**
|
||||
* Data storage; 128 bits.
|
||||
* 2 x 64 bit
|
||||
* 4 x 32 bit
|
||||
* 16 x 8 bit
|
||||
*/
|
||||
|
||||
union Data {
|
||||
uint64_t u64[2];
|
||||
uint32_t u32[4];
|
||||
uint8_t u8[16];
|
||||
};
|
||||
|
||||
public:
|
||||
// Create a new, unused, UUID.
|
||||
static UUID Generate();
|
||||
// Check whether the UUID is correctly formed.
|
||||
static bool IsValidStr(char const* str);
|
||||
|
||||
// Create an empty UUID.
|
||||
inline UUID() { std::memset(&data.u8, 0, 16); }
|
||||
// Create a UUID based on the given values.
|
||||
inline UUID(uint64_t i0, uint64_t i1) { data.u64[0] = i0; data.u64[1] = i1; }
|
||||
inline UUID(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3) { data.u32[0] = i0; data.u32[1] = i1; data.u32[2] = i2; data.u32[3] = i3; }
|
||||
inline explicit UUID(std::string const& str) : UUID(str.c_str()) {}
|
||||
// Create a UUID from the given format.
|
||||
explicit UUID(char const* str);
|
||||
|
||||
// Check whether the UUID is nonzero.
|
||||
inline bool IsValid() const { return data.u64[0] != 0 && data.u64[1] != 0; }
|
||||
// Set the UUID to zero.
|
||||
inline void Clear() { std::memset(&data.u8, 0, 16); }
|
||||
|
||||
// Get a section of the UUID's data as the given bit width.
|
||||
inline uint8_t GetU8(size_t idx) const { return data.u8[idx]; }
|
||||
inline uint32_t GetU32(size_t idx) const { return data.u32[idx]; }
|
||||
inline uint64_t GetU64(size_t idx) const { return data.u64[idx]; }
|
||||
|
||||
// Check whether this and a given UUID are in/equal.
|
||||
__inline bool operator==(UUID const& other) const { return data.u64[0] == other.data.u64[0] && data.u64[1] == other.data.u64[1]; }
|
||||
__inline bool operator!=(UUID const& other) const { return !(*this == other); }
|
||||
|
||||
private:
|
||||
|
||||
Data data {};
|
||||
};
|
||||
}
|
23
projs/shadow/shadow-engine/core/inc/math/bounds.h
Normal file
23
projs/shadow/shadow-engine/core/inc/math/bounds.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
#include <math/transform.h>
|
||||
|
||||
/**
|
||||
* A temporary header that contains some of the bounds implementations.
|
||||
*/
|
||||
|
||||
namespace Math {
|
||||
|
||||
/**
|
||||
* A bounding box that can be rotated freely.
|
||||
* Can be used as the collision box for an entity.
|
||||
*/
|
||||
struct OrientedBB {
|
||||
|
||||
OrientedBB() = default;
|
||||
|
||||
|
||||
Quaternion orientation;
|
||||
Vector center;
|
||||
Vector extent;
|
||||
};
|
||||
}
|
47
projs/shadow/shadow-engine/core/inc/math/transform.h
Normal file
47
projs/shadow/shadow-engine/core/inc/math/transform.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* A temporary header that contains some of the core transform logic.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
namespace Math {
|
||||
|
||||
struct alignas(16) Vector {
|
||||
Vector() = default;
|
||||
|
||||
union {
|
||||
struct { float x, y, z, w; };
|
||||
__m128 data;
|
||||
};
|
||||
};
|
||||
|
||||
struct alignas(16) Quaternion {
|
||||
|
||||
inline Quaternion() = default;
|
||||
|
||||
union {
|
||||
struct { float x, y, z, w; };
|
||||
__m128 data;
|
||||
};
|
||||
};
|
||||
|
||||
class Transform {
|
||||
public:
|
||||
Transform() = default;
|
||||
|
||||
const Vector& GetTranslation() const { return translation; }
|
||||
const Quaternion& GetRotation() const { return rotation; }
|
||||
|
||||
inline Vector GetRightVector() const;
|
||||
inline Vector GetForwardVector() const;
|
||||
inline Vector GetUpVector() const;
|
||||
|
||||
private:
|
||||
Quaternion rotation;
|
||||
Vector translation;
|
||||
Vector scale;
|
||||
};
|
||||
}
|
56
projs/shadow/shadow-engine/core/src/id/UUID.cpp
Normal file
56
projs/shadow/shadow-engine/core/src/id/UUID.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include <id/UUID.h>
|
||||
|
||||
namespace SE {
|
||||
static_assert(sizeof(UUID) == 16, "UUID has incorrect size");
|
||||
|
||||
/**
|
||||
* Verify that a string has the correct format;
|
||||
* XXXXXXXX-XXXX-XXX-XXXXX-XXXXXXXXXXXX
|
||||
*
|
||||
* The length must be 36.
|
||||
* There must be dashes at index 8, 13, 18 and 23.
|
||||
* @param str the input string
|
||||
* @return whether the UUID string is correctly formed
|
||||
*/
|
||||
bool UUID::IsValidStr(const char *str) {
|
||||
size_t const len = strlen(str);
|
||||
if (len != 36) return false;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
char c = str[i];
|
||||
if (c == '-') {
|
||||
if (i != 8 && i != 13 && i != 18 && i != 23) return false;
|
||||
} else if (! std::isxdigit(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
UUID::UUID(char const* str ) {
|
||||
// A single byte is two hex characters.
|
||||
// Store them here so that we can use them later.
|
||||
char c0 = '\0', c1;
|
||||
|
||||
size_t const len = strlen( str );
|
||||
uint32_t byteIdx = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++ ) {
|
||||
char const c = str[i];
|
||||
if ( c == '-' )
|
||||
continue;
|
||||
|
||||
// Scan for pairs of characters.
|
||||
// Only assign a byte if two have been parsed.
|
||||
if (c0 == '\0') {
|
||||
c0 = c;
|
||||
} else {
|
||||
c1 = c;
|
||||
data.u8[byteIdx++] = std::stoi(std::string(c0, c1));
|
||||
// Reset the first char so that we can return to scanning a pair.
|
||||
c0 = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include "id/ID.h"
|
||||
|
||||
namespace SE {
|
||||
|
||||
/**
|
||||
* A Component is a part of an Entity that stores and manages data.
|
||||
* This data is held separately from the Entity that requests it.
|
||||
*
|
||||
* Components can be Spatial (ie. Position, Rotation).
|
||||
* Components can also be Visual (ie. Mesh, Collider).
|
||||
* Components are part of the larger Entity-Component-System architecture.
|
||||
*
|
||||
* Systems operate over these Components.
|
||||
* Entities may have their own Systems, and each Scene has its own set of global Systems.
|
||||
* Components may be registered to only one of these.
|
||||
*
|
||||
* EntityComponent classes are not singleton; new EntityComponent(..) is valid.
|
||||
*
|
||||
*/
|
||||
class EntityComponent {
|
||||
public:
|
||||
|
||||
/**
|
||||
* The Component's possible statuses.
|
||||
*/
|
||||
enum class Status: uint8_t {
|
||||
Unloaded, // The component is not yet loaded.
|
||||
Loading, // The component is being loaded.
|
||||
Loaded, // The component is finished loading, but is not yet populated with data.
|
||||
Failed, // The component encountered an error while loading.
|
||||
Initialized // The component is finished loading, and is populated with data.
|
||||
};
|
||||
|
||||
virtual ~EntityComponent();
|
||||
|
||||
// Get the ComponentID.
|
||||
inline ComponentID const& GetID() const { return id; }
|
||||
// Get the Name of this Component; guaranteed to be unique in a given entity.
|
||||
inline std::string& GetName() { return name; }
|
||||
// Get the Entity that owns this Component.
|
||||
inline EntityID const& GetParent() const { return owner; }
|
||||
|
||||
inline Status GetStatus() const { return status; }
|
||||
// Check Status
|
||||
inline bool IsLoaded() const { return status == Status::Loaded; }
|
||||
inline bool IsLoading() const { return status == Status::Loading; }
|
||||
inline bool IsUnloaded() const { return status == Status::Unloaded; }
|
||||
inline bool Failed() const { return status == Status::Failed; }
|
||||
inline bool Initialized() const { return status == Status::Initialized; }
|
||||
|
||||
// Whether one instance of this Component is allowed per Entity
|
||||
virtual bool IsSingleton() const { return false; }
|
||||
|
||||
protected:
|
||||
|
||||
EntityComponent() = default;
|
||||
EntityComponent(std::string& name) : name(name) {}
|
||||
|
||||
// Load Component data. May perform background ops.
|
||||
virtual void Load() = 0;
|
||||
// Unload Component data. Must be blocking.
|
||||
virtual void Unload() = 0;
|
||||
|
||||
// Check that everything went properly.
|
||||
virtual void UpdateStatus() = 0;
|
||||
|
||||
// Update the status to Initialized. Must only be called if checks passed.
|
||||
// The status must be Loaded.
|
||||
virtual void Initialize() { status = Status::Initialized; }
|
||||
|
||||
// Prepare for unloading the Component. Must be called before the process begins.
|
||||
// The status must be Initialized.
|
||||
virtual void Close() { status == Status::Loaded; }
|
||||
|
||||
private:
|
||||
// This Component's unique ID.
|
||||
ComponentID id = ComponentID::Generate();
|
||||
// The Entity that requested this Component.
|
||||
EntityID owner;
|
||||
// The name of the Component, for visualization
|
||||
std::string name;
|
||||
// The status of the Component
|
||||
Status status = Status::Unloaded;
|
||||
|
||||
// Whether this Component is registered to the Entity's Local Systems.
|
||||
bool localComponent = false;
|
||||
// Whether this Component is registered to the Scene's Global Systems.
|
||||
bool globalComponent = false;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
|
||||
namespace SE {
|
||||
|
||||
/**
|
||||
* An Entity Component that has a Spatial context.
|
||||
* AKA, a Component with a position, a rotation, and a size.
|
||||
*
|
||||
* Spatial Components may exist in a hierarchy; where each subsequent object inherits the spatial positions of its' parents.
|
||||
* This allows for things like complex articulation of large machines, etc.
|
||||
*/
|
||||
class EntitySpatialComponent : public EntityComponent {
|
||||
public:
|
||||
|
||||
// Whether this is the root spatial component for this Entity.
|
||||
inline bool IsSpatialRoot() const { return parent == nullptr; }
|
||||
|
||||
// Fetch the transforms and bounds.
|
||||
inline Math::Transform const& GetLocalTransform() const { return transform; }
|
||||
inline Math::OrientedBB const& GetLocalBounds() const { return bounds; }
|
||||
|
||||
inline Math::Transform const& GetWorldTransform() const { return worldTransform; }
|
||||
inline Math::OrientedBB const& GetWorldBounds() const { return worldBounds; }
|
||||
|
||||
// Get the position in world-space.
|
||||
inline Math::Vector const& GetPosition() const { return worldTransform.GetTranslation(); }
|
||||
|
||||
// Get the rotation in world-space.
|
||||
inline Math::Quaternion const& GetRotation() const { return worldTransform.GetRotation(); }
|
||||
|
||||
// Get vectors relative to this spatial component.
|
||||
inline Math::Vector GetForwardVector() const { return worldTransform.GetForwardVector(); }
|
||||
inline Math::Vector GetUpVector() const { return worldTransform.GetUpVector(); }
|
||||
inline Math::Vector GetRightVector() const { return worldTransform.GetRightVector(); }
|
||||
|
||||
// Update the local and world transforms
|
||||
inline void SetLocalTransform(Math::Transform const& newTransform);
|
||||
inline void SetWorldTransform(Math::Transform const& newTransform);
|
||||
|
||||
// Move this component by the specified amount of transform, rotation
|
||||
inline void MoveBy(Math::Transform const& delta);
|
||||
|
||||
|
||||
// Is there a child spatial component
|
||||
inline bool HasChildren() const { return !children.empty(); }
|
||||
|
||||
// Get the ID of the parent of this Spatial Component
|
||||
inline ComponentID const& GetParentID() const { return parent->GetID(); }
|
||||
|
||||
// Get the transform of the parent component
|
||||
inline Math::Transform const& GetParentTransform() const { return parent->worldTransform; }
|
||||
|
||||
// Fetch how deep in the spatial hierarchy this Component is.
|
||||
size_t GetHierarchyDepth(bool singleEntity = true) const;
|
||||
|
||||
// Check if we are a child of a given Component
|
||||
bool IsChildOf(EntitySpatialComponent const* parent) const;
|
||||
|
||||
// Get the ID of the socket we are attached to
|
||||
inline std::string const& GetAttachmentSocketID() const { return attachmentSocket; }
|
||||
|
||||
// Set the name of the socket we wish to be attached to.
|
||||
inline void SetAttachmentSocket(std::string& id) { attachmentSocket = id;}
|
||||
|
||||
// Fetch the transform of a specific attachment.
|
||||
Math::Transform const& GetAttachmentTransform(std::string& id) const;
|
||||
|
||||
// Whether this Component supports local scaling
|
||||
virtual bool LocalScale() const { return false; }
|
||||
// Fetch the local scale, if supported. { 1, 1, 1 } otherwise.
|
||||
virtual std::array<float, 3> const& GetLocalScale() const { static auto ones = std::array<float, 3> { 1, 1, 1 }; return ones; }
|
||||
|
||||
// Convert a given world-space transform to a model-space transform.
|
||||
inline Math::Transform const& ConvertWorldToLocalTransform(Math::Transform const& world);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
virtual void Initialize() override;
|
||||
|
||||
// Set the local scale, if supported
|
||||
virtual void SetLocalScale(std::array<float, 3> const& newScale) {}
|
||||
|
||||
// Calculate the local bounding box for the Component; the position should always be close to origin.
|
||||
virtual Math::OrientedBB CalculateBounds() const;
|
||||
|
||||
// Update the local and world bounds for the Component.
|
||||
void UpdateBounds();
|
||||
|
||||
// Attempt to find the given Socket in this Component, and return its' Transform if present.
|
||||
bool GetAttachmentTransform(std::string& socketId, Math::Transform& out) const;
|
||||
virtual bool FindAttachmentTransform(std::string& socketId, Math::Transform& out) const;
|
||||
|
||||
// Whether this Component has the given Socket.
|
||||
// Default: No sockets.
|
||||
virtual bool HasSocket(std::string& socket) const { return false;}
|
||||
|
||||
// Process the creation/destruction/movement of a Socket.
|
||||
void UpdateSockets();
|
||||
|
||||
// Called whenever the World Transform is updated.
|
||||
virtual void OnMoved() {}
|
||||
|
||||
// Set the World Transform for a component.
|
||||
// Skips a lot of internal processing.
|
||||
inline void SetWorldTransform(Math::Transform& newTransform, bool callback = true);
|
||||
|
||||
private:
|
||||
|
||||
inline void CalculateWorldTransform(bool callback = true);
|
||||
|
||||
// The location of this Component, relative to the world.
|
||||
Math::Transform transform;
|
||||
// The collision boundary of this Component.
|
||||
Math::OrientedBB bounds;
|
||||
|
||||
// The world transform of this component; how to get to the position from the world origin.
|
||||
Math::Transform worldTransform;
|
||||
Math::OrientedBB worldBounds;
|
||||
|
||||
// The parent of this Spatial Component
|
||||
EntitySpatialComponent* parent = nullptr;
|
||||
// The socket (attachment point) of the parent entity that this Component is attached to.
|
||||
std::string attachmentSocket;
|
||||
// The Components that are attached to this Component.
|
||||
std::vector<EntitySpatialComponent*> children;
|
||||
|
||||
};
|
||||
}
|
61
projs/shadow/shadow-engine/shadow-entity/inc/id/ID.h
Normal file
61
projs/shadow/shadow-engine/shadow-entity/inc/id/ID.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#include <id/UUID.h> // Shadow-Engine/core/inc/id
|
||||
|
||||
namespace SE {
|
||||
|
||||
// An ID for a section of the scene (which may be unloaded separately of the level; for ie. open world Cells.)
|
||||
using EntitySectionID = UUID;
|
||||
// An ID for a scene (which contains all sections and entities).
|
||||
using EntitySceneID = UUID;
|
||||
|
||||
/**
|
||||
* Contains the common data and functions for the Entity System's identifiers.
|
||||
*/
|
||||
struct IDContainer {
|
||||
public:
|
||||
IDContainer() = default;
|
||||
explicit IDContainer(uint64_t v) : id(v) {}
|
||||
|
||||
// Check if the ID is valid (non-zero)
|
||||
__inline virtual bool Valid() const { return id != 0; }
|
||||
// Set this ID to be invalid (zero).
|
||||
__inline virtual void Invalidate() { id = 0; }
|
||||
// Check for in/equality against another ID.
|
||||
__inline virtual bool operator==(IDContainer const& other) const { return id == other.id; }
|
||||
__inline virtual bool operator!=(IDContainer const& other) const { return id != other.id; }
|
||||
__inline virtual bool operator<(IDContainer const& other) const { return id < other.id; }
|
||||
|
||||
uint64_t id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An ID used for an Entity.
|
||||
* Is only guaranteed to be unique in the current scene (ie. a level change may also change the IDs of the entities within).
|
||||
*/
|
||||
struct EntityID : public IDContainer {
|
||||
/**
|
||||
* @return a new, unused Entity ID.
|
||||
*/
|
||||
static EntityID Generate();
|
||||
|
||||
EntityID() = default;
|
||||
explicit EntityID(uint64_t v) : IDContainer(v) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* An ID used for a Component (a segment of data attached to an Entity).
|
||||
* Is only guaranteed to be unique in the current scene (ie. a level change may also change the IDs of the components within).
|
||||
*/
|
||||
struct ComponentID : public IDContainer {
|
||||
/**
|
||||
* @return a new, unused Component ID.
|
||||
*/
|
||||
static ComponentID Generate();
|
||||
|
||||
ComponentID() = default;
|
||||
explicit ComponentID(uint64_t v) : IDContainer(v) {}
|
||||
};
|
||||
}
|
||||
|
172
projs/shadow/shadow-engine/shadow-entity/inc/scene/EntityScene.h
Normal file
172
projs/shadow/shadow-engine/shadow-entity/inc/scene/EntityScene.h
Normal file
|
@ -0,0 +1,172 @@
|
|||
#pragma once
|
||||
|
||||
#include <scene/EntitySection.h>
|
||||
|
||||
namespace SE {
|
||||
|
||||
/**
|
||||
* A scene is a collection of Sections that contain Entities.
|
||||
* Scenes have support for asynchronous task management.
|
||||
* Scenes have their own input state, local to the world.
|
||||
* Scenes have Systems that operate over all Scene Components of all entities within.
|
||||
* Scenes can be either for Tools or for Gameplay.
|
||||
*
|
||||
* Scenes each have a primary viewport and any number of secondary viewports.
|
||||
*
|
||||
* Scenes contain Sections, which contain Entities.
|
||||
* One of the Sections in the Scene is always loaded; similar to Spawn Chunks.
|
||||
*
|
||||
* Scenes have a local timescale, which can be increased to make physics and logic run faster.
|
||||
*/
|
||||
class EntityScene {
|
||||
|
||||
/**
|
||||
* The type of the scene.
|
||||
* More-or-less exists to allow differentiating between an Editor and a Runtime.
|
||||
*/
|
||||
enum Type {
|
||||
TOOLS, // This scene exists for tooling support, ie. the builtin editor.
|
||||
GAME // This scene exists for gameplay, ie. the runtime.
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
EntityScene(Type wType = Type::GAME);
|
||||
~EntityScene();
|
||||
|
||||
// Fetch the ID of this scene.
|
||||
inline EntitySceneID const& GetID() const { return id; }
|
||||
// Whether this is a Gameplay scene.
|
||||
inline bool IsGameScene() const { return type == Type::GAME; }
|
||||
|
||||
// Prepare the Scene for processing entity updates. TODO: Systems.
|
||||
void Initialize();
|
||||
// Prepare all Regions and Entities for the closing of the Scene.
|
||||
void Shutdown();
|
||||
|
||||
|
||||
// Whether or not updates are suspended. ( Game is Paused )
|
||||
inline bool IsSuspended() const { return suspended; }
|
||||
|
||||
// Stop all Regions, Entities and Systems from updating.
|
||||
void Suspend() { suspended = true; }
|
||||
|
||||
// Resume updates to the Entities and Systems within.
|
||||
void Resume() { suspended = false; }
|
||||
|
||||
// Run a single tick of Entity and System updates. TODO: context
|
||||
void Update();
|
||||
|
||||
// Handle Entities, Regions, Resources that want to load or unload.
|
||||
void UpdateLoads();
|
||||
|
||||
// TODO: Systems
|
||||
|
||||
// TODO: Input
|
||||
|
||||
|
||||
// Check whether time is paused; the Scene itself can be unpaused during this, to allow movement through a paused world.
|
||||
inline bool IsTimePaused() const { return timeScale <= 0.0f; }
|
||||
|
||||
// Pause time in the Scene.
|
||||
inline void PauseTime() { timeScale = 0.0f; }
|
||||
|
||||
// The Time Scale for the Scene
|
||||
inline float GetTimeScale() const { return timeScale; }
|
||||
|
||||
// Set the Time Scale for the Scene.
|
||||
inline void SetTimeScale(float newScale) { timeScale = newScale; }
|
||||
|
||||
// Request a Time Step through a paused world.
|
||||
inline void TimeStep() { timeStepNeeded = true; }
|
||||
|
||||
// Whether a Scene with Paused Time needs a time step
|
||||
inline bool TimeStepRequested() const { return timeStepNeeded; }
|
||||
|
||||
// How long a single Time Step last, at most.
|
||||
inline float TimeStepLength() const { return timeStepLength; }
|
||||
|
||||
// Set the maximum length of a Time Step.
|
||||
inline void SetTimeStepLength(float newStep) { timeStepLength = newStep; }
|
||||
|
||||
// TODO: Viewports
|
||||
|
||||
// Fetch the Section that is always present and loaded; be careful adding things to this.
|
||||
EntitySection* GetPersistentSection() { return sections[0]; }
|
||||
EntitySection const* GetPersistentSection() const { return sections[0]; }
|
||||
|
||||
// Get the first Section that is not persistent, if present.
|
||||
EntitySection* GetFirstNonPersistentSection() { return sections.size() > 1 ? sections[1] : nullptr; }
|
||||
EntitySection const* GetFirstNonPersistentSection() const { return sections.size() > 1 ? sections[1] : nullptr; }
|
||||
|
||||
// Create a transient (memory-resident) Section.
|
||||
EntitySection* CreateTransientSection();
|
||||
|
||||
// Get a Section from memory.
|
||||
EntitySection const* GetSection(EntitySectionID const& sID) const;
|
||||
EntitySection* GetSection(EntitySectionID const& sID);
|
||||
|
||||
// Whether anything is loading into a Section
|
||||
bool IsLoading() const;
|
||||
|
||||
// Whether a Section exists in this scene
|
||||
bool HasSection(const EntitySectionID& eID) const;
|
||||
// Whether the Section in this scene is loaded.
|
||||
bool isSectionLoaded(const EntitySectionID& sID) const;
|
||||
|
||||
// Load a Section from the Scene file into memory.
|
||||
EntitySectionID LoadSection(EntitySectionID& section);
|
||||
// Unload a section from memory; delete every entity within.
|
||||
void UnloadSection(EntitySectionID& section);
|
||||
|
||||
inline Entity* FindEntity(EntityID& entity) const {
|
||||
Entity* e = nullptr;
|
||||
for (auto const& section : sections) {
|
||||
e = section->GetEntity(entity);
|
||||
if (e != nullptr) break;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
private:
|
||||
// The ID of this Scene.
|
||||
EntitySceneID id = UUID::Generate();
|
||||
|
||||
// The system that manages asynchronous background tasks for this Scene, such as Systems and Entity management.
|
||||
// Tasks* tasks;
|
||||
|
||||
// The local Input State, which exists relative to the viewport, allowing for tri picking.
|
||||
// Input input;
|
||||
|
||||
// TODO: Loading/Initialization
|
||||
|
||||
// TODO: Scene Systems
|
||||
|
||||
// The type of this Scene; default to game.
|
||||
Type type = Type::GAME;
|
||||
|
||||
// Whether or not everything in the map is ready to start.
|
||||
bool initialized = false;
|
||||
// Whether or not everything in the map is paused; no logic runs, nothing updates.
|
||||
bool suspended = false;
|
||||
|
||||
// TODO: Viewport
|
||||
|
||||
// The list of Sections in this Scene.
|
||||
std::vector<EntitySection*> sections;
|
||||
|
||||
// Every entity that is eligible for updates.
|
||||
// Ie. Every Initialized Entity in every Loaded Section.
|
||||
std::vector<Entity*> entityUpdateList;
|
||||
|
||||
//TODO: Scene Systems 2
|
||||
|
||||
// The multiplier for the number of steps per second (1/timescale * stepInterval)
|
||||
float timeScale = 1.0f;
|
||||
// The maximum length of each time step; if a step goes over this, it is aborted and the next begins processing.
|
||||
float timeStepLength = 1.0f/30;
|
||||
// Whether or not a new Time Step should begin immediately. Only applicable to Scenes with Paused Time.
|
||||
bool timeStepNeeded = false;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace SE {
|
||||
// Forward declaration, see inc/entity/Entity.h
|
||||
class Entity;
|
||||
|
||||
/**
|
||||
* A section is a collection of Entities with linked runtime.
|
||||
* ie. a game level could have one giant linked Section.
|
||||
* a cell of an open-world game could represent one Region,
|
||||
* and rooms of a BSP level could represent one Region.
|
||||
*/
|
||||
class EntitySection {
|
||||
|
||||
/**
|
||||
* The possible statuses for this Section.
|
||||
* Entities are not valid until the Loaded status is reached.
|
||||
*/
|
||||
enum class Status {
|
||||
Failed = -1, // An error occurred during loading.
|
||||
Unloaded = 0, // The Section is present, but none of the data is populated.
|
||||
Loading, // The Section is being loaded with data.
|
||||
Loaded, // The Section is present and contains valid data.
|
||||
Unloading // The Section is present but preparing to unload.
|
||||
};
|
||||
|
||||
/**
|
||||
* Request the deletion of an entity, after ie. destruction or death.
|
||||
*/
|
||||
struct PendingRemoval {
|
||||
PendingRemoval(Entity* entity, bool destroy)
|
||||
: entity(entity), destroy(destroy) {}
|
||||
|
||||
Entity* entity = nullptr;
|
||||
bool destroy = false;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
EntitySection();
|
||||
EntitySection(EntitySection const& section);
|
||||
EntitySection(EntitySection&& section);
|
||||
~EntitySection();
|
||||
|
||||
EntitySection& operator=(EntitySection const& section);
|
||||
EntitySection& operator=(EntitySection&& section);
|
||||
|
||||
// Get the ID of this Section
|
||||
inline EntitySectionID GetID() const { return id; }
|
||||
// Whether or not this Section was generated, without being loaded from disk.
|
||||
inline bool IsTransient() const { return isTransient; }
|
||||
|
||||
// TODO: Contexts?
|
||||
void Load();
|
||||
void Unload();
|
||||
|
||||
// Check that everything went properly, and update state accordingly.
|
||||
bool UpdateState();
|
||||
|
||||
// Whether there are any pending entity removals or additions.
|
||||
inline bool HasPendingEntityChanges() const { return (entitiesPendingLoading.size() + entitiesPendingRemoval.size()) > 0; }
|
||||
|
||||
bool IsLoading() const { return status == Status::Loading; }
|
||||
inline bool IsLoaded() const { return status == Status::Loaded; }
|
||||
inline bool IsUnloaded() const { return status == Status::Unloaded; }
|
||||
inline bool LoadingFailed() const { return status == Status::Failed; }
|
||||
|
||||
// Get the total number of entities in the section
|
||||
inline size_t GetEntityCount() const { return entities.size(); }
|
||||
// Get all entities in the region.
|
||||
inline std::vector<Entity*> const& GetEntities() const { return entities; }
|
||||
// Get a specific entity by its' ID.
|
||||
inline Entity* GetEntity(const EntityID& eID) const {
|
||||
auto i = entityLookup.find(eID);
|
||||
return (i != entityLookup.end()) ? i->second : nullptr;
|
||||
}
|
||||
// Check whether this region contains the specified entity.
|
||||
inline bool ContainsEntity(const EntityID& eID) const { return GetEntity(eID) != nullptr; }
|
||||
|
||||
// Add all of the specified entities to the region.
|
||||
// Transfers ownership if already present.
|
||||
// This operation takes time, but is guaranteed to be finished by the start of the next frame.
|
||||
void AddEntities(const std::vector<Entity*>& entities);
|
||||
|
||||
// Add an entity to the region.
|
||||
// Transfers ownership if already present.
|
||||
void AddEntity(Entity* entity);
|
||||
|
||||
// Queue an entity for removal from this region.
|
||||
// Transfers ownership to the caller.
|
||||
// This operation takes time, and no guarantee is given for completion.
|
||||
Entity* RemoveEntity(const EntityID& eID);
|
||||
|
||||
// Queue an entity for unloading from this region.
|
||||
// This operation takes time, and no guarantee is given for completion.
|
||||
void DestroyEntity(const EntityID& eID);
|
||||
|
||||
private:
|
||||
|
||||
// A callback for when an entity's state changes (ie. when loading)
|
||||
void EntityStateUpdated(Entity* entity);
|
||||
|
||||
// TODO: Process Loading, Unloading, Entity Shutdown, Entity Removal, Entity Loading.
|
||||
|
||||
private:
|
||||
|
||||
EntitySectionID id = UUID::Generate();
|
||||
Status status = Status::Unloaded;
|
||||
|
||||
// Transient = created on-the-fly, rather than existing on disk.
|
||||
bool const isTransient = false;
|
||||
|
||||
// The list of every entity in the Section, including those that are not yet loaded, or those that are due to be unloaded.
|
||||
std::vector<Entity*> entities;
|
||||
|
||||
// A fast map for looking up entities by ID.
|
||||
std::map<EntityID, Entity*> entityLookup;
|
||||
|
||||
// The list of entities that are currently being initialized to be put into the Section.
|
||||
std::vector<Entity*> entitiesLoading;
|
||||
|
||||
// The list of entities that are waiting to be loaded.
|
||||
std::vector<Entity*> entitiesPendingLoading;
|
||||
|
||||
// The list of entities that are waiting to be removed.
|
||||
std::vector<Entity*> entitiesPendingRemoval;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace SE {
|
||||
|
||||
// Forward declaration.
|
||||
class EntityComponent;
|
||||
|
||||
/**
|
||||
* A System is a routine that operates over the Components in an Entity.
|
||||
* A System may be local to a given Entity, or it may be glboal to the Scene.
|
||||
*
|
||||
* Components must be registered to the System that works over them.
|
||||
*
|
||||
* TODO: Think of better names for these functions
|
||||
*/
|
||||
class EntitySystem {
|
||||
public:
|
||||
|
||||
virtual ~EntitySystem();
|
||||
virtual std::string& GetName() const = 0;
|
||||
|
||||
// Pre-Component Register
|
||||
virtual void Initialize() {}
|
||||
|
||||
// Post-Component Register
|
||||
virtual void Initialized() {}
|
||||
|
||||
// Pre-Component Unregister
|
||||
virtual void Uninitialize() {}
|
||||
|
||||
// Post-Component Unregister
|
||||
virtual void Uninitialized() {}
|
||||
|
||||
protected:
|
||||
|
||||
// Register a Component with this System
|
||||
virtual void RegisterComponent(EntityComponent* component) = 0;
|
||||
// Unregister a Component from this system
|
||||
virtual void UnregisterComponent(EntityComponent* component) = 0;
|
||||
|
||||
// Update over all Components. TODO: Context?
|
||||
virtual void Update() = 0;
|
||||
};
|
||||
}
|
16
projs/shadow/shadow-engine/shadow-entity/src/id/ID.cpp
Normal file
16
projs/shadow/shadow-engine/shadow-entity/src/id/ID.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include <id/ID.h>
|
||||
#include <atomic>
|
||||
|
||||
namespace SE {
|
||||
static std::atomic<uint64_t> entityID = 1;
|
||||
EntityID EntityID::Generate() {
|
||||
EntityID id(entityID++);
|
||||
return id;
|
||||
}
|
||||
|
||||
static std::atomic<uint64_t> componentID = 1;
|
||||
ComponentID ComponentID::Generate() {
|
||||
ComponentID id(componentID++);
|
||||
return id;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user