Basic entities
This commit is contained in:
parent
ff9942691a
commit
310efea675
8
TODO.md
8
TODO.md
|
@ -15,7 +15,13 @@
|
|||
- [x] High memory: Save multiple
|
||||
- [x] Unload unused
|
||||
- [x] Edition
|
||||
- [ ] Entity
|
||||
- [~] Entity
|
||||
- [x] Basic
|
||||
- [ ] Instanced
|
||||
- https://learnopengl.com/Advanced-OpenGL/Instancing
|
||||
- [ ] Inheritance
|
||||
- [ ] ECS
|
||||
- [ ] Relative to area
|
||||
- [x] Area
|
||||
- [x] Offset
|
||||
- [ ] Rotation
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
enum class Input {
|
||||
Forward, Backward, Left, Right, Up, Down,
|
||||
Mouse, Debug
|
||||
Mouse, Debug, Throw
|
||||
};
|
||||
enum class Mouse {
|
||||
Left = GLFW_MOUSE_BUTTON_LEFT,
|
||||
|
@ -46,9 +46,10 @@ private:
|
|||
{Input::Down, GLFW_KEY_LEFT_SHIFT},
|
||||
{Input::Mouse, GLFW_KEY_E},
|
||||
{Input::Debug, GLFW_KEY_F3},
|
||||
{Input::Throw, GLFW_KEY_B}
|
||||
};
|
||||
const std::vector<Input> Toggles = {
|
||||
Input::Mouse, Input::Debug
|
||||
Input::Mouse, Input::Debug, Input::Throw
|
||||
};
|
||||
std::unordered_map<Input, bool> Previous;
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace data::generational {
|
|||
freed.pop_back();
|
||||
auto &entry = entries[idx];
|
||||
assert(!entry.value.has_value());
|
||||
entry.value = std::make_optional<T>(std::forward<_Args>(__args)...);
|
||||
entry.value.emplace(std::forward<_Args>(__args)...);
|
||||
return id(idx, ++entries[idx].generation);
|
||||
}
|
||||
}
|
||||
|
@ -125,6 +125,10 @@ namespace data::generational {
|
|||
entries[idx.index].value = in;
|
||||
return true;
|
||||
}
|
||||
T& at(id idx) {
|
||||
assert(contains(idx));
|
||||
return entries[idx.index].value.value();
|
||||
}
|
||||
|
||||
bool contains(id idx) const {
|
||||
return idx.index < entries.size() &&
|
||||
|
@ -151,6 +155,16 @@ namespace data::generational {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename apply>
|
||||
void for_each(apply fn) {
|
||||
for (size_t i = 0; i < entries.size(); i++) {
|
||||
auto &entry = entries[i];
|
||||
if(entry.value.has_value()) {
|
||||
fn(id(i, entry.generation), entry.value.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename extractor>
|
||||
void extract(extractor fn) {
|
||||
for (size_t i = 0; i < entries.size(); i++) {
|
||||
|
@ -162,6 +176,19 @@ namespace data::generational {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename extractor>
|
||||
void remove(extractor fn) {
|
||||
for (size_t i = 0; i < entries.size(); i++) {
|
||||
auto &entry = entries[i];
|
||||
if(entry.value.has_value()) {
|
||||
if(fn(id(i, entry.generation), entry.value.value())) {
|
||||
entry.value = std::nullopt;
|
||||
freed.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return std::count_if(entries.begin(), entries.end(),
|
||||
[](const entry &e) { return e.value.has_value(); });
|
||||
|
@ -172,6 +199,10 @@ namespace data::generational {
|
|||
entry(): value(std::nullopt), generation(0) { }
|
||||
entry(const T &in, size_t gen = 0):
|
||||
value(in), generation(gen) { }
|
||||
template <typename... _Args>
|
||||
entry(_Args &&... __args): generation(0) {
|
||||
value.emplace(std::forward<_Args>(__args)...);
|
||||
}
|
||||
std::optional<T> value;
|
||||
size_t generation;
|
||||
};
|
||||
|
|
|
@ -33,6 +33,11 @@ namespace glm {
|
|||
glm::llvec3 raw_as_long() const;
|
||||
glm::dvec3 as_double() const;
|
||||
|
||||
inline const ifvec3 &operator+=(const offset_t &v) {
|
||||
offset += v;
|
||||
center();
|
||||
return *this;
|
||||
}
|
||||
inline ifvec3 operator+(const offset_t& v) const { return ifvec3(raw, offset + v); }
|
||||
inline ifvec3 operator/(int i) const { return ifvec3(raw / i, offset / (i * 1.f), false); }
|
||||
inline ifvec3 operator*(int i) const { return ifvec3(raw * i, offset * (i * 1.f)); }
|
||||
|
|
50
src/main.cpp
50
src/main.cpp
|
@ -100,11 +100,16 @@ int main(int /*unused*/, char */*unused*/[]){
|
|||
|
||||
state.position = camera.getPosition();
|
||||
state.look_at = world.raycast(camera.getRay() * options.voxel_density);
|
||||
if (state.capture_mouse && state.look_at.has_value()) {
|
||||
if (inputs.isPressing(Mouse::Left))
|
||||
world.setCube(state.look_at.value().pos, world::Voxel(0), options.tool.radius);
|
||||
else if (inputs.isPressing(Mouse::Right))
|
||||
world.setCube(state.look_at.value().pos, world::Voxel(options.tool.material, world::Voxel::DENSITY_MAX), options.tool.radius);
|
||||
if (state.capture_mouse) {
|
||||
if (state.look_at.has_value()) {
|
||||
if (inputs.isPressing(Mouse::Left))
|
||||
world.setCube(state.look_at.value().pos, world::Voxel(0), options.tool.radius);
|
||||
else if (inputs.isPressing(Mouse::Right))
|
||||
world.setCube(state.look_at.value().pos, world::Voxel(options.tool.material, world::Voxel::DENSITY_MAX), options.tool.radius);
|
||||
}
|
||||
if (inputs.isDown(Input::Throw)) {
|
||||
world.addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)});
|
||||
}
|
||||
}
|
||||
world.update((state.position * options.voxel_density).as_voxel(), deltaTime, reports.world);
|
||||
inputs.saveKeys();
|
||||
|
@ -157,25 +162,40 @@ int main(int /*unused*/, char */*unused*/[]){
|
|||
auto pass = renderer->getPass();
|
||||
pass.start();
|
||||
|
||||
std::vector<std::pair<glm::mat4, buffer::Abstract *const>> models;
|
||||
reports.main.models_count = 0;
|
||||
reports.main.tris_count = 0;
|
||||
std::optional<geometry::Frustum> frustum;
|
||||
if(options.culling) {
|
||||
frustum = {camera.getFrustum()};
|
||||
}
|
||||
const auto offset = state.position.raw_as_long();
|
||||
world.getContouring()->getModels(models, frustum, offset, options.voxel_density);
|
||||
reports.main.models_count = 0;
|
||||
reports.main.tris_count = 0;
|
||||
rmt_ScopedOpenGLSample(Render);
|
||||
for (auto [model, buffer] : models) {
|
||||
reports.main.models_count++;
|
||||
reports.main.tris_count += buffer->draw(pass.setup(model));
|
||||
{ // Chunks
|
||||
std::vector<std::pair<glm::mat4, buffer::Abstract *const>> models;
|
||||
world.getContouring()->getModels(models, frustum, offset, options.voxel_density);
|
||||
rmt_ScopedOpenGLSample(Render);
|
||||
for (auto [model, buffer] : models) {
|
||||
reports.main.models_count++;
|
||||
reports.main.tris_count += buffer->draw(pass.setup(model));
|
||||
}
|
||||
}
|
||||
if(state.look_at.has_value()) {
|
||||
{ // Entities
|
||||
std::vector<std::pair<std::vector<glm::mat4>, buffer::Abstract *const>> models;
|
||||
world.getEntitiesModels(models, frustum, offset, options.voxel_density);
|
||||
lookProgram->useIt();
|
||||
lookProgram->start(renderer);
|
||||
for (auto [mats, buffer]: models) {
|
||||
for(auto model: mats) {
|
||||
reports.main.models_count++;
|
||||
reports.main.tris_count += lookBuffer.draw(lookProgram->setup(renderer, model));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(state.look_at.has_value()) { // Indicator
|
||||
lookProgram->useIt();
|
||||
lookProgram->start(renderer);
|
||||
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().pos.second + state.look_at.value().offset - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.tool.radius)), glm::vec3(1 + options.tool.radius * 2));
|
||||
lookBuffer.draw(lookProgram->setup(renderer, model));
|
||||
reports.main.models_count++;
|
||||
reports.main.tris_count += lookBuffer.draw(lookProgram->setup(renderer, model));
|
||||
}
|
||||
renderer->postProcess();
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
ImGui::PlotHistogram("Loading", reports.world.chunk_load.buffer.get(), reports.world.chunk_load.size, 0, std::to_string(reports.world.chunk_load.current()).c_str(), 0);
|
||||
ImGui::PlotHistogram("Saving", reports.world.chunk_unload.buffer.get(), reports.world.chunk_unload.size, 0, std::to_string(reports.world.chunk_unload.current()).c_str(), 0);
|
||||
ImGui::PlotHistogram("Regions", reports.world.region_count.buffer.get(), reports.world.region_count.size, 0, std::to_string(reports.world.region_count.current()).c_str(), 0);
|
||||
ImGui::PlotHistogram("Entities", reports.world.entity_count.buffer.get(), reports.world.entity_count.size, 0, std::to_string(reports.world.entity_count.current()).c_str(), 0);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Path: %s", options.world.folderPath.c_str());
|
||||
if (ImGui::SliderInt("Load distance", &options.world.loadDistance, 1, options.world.keepDistance) |
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace buffer {
|
|||
struct params {
|
||||
/// Bind only vertices positions
|
||||
bool vertexOnly;
|
||||
size_t instances = 1;
|
||||
};
|
||||
|
||||
/// Abstract OpenGL Buffer
|
||||
|
|
|
@ -39,13 +39,13 @@ namespace buffer {
|
|||
ShortIndexed(GLenum shape, const typename ShortIndexed::Data &data);
|
||||
virtual ~ShortIndexed();
|
||||
|
||||
uint draw(params params) override;
|
||||
|
||||
private:
|
||||
void enableAllAttribs();
|
||||
void disableAllAttribs();
|
||||
void enableIndex();
|
||||
|
||||
uint draw(params params) override;
|
||||
|
||||
private:
|
||||
GLuint IndexBufferID;
|
||||
GLushort IndexSize = 0;
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ Universe::Universe(const Universe::options &options): dicts("content/zstd.dict"
|
|||
index.close();
|
||||
}
|
||||
|
||||
entities.emplace(nullptr, glm::vec3(1), glm::vec3(2));
|
||||
|
||||
// Load workers
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
loadWorkers.emplace_back([&] {
|
||||
|
@ -185,7 +187,7 @@ void Universe::update(const voxel_pos& pos, float deltaTime, Universe::report& r
|
|||
});
|
||||
}
|
||||
{ // Update alive areas
|
||||
rmt_ScopedCPUSample(Update, 0);
|
||||
rmt_ScopedCPUSample(World, 0);
|
||||
size_t chunk_count = 0;
|
||||
size_t region_count = 0;
|
||||
const bool queuesEmpty = loadQueue.empty() && saveQueue.empty();
|
||||
|
@ -271,6 +273,18 @@ void Universe::update(const voxel_pos& pos, float deltaTime, Universe::report& r
|
|||
contouring->update(pos, areas);
|
||||
//MAYBE: if(chunkChange) contouring->notify(chunks);
|
||||
}
|
||||
{ // Update entities
|
||||
rmt_ScopedCPUSample(Entities, 0);
|
||||
size_t entity_count = 0;
|
||||
entities.for_each([&](entity_id, Entity &val) {
|
||||
val.instances.remove([&](entity_id, Entity::Instance &inst) {
|
||||
entity_count++;
|
||||
inst.pos += inst.velocity * deltaTime;
|
||||
return glm::length2(glm::divide(pos - inst.pos.as_voxel())) > glm::pow2(keepDistance);
|
||||
});
|
||||
});
|
||||
rep.entity_count.push(entity_count);
|
||||
}
|
||||
|
||||
{ // Store loaded chunks
|
||||
rmt_ScopedCPUSample(Load, 0);
|
||||
|
@ -357,4 +371,20 @@ ItemList Universe::setCube(const area_<voxel_pos>& pos, const Voxel& val, int ra
|
|||
}}}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
entity_instance_id Universe::addEntity(entity_id type, const Entity::Instance &instance) {
|
||||
return std::make_pair(type, entities.at(type).instances.push(instance));
|
||||
}
|
||||
void Universe::getEntitiesModels(std::vector<std::pair<std::vector<glm::mat4>, buffer::Abstract *const>> &buffers, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density) {
|
||||
entities.iter([&](entity_id, const Entity &entity) {
|
||||
std::vector<glm::mat4> mats;
|
||||
entity.instances.iter([&](entity_id, const Entity::Instance &inst) {
|
||||
const glm::vec3 fPos = (glm::vec3(inst.pos.raw_as_long() - offset * glm::llvec3(density)) + inst.pos.offset) / glm::vec3(density);
|
||||
if (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, entity.size)))
|
||||
mats.emplace_back(glm::scale(glm::translate(glm::mat4(1), fPos * (float)density), entity.scale));
|
||||
});
|
||||
if(!mats.empty())
|
||||
buffers.emplace_back(mats, entity.buffer);
|
||||
});
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
#include "../data/safe_priority_queue.hpp"
|
||||
#include "../data/circular_buffer.hpp"
|
||||
#include "../data/geometry/Ray.hpp"
|
||||
#include "../data/geometry/Frustum.hpp"
|
||||
#include "forward.h"
|
||||
#include "Area.hpp"
|
||||
#include "Voxel.hpp"
|
||||
|
@ -16,6 +17,9 @@
|
|||
namespace contouring {
|
||||
class Abstract;
|
||||
};
|
||||
namespace buffer {
|
||||
class Abstract;
|
||||
}
|
||||
|
||||
using namespace data;
|
||||
/// Universe data
|
||||
|
@ -42,6 +46,8 @@ namespace world {
|
|||
report_buffer chunk_unload;
|
||||
/// Regions in memory
|
||||
report_buffer region_count;
|
||||
/// Entity instances
|
||||
report_buffer entity_count;
|
||||
};
|
||||
|
||||
Universe(const options &);
|
||||
|
@ -66,6 +72,23 @@ namespace world {
|
|||
/// MAYBE: allow set multi area
|
||||
ItemList setCube(const area_<voxel_pos> &pos, const Voxel &val, int radius);
|
||||
|
||||
/// Entities commun properties
|
||||
struct Entity {
|
||||
Entity(buffer::Abstract* buffer, const glm::vec3& size = glm::vec3(1), const glm::vec3& scale = glm::vec3(1)):
|
||||
buffer(buffer), size(size), scale(scale) { };
|
||||
buffer::Abstract* buffer;
|
||||
glm::vec3 size;
|
||||
glm::vec3 scale;
|
||||
struct Instance {
|
||||
glm::ifvec3 pos;
|
||||
glm::vec3 velocity;
|
||||
};
|
||||
data::generational::vector<Instance> instances;
|
||||
};
|
||||
/// Instante entity
|
||||
entity_instance_id addEntity(entity_id type, const Entity::Instance &instance);
|
||||
void getEntitiesModels(std::vector<std::pair<std::vector<glm::mat4>, buffer::Abstract *const>> &buffers, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density);
|
||||
|
||||
/// Change contouring worker
|
||||
void setContouring(const std::shared_ptr<contouring::Abstract>& ct);
|
||||
/// Get current contouring worker
|
||||
|
@ -83,6 +106,8 @@ namespace world {
|
|||
data::generational::vector<Area::params> far_areas;
|
||||
void saveAreas() const;
|
||||
|
||||
data::generational::vector<Entity> entities;
|
||||
|
||||
bool running = true;
|
||||
std::vector<std::thread> loadWorkers;
|
||||
safe_priority_queue_map<area_<chunk_pos>, std::shared_ptr<Area>, int, area_hash> loadQueue; //NOTE: consider Area const (getRegion uses mutex)
|
||||
|
|
|
@ -47,4 +47,7 @@ struct area_hash {
|
|||
};
|
||||
using area_pos = glm::ifvec3;
|
||||
|
||||
using entity_id = data::generational::id;
|
||||
using entity_instance_id = std::pair<entity_id, data::generational::id>;
|
||||
|
||||
using camera_pos = glm::ifvec3;
|
||||
|
|
Loading…
Reference in New Issue