Commit f6a5a166 authored by Florian Oetke's avatar Florian Oetke
Browse files

replaced ECS emplace method with easier to use Entity_builder

parent 286994c2
Pipeline #2617 passed with stage
in 15 minutes and 6 seconds
......@@ -9,6 +9,8 @@ Mirrage (Mirrage Indirect Radiance Renderer And Game Engine) is a Vulkan based d
The repository at <a href="https://github.com/lowkey42/mirrage">GitHub</a> is a read-only mirror and the main repository is located on <a href="https://gitlab.com/lowkey42/mirrage">Gitlab.com</a>.
WIP API documentation/examples: <https://gitlab.com/lowkey42/mirrage/wikis/Documentation>
### Demo
<a href="http://www.youtube.com/watch?feature=player_embedded&v=gHHLuwjDiZo" target="_blank"><img src="screenshots/video_thumbnail2.jpeg" alt="Demo Video" height="180" border="10" /></a>
<a href="http://www.youtube.com/watch?feature=player_embedded&v=e1NXM5U4Rig" target="_blank"><img src="screenshots/video_thumbnail.jpeg" alt="Demo Video" height="180" border="10" /></a>
......
......@@ -31,8 +31,7 @@ namespace mirrage {
pos = transform.position + transform.direction() * 2.f;
}
}
_entities.emplace(blueprint).get<Transform_comp>().process(
[&](auto& transform) { transform.position = pos; });
_entities.entity_builder(blueprint).position(pos).create();
});
_commands.add("mem.renderer | Prints memory usage of renderer", [&] {
......
......@@ -11,28 +11,28 @@ namespace mirrage {
Test_animation_screen::Test_animation_screen(Engine& engine) : Test_screen(engine)
{
_animation_test_dqs = _meta_system.entities().emplace("monk");
_animation_test_dqs.get<Transform_comp>().process([](auto& transform) {
transform.position = {-8, 0, -0.5f - 1.f};
transform.orientation = glm::quatLookAt(glm::vec3{-1, 0, 0}, glm::vec3{0, 1, 0});
});
_animation_test_lbs = _meta_system.entities().emplace("monk_lbs");
_animation_test_lbs.get<Transform_comp>().process([](auto& transform) {
transform.position = {-8, 0, -0.5f + 1.f};
transform.orientation = glm::quatLookAt(glm::vec3{-1, 0, 0}, glm::vec3{0, 1, 0});
});
_animation_test2_dqs = _meta_system.entities().emplace("rotation_test");
_animation_test2_dqs.get<Transform_comp>().process([](auto& transform) {
transform.position = {-4, 0, -0.5f - 1.f};
});
_animation_test2_lbs = _meta_system.entities().emplace("rotation_test_lbs");
_animation_test2_lbs.get<Transform_comp>().process([](auto& transform) {
transform.position = {-4, 0, -0.5f + 1.f};
});
_animation_test_dqs = _meta_system.entities()
.entity_builder("monk")
.position({-8, 0, -0.5f - 1.f})
.direction(glm::vec3{-1, 0, 0})
.create();
_animation_test_lbs = _meta_system.entities()
.entity_builder("monk_lbs")
.position({-8, 0, -0.5f + 1.f})
.direction(glm::vec3{-1, 0, 0})
.create();
_animation_test2_dqs = _meta_system.entities()
.entity_builder("rotation_test")
.position({-4, 0, -0.5f - 1.f})
.create();
_animation_test2_lbs = _meta_system.entities()
.entity_builder("rotation_test_lbs")
.position({-4, 0, -0.5f + 1.f})
.create();
}
void Test_animation_screen::_draw()
......
......@@ -79,10 +79,7 @@ namespace mirrage {
, _gui(engine.gui())
, _performance_log(util::nothing)
{
_camera = _meta_system.entities().emplace("camera");
auto cornell = _meta_system.entities().emplace("cornell");
cornell.get<Transform_comp>().process([&](auto& transform) { transform.position = {1000, 0, 0}; });
_meta_system.entities().entity_builder("cornell").position({1000, 0, 0}).create();
_cmd_commands.add_property("pos",
[&](glm::vec3 position) {
......@@ -95,27 +92,25 @@ namespace mirrage {
[&](auto& transform) { return transform.position; });
});
_meta_system.entities().emplace("sponza");
_meta_system.entities().entity_builder("sponza").create();
_meta_system.entities().emplace("test_particle_emitter").process<Transform_comp>([&](auto& transform) {
transform.position = {-6, 2, 1};
});
_meta_system.entities().emplace("test_smoke_emitter").process<Transform_comp>([&](auto& transform) {
transform.position = {-6, 1, -1};
});
_meta_system.entities().entity_builder("test_particle_emitter").position({-6, 2, 1}).create();
_meta_system.entities().entity_builder("test_smoke_emitter").position({-6, 1, -1}).create();
auto billboard = _meta_system.entities().emplace("billboard");
billboard.get<Transform_comp>().process([](auto& transform) {
transform.position = {-8, 1, 0.5f};
transform.orientation = glm::quatLookAt(glm::vec3{-1, 0, 0}, glm::vec3{0, 1, 0});
});
_meta_system.entities()
.entity_builder("billboard")
.position({-8, 1, 0.5f})
.direction({-1, 0, 0})
.create();
auto decal = _meta_system.entities().emplace("decal");
decal.get<Transform_comp>().process([](auto& transform) { transform.position = {-8, 0, -0.5f}; });
_meta_system.entities().entity_builder("decal").position({-8, 0, -0.5f}).create();
_sun = _meta_system.entities().emplace("sun");
_sun = _meta_system.entities().entity_builder("sun").create();
_set_preset(1);
_camera = _meta_system.entities()
.entity_builder("camera")
.post_create([&](auto&&) { _set_preset(1); })
.create();
_mailbox.subscribe_to([&](input::Once_action& e) {
switch(e.id) {
......@@ -133,14 +128,14 @@ namespace mirrage {
mirrage_quick_exit();
break;
case "create"_strid:
_meta_system.entities().emplace("cube").get<Transform_comp>().process(
[&](auto& transform) {
auto& cam = _camera.get<Transform_comp>().get_or_throw();
transform.position = cam.position + cam.direction();
});
case "create"_strid: {
auto& cam = _camera.get<Transform_comp>().get_or_throw();
_meta_system.entities()
.entity_builder("cube")
.position(cam.position + cam.direction())
.create();
break;
}
case "print"_strid: {
auto cam = _camera.get<Transform_comp>().get_or_throw().position;
......
......@@ -18,10 +18,13 @@
#include <mirrage/utils/template_utils.hpp>
#include <concurrentqueue.h>
#include <glm/gtx/quaternion.hpp>
#include <glm/vec3.hpp>
#include <memory>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
......@@ -36,6 +39,70 @@ namespace mirrage::ecs {
/// entity transfer object
using ETO = std::string;
class Entity_builder {
public:
Entity_builder() = default;
auto blueprint(std::string v) -> Entity_builder&
{
_blueprint = std::move(v);
return *this;
}
auto position(glm::vec3 v) -> Entity_builder&
{
_position = v;
return *this;
}
auto direction(glm::vec3 v) -> Entity_builder&
{
_rotation = v;
_look_at = false;
return *this;
}
auto look_at(glm::vec3 v) -> Entity_builder&
{
_rotation = v;
_look_at = true;
return *this;
}
auto rotation(glm::quat v) -> Entity_builder&
{
_rotation = v;
return *this;
}
auto post_create(std::function<void(Entity_facet)> v) -> Entity_builder&
{
_post_create = v;
return *this;
}
auto create() -> Entity_facet;
private:
friend class Entity_manager;
using Listener = std::function<void(Entity_facet)>;
using Rotation = std::variant<std::monostate, glm::vec3, glm::quat>;
Entity_builder(Entity_manager& m, std::string blueprint = {})
: _manager(&m), _blueprint(std::move(blueprint))
{
}
void apply();
Entity_manager* _manager = nullptr;
Entity_facet _facet;
Listener _post_create;
std::string _blueprint;
Rotation _rotation;
util::maybe<glm::vec3> _position;
bool _look_at = false;
};
/**
* The main functionality is thread-safe but the other methods require a lock to prevent
* concurrent read access during their execution
......@@ -46,8 +113,11 @@ namespace mirrage::ecs {
~Entity_manager();
// user interface; thread-safe
auto emplace() noexcept -> Entity_facet;
auto emplace(const std::string& blueprint) -> Entity_facet; // TODO/FIXME: currently NOT thread-safe
auto entity_builder(std::string blueprint = {}) -> Entity_builder
{
return {*this, std::move(blueprint)};
}
auto emplace_empty() -> Entity_facet;
auto get(Entity_handle entity) -> util::maybe<Entity_facet>;
auto get_handle(Entity_id id) const -> Entity_handle { return _handles.get(id); }
auto validate(Entity_handle entity) -> bool { return _handles.valid(entity); }
......@@ -84,10 +154,12 @@ namespace mirrage::ecs {
auto component_type_by_name(const std::string& name) -> util::maybe<Component_type>;
private:
friend class Entity_builder;
friend class Entity_facet;
friend class Entity_collection_facet;
using Erase_queue = moodycamel::ConcurrentQueue<Entity_handle>;
using Erase_queue = moodycamel::ConcurrentQueue<Entity_handle>;
using Emplace_queue = moodycamel::ConcurrentQueue<Entity_builder>;
asset::Asset_manager& _assets;
util::any_ptr _userdata;
......@@ -95,6 +167,7 @@ namespace mirrage::ecs {
Entity_handle_generator _handles;
Erase_queue _queue_erase;
std::vector<Entity_handle> _local_queue_erase;
Emplace_queue _queued_emplace;
std::vector<std::unique_ptr<Component_container_base>> _components;
std::unordered_map<std::string, Component_type> _components_by_name;
......
......@@ -3,6 +3,8 @@
#include <mirrage/ecs/component.hpp>
#include <mirrage/ecs/serializer.hpp>
#include <mirrage/ecs/components/transform_comp.hpp>
#include <mirrage/utils/log.hpp>
#include <mirrage/utils/string_utils.hpp>
......@@ -23,16 +25,51 @@ namespace mirrage::ecs {
}
Entity_manager::~Entity_manager() { deinit_serializer(*this); }
Entity_facet Entity_manager::emplace() noexcept { return {*this, _handles.get_new()}; }
Entity_facet Entity_manager::emplace(const std::string& blueprint)
auto Entity_builder::create() -> Entity_facet
{
auto e = emplace();
MIRRAGE_INVARIANT(_manager, "Called Entity_builder::create() on uninitialized/moved-from object.");
_facet = _manager->emplace_empty();
apply_blueprint(_assets, e, blueprint);
if(!_blueprint.empty()) {
_manager->_queued_emplace.enqueue(*this);
} else {
apply();
}
return {*this, e.handle()};
return _facet;
}
void Entity_builder::apply()
{
MIRRAGE_INVARIANT(_facet, "Called Entity_builder::apply() without facet");
if(!_blueprint.empty())
apply_blueprint(_manager->_assets, _facet, _blueprint);
else if(_position.is_some() || std::holds_alternative<std::monostate>(_rotation))
_facet.emplace<components::Transform_comp>();
_facet.process<components::Transform_comp>([&](auto& transform) {
if(_position.is_some())
transform.position = _position.get_or_throw();
if(auto r = std::get_if<glm::vec3>(&_rotation)) {
if(_look_at)
transform.look_at(*r);
else
transform.direction(*r);
} else if(auto r = std::get_if<glm::quat>(&_rotation)) {
transform.orientation = *r;
}
});
if(_post_create)
_post_create(_facet);
}
auto Entity_manager::emplace_empty() -> Entity_facet { return {*this, _handles.get_new()}; }
auto Entity_manager::get(Entity_handle entity) -> util::maybe<Entity_facet>
{
if(validate(entity))
......@@ -55,27 +92,45 @@ namespace mirrage::ecs {
MIRRAGE_INVARIANT(_local_queue_erase.empty(),
"Someone's been sleeping in my bed! (_local_queue_erase is dirty)");
std::array<Entity_handle, 32> erase_buffer;
do {
std::size_t count = _queue_erase.try_dequeue_bulk(erase_buffer.data(), erase_buffer.size());
{
std::array<Entity_builder, 8> emplace_buffer;
do {
std::size_t count =
_queued_emplace.try_dequeue_bulk(emplace_buffer.data(), emplace_buffer.size());
if(count > 0) {
for(std::size_t i = 0; i < count; i++) {
emplace_buffer[i].apply();
}
} else {
break;
}
} while(true);
}
{
std::array<Entity_handle, 32> erase_buffer;
do {
std::size_t count = _queue_erase.try_dequeue_bulk(erase_buffer.data(), erase_buffer.size());
if(count > 0) {
for(std::size_t i = 0; i < count; i++) {
const auto h = erase_buffer[i];
if(!validate(h))
continue;
if(count > 0) {
for(std::size_t i = 0; i < count; i++) {
const auto h = erase_buffer[i];
if(!validate(h))
continue;
_local_queue_erase.emplace_back(h);
_local_queue_erase.emplace_back(h);
for(auto& component : _components) {
if(component)
component->erase(h);
for(auto& component : _components) {
if(component)
component->erase(h);
}
}
} else {
break;
}
} else {
break;
}
} while(true);
} while(true);
}
for(auto& component : _components) {
if(component)
......@@ -95,7 +150,8 @@ namespace mirrage::ecs {
component->clear();
_handles.clear();
_queue_erase = Erase_queue{};
_queue_erase = Erase_queue{};
_queued_emplace = Emplace_queue{};
}
......@@ -111,7 +167,7 @@ namespace mirrage::ecs {
auto Entity_manager::read_one(ETO data, Entity_handle target) -> Entity_facet
{
if(!validate(target)) {
target = emplace();
target = emplace_empty();
}
std::istringstream stream{data};
......
......@@ -253,7 +253,7 @@ namespace mirrage::ecs {
auto& ecs_deserializer = static_cast<Deserializer&>(s);
if(!ecs_deserializer.manager.validate(e)) {
auto e_facet = ecs_deserializer.manager.emplace();
auto e_facet = ecs_deserializer.manager.emplace_empty();
e = e_facet.handle();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment