simplified component manager, removed ref type

This commit is contained in:
turanszkij
2018-09-01 16:16:46 +01:00
parent dcfdcc883a
commit 48256ca39e
8 changed files with 80 additions and 183 deletions
+4 -8
View File
@@ -106,13 +106,9 @@ CameraWindow::CameraWindow(wiGUI* gui) :GUI(gui)
Entity proxy = CreateEntity();
auto name_ref = scene.names.Create(proxy);
auto transform_ref = scene.transforms.Create(proxy);
auto camera_ref = scene.cameras.Create(proxy);
auto& name = scene.names.GetComponent(name_ref);
auto& transform = scene.transforms.GetComponent(transform_ref);
auto& camera = scene.cameras.GetComponent(camera_ref);
auto& name = scene.names.Create(proxy);
auto& transform = scene.transforms.Create(proxy);
auto& camera = scene.cameras.Create(proxy);
name = "cam";
camera = *wiRenderer::getCamera();
@@ -166,7 +162,7 @@ void CameraWindow::SetEntity(Entity entity)
Scene& scene = wiRenderer::GetScene();
if (scene.cameras.Find(entity))
if (scene.cameras.GetComponent(entity) != nullptr)
{
followCheckBox->SetEnabled(true);
followSlider->SetEnabled(true);
+2 -3
View File
@@ -1082,11 +1082,10 @@ void EditorComponent::Update(float dt)
else
{
// Orbital Camera
auto parented = scene.parents.Find(wiRenderer::getCameraID());
ParentComponent* parented = scene.parents.GetComponent(wiRenderer::getCameraID());
TransformComponent* target_transform = scene.transforms.GetComponent(cameraWnd->target);
if (!parented)
if (parented == nullptr)
{
//cam->attachTo(cameraWnd->orbitalCamTarget);
scene.Component_Attach(wiRenderer::getCameraID(), cameraWnd->target);
+2 -4
View File
@@ -168,16 +168,14 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui)
scene.owned_entities.insert(newEntity);
auto ref_light = scene.lights.Create(newEntity);
LightComponent& light = scene.lights.GetComponent(ref_light);
LightComponent& light = scene.lights.Create(newEntity);
light.energy = 2;
light.range = 60;
light.fov = XM_PIDIV4;
light.color = XMFLOAT3(1, 1, 1);
light.SetType(LightComponent::POINT);
auto ref_transform = scene.transforms.Create(newEntity);
TransformComponent& transform = scene.transforms.GetComponent(ref_transform);
TransformComponent& transform = scene.transforms.Create(newEntity);
transform.Translate(XMFLOAT3(0, 3, 0));
scene.cullables.Create(newEntity);
+58 -140
View File
@@ -27,183 +27,105 @@ namespace wiECS
components.reserve(reservedCount);
entities.reserve(reservedCount);
lookup.reserve(reservedCount);
indices.reserve(reservedCount);
}
// The ref is an indirection to the components. Components will be moved around to remain compacted, but ref will always be able to reference a component.
struct ref
{
size_t value = ~0;
inline ref operator=(ref other) { value = other.value; return *this; }
inline bool operator==(ref other) const { return value == other.value; }
inline bool operator!=(ref other) const { return value != other.value; }
inline ref& operator++() { value++; return *this; }
inline ref operator++(int v) { ref temp = *this; ++*this; return temp; }
inline ref& operator--() { value--; return *this; }
inline ref operator--(int v) { ref temp = *this; --*this; return temp; }
inline operator bool() const { return value != ~0; }
};
// Clear the whole container, invalidate all refs
// Clear the whole container
inline void Clear()
{
components.clear();
entities.clear();
lookup.clear();
indices.clear();
dead.clear();
}
// Check if an ref is referencing a component or not (ref is safe but uses indirection):
inline bool IsValid(ref it) const
{
return it.value < indices.size() && indices[it.value] < components.size();
}
// Check if an ref is referencing a specific entity or not (ref is safe but uses indirection):
inline bool IsValid(ref it, Entity entity) const
{
assert(entities.size() == components.size());
return IsValid(it) && entities[indices[it.value]] == entity;
}
// Create a new component and retrieve ref (ref is safe but uses indirection):
inline ref Create(Entity entity)
// Create a new component and retrieve a reference to it:
inline T& Create(Entity entity)
{
// Only one of this component type per entity is allowed!
assert(!IsValid(Find(entity)));
ref it;
if (dead.empty())
{
// There are no dead elements, so we must have the same amount of components as indices:
assert(components.size() == indices.size());
// Any new component and index will just be pushed onto the end:
it.value = components.size();
indices.push_back(it.value);
}
else
{
// We have dead elements, which means components was popped, but indices only swapped, so there must be less components than indices:
assert(components.size() < indices.size());
// Essentially we pop the last dead ref and update its value to the new component (that will always be pushed to the end of components):
it = dead.back();
dead.pop_back();
indices[it.value] = components.size();
}
assert(lookup.find(entity) == lookup.end());
// Entity count must always be the same as the number of coponents!
assert(entities.size() == components.size());
assert(lookup.size() == components.size());
// Update the entity lookup table:
lookup[entity] = components.size();
// New components are always pushed to the end:
components.push_back(T());
// Also push corresponding entity:
entities.push_back(entity);
// Update the entity lookup table:
lookup[entity] = it;
return it;
return components.back();
}
// Remove a component of a certain entity if it exists (referencing by Entity involves multiple indirection):
// Remove a component of a certain entity if it exists:
inline void Remove(Entity entity)
{
ref it = Find(entity);
if (IsValid(it, entity))
{
Remove(it);
}
}
// Remove a component referenced by a certain ref (ref is safe but uses indirection):
inline void Remove(ref it)
{
// ref should be valid:
assert(IsValid(it));
// Directly index into components and entities array:
const size_t index = indices[it.value];
// Remove the corresponding entry from the lookup table:
const Entity entity = entities[index];
lookup.erase(entity);
// Swap out the dead element with the last one, and shrink the container:
components[index] = std::move(components.back()); // try to use move instead of copy
components.pop_back();
entities[index] = entities.back();
entities.pop_back();
// Because the last element of the container was moved to the position of the removed element, we update its ref accordingly:
indices[components.size()] = index;
//The current ref is marked as dead:
indices[it.value] = ~0;
dead.push_back(it);
}
// Swap two components' data that are referenced by refs (ref is safe but uses indirection):
inline void Swap(ref a, ref b)
{
const size_t index_a = indices[a.value];
const size_t index_b = indices[b.value];
const size_t index_tmp = index_a;
const Entity entity_tmp = entities[index_a];
const T component_tmp = std::move(components[index_a]);
indices[a.value] = index_b;
entities[index_a] = entities[index_b];
components[index_a] = std::move(components[index_b]);
indices[b.value] = index_tmp;
entities[index_b] = entity_tmp;
components[index_b] = std::move(component_tmp);
}
// Find a specific component of a certain entity if exists (referencing by Entity involves multiple indirection):
inline ref Find(Entity entity) const
{
auto it = lookup.find(entity);
if (it != lookup.end())
{
return it->second;
// Directly index into components and entities array:
const size_t index = it->second;
// Remove the corresponding entry from the lookup table:
const Entity entity = entities[index];
lookup.erase(entity);
if (components.size() > 1)
{
// Swap out the dead element with the last one:
components[index] = std::move(components.back()); // try to use move instead of copy
entities[index] = entities.back();
// Update the lookup table:
lookup[entities[index]] = index;
}
// Shrink the container:
components.pop_back();
entities.pop_back();
}
}
// Swap two components' data:
inline void Swap(Entity a, Entity b)
{
auto it_a = lookup.find(a);
auto it_b = lookup.find(b);
if (it_a != lookup.end() && it_b != lookup.end())
{
const size_t index_a = it_a->second;
const size_t index_b = it_b->second;
const Entity entity_tmp = entities[index_a];
const T component_tmp = std::move(components[index_a]);
entities[index_a] = entities[index_b];
components[index_a] = std::move(components[index_b]);
entities[index_b] = entity_tmp;
components[index_b] = std::move(component_tmp);
lookup[a] = index_b;
lookup[b] = index_a;
}
return ref();
}
// Retrieve a component specified by an entity (if it exists, otherwise nullptr):
inline T* GetComponent(Entity entity)
{
ref it = Find(entity);
if (IsValid(it, entity))
auto it = lookup.find(entity);
if (it != lookup.end())
{
return &components[indices[it.value]];
return &components[it->second];
}
return nullptr;
}
// Retrieve a component specified by an ref (ref is safe but uses indirection):
inline T& GetComponent(ref it)
{
assert(IsValid(it));
return components[indices[it.value]];
}
// Retrieve an entity specified by an ref (ref is safe but uses indirection):
inline Entity GetEntity(ref it) const
{
assert(IsValid(it));
return entities[indices[it.value]];
}
// Retrieve the number of existing entries:
inline size_t GetCount() const { return components.size(); }
@@ -225,11 +147,7 @@ namespace wiECS
// This is a linear array of entities corresponding to each alive component:
std::vector<Entity> entities;
// This is a lookup table for entities:
std::unordered_map<Entity, ref> lookup;
// This is the indirection of ref->component index:
std::vector<size_t> indices;
// The indices will also contain dead elements, and those are saved here:
std::vector<ref> dead;
std::unordered_map<Entity, size_t> lookup;
};
}
+5 -6
View File
@@ -7969,7 +7969,7 @@ wiRenderer::RayIntersectWorldResult wiRenderer::RayIntersectWorld(const RAY& ray
return result;
}
ComponentManager<ModelComponent>::ref wiRenderer::LoadModel(const std::string& fileName, const XMMATRIX& transform)
Entity wiRenderer::LoadModel(const std::string& fileName, const XMMATRIX& transform)
{
//Model* model = nullptr;
@@ -7991,7 +7991,7 @@ ComponentManager<ModelComponent>::ref wiRenderer::LoadModel(const std::string& f
//return model;
return ComponentManager<ModelComponent>::ref();
return INVALID_ENTITY;
}
void wiRenderer::LoadWorldInfo(const std::string& fileName)
{
@@ -8072,9 +8072,8 @@ Scene& wiRenderer::GetScene()
{
scene = new Scene;
auto transform_ref = scene->transforms.Create(cameraID);
auto camera_ref = scene->cameras.Create(cameraID);
scene->cameras.GetComponent(camera_ref).CreatePerspective((float)wiRenderer::GetInternalResolution().x, (float)wiRenderer::GetInternalResolution().y, 0.1f, 800);
scene->transforms.Create(cameraID);
scene->cameras.Create(cameraID).CreatePerspective((float)wiRenderer::GetInternalResolution().x, (float)wiRenderer::GetInternalResolution().y, 0.1f, 800);
}
return *scene;
}
@@ -8165,7 +8164,7 @@ void wiRenderer::PutEnvProbe(const XMFLOAT3& position)
//GetScene().GetWorldNode()->environmentProbes.push_back(probe);
}
void wiRenderer::CreateImpostor(ComponentManager<MeshComponent>::ref mesh_ref, GRAPHICSTHREAD threadID)
void wiRenderer::CreateImpostor(Entity entity, GRAPHICSTHREAD threadID)
{
//MeshComponent& mesh = GetScene().meshes.GetComponent(mesh_ref);
+2 -2
View File
@@ -500,12 +500,12 @@ public:
static void SetOceanEnabled(bool enabled, const wiOceanParameter& params);
static wiOcean* GetOcean() { return ocean; }
static wiECS::ComponentManager<wiSceneSystem::ModelComponent>::ref LoadModel(const std::string& fileName, const XMMATRIX& transform = XMMatrixIdentity());
static wiECS::Entity LoadModel(const std::string& fileName, const XMMATRIX& transform = XMMatrixIdentity());
static void LoadWorldInfo(const std::string& fileName);
static void PutEnvProbe(const XMFLOAT3& position);
static void CreateImpostor(wiECS::ComponentManager<wiSceneSystem::MeshComponent>::ref mesh_ref, GRAPHICSTHREAD threadID);
static void CreateImpostor(wiECS::Entity, GRAPHICSTHREAD threadID);
static std::vector<std::pair<XMFLOAT4X4,XMFLOAT4>> renderableBoxes;
// Add box to render in next frame
+5 -6
View File
@@ -591,19 +591,18 @@ namespace wiSceneSystem
{
assert(entity != parent);
auto it = parents.Find(entity);
ParentComponent* parentcomponent = parents.GetComponent(entity);
if (!it)
if (parentcomponent == nullptr)
{
it = parents.Create(entity);
parentcomponent = &parents.Create(entity);
}
ParentComponent& parentcomponent = parents.GetComponent(it);
TransformComponent* transformcomponent = transforms.GetComponent(parent);
assert(transformcomponent != nullptr);
parentcomponent.parentID = parent;
XMStoreFloat4x4(&parentcomponent.world_parent_bind, XMMatrixInverse(nullptr, XMLoadFloat4x4(&transformcomponent->world)));
parentcomponent->parentID = parent;
XMStoreFloat4x4(&parentcomponent->world_parent_bind, XMMatrixInverse(nullptr, XMLoadFloat4x4(&transformcomponent->world)));
}
void Scene::Component_Detach(wiECS::Entity entity)
{
+2 -14
View File
@@ -357,7 +357,7 @@ namespace wiSceneSystem
struct ArmatureComponent
{
std::vector<wiECS::ComponentManager<BoneComponent>::ref> boneCollection;
std::vector<wiECS::Entity> boneCollection;
GFX_STRUCT ShaderBoneType
{
@@ -563,19 +563,7 @@ namespace wiSceneSystem
struct ModelComponent
{
std::vector<wiECS::ComponentManager<MaterialComponent>::ref> material_refs;
std::vector<wiECS::ComponentManager<MeshComponent>::ref> mesh_refs;
std::vector<wiECS::ComponentManager<ObjectComponent>::ref> object_refs;
std::vector<wiECS::ComponentManager<PhysicsComponent>::ref> physicscomponent_refs;
std::vector<wiECS::ComponentManager<CullableComponent>::ref> cullable_refs;
std::vector<wiECS::ComponentManager<BoneComponent>::ref> bone_refs;
std::vector<wiECS::ComponentManager<ArmatureComponent>::ref> armature_refs;
std::vector<wiECS::ComponentManager<LightComponent>::ref> light_refs;
std::vector<wiECS::ComponentManager<EnvironmentProbeComponent>::ref> probe_refs;
std::vector<wiECS::ComponentManager<ForceFieldComponent>::ref> force_refs;
std::vector<wiECS::ComponentManager<DecalComponent>::ref> decal_refs;
std::vector<wiECS::ComponentManager<CameraComponent>::ref> camera_refs;
std::unordered_set<wiECS::Entity> entities;
};
struct Scene