1
0
Fork 0
Univerxel/src/core/world/Node.hpp

190 lines
6.2 KiB
C++

#pragma once
#include "forward.h"
#include "../generational/map.hpp"
#include "./Registry.hpp"
#include "../geometry/math.hpp"
#include <memory>
namespace world {
class Chunk;
struct Elements;
struct transform {
transform(const world_pos& p = world_pos(0), const pivot& r = identity_pivot):
position(p), rotation(r) { }
world_pos position;
pivot rotation;
world_pos computeChild(const world_pos& relative) const {
return position + (lpivot)rotation * relative;
}
transform computeChild(const transform& relative) const {
return transform(computeChild(relative.position), relative.rotation * rotation);
}
inline bool operator==(const transform &t) const { return position == t.position && rotation == t.rotation; }
inline bool operator!=(const transform &t) const { return !operator==(t); }
};
struct velocity {
velocity(const offset_pos& p = offset_pos(0), const pivot& r = identity_pivot):
position(p), rotation(r) { }
offset_pos position;
pivot rotation;
inline bool operator==(const velocity &v) const { return position == v.position && rotation == v.rotation; }
inline bool operator!=(const velocity &v) const { return !operator==(v); }
};
const auto FIXED = velocity();
/// Element position
struct NodeBody {
public:
transform absolute;
};
//MAYBE: separate NodeBody and dense maps of Elements
class Element;
struct Node: NodeBody {
Node(const transform& t, const std::shared_ptr<Element>& c): content(c) {
absolute = t;
}
std::shared_ptr<Element> content;
};
using node_id = generational::key<world::Node>;
using node_ref = generational::ref<world::Node>;
/// Abstract element content
class Element {
public:
virtual ~Element() { }
/// Remove itself from specific maps
virtual void free(const node_id& i, Elements&) = 0;
/// Axis-align bounding box relative to center
virtual aabb getBoundingBox(const Elements& l) const = 0;
//TODO: add physics queries
//TODO: getMass
};
template<class El>
struct NodeOf: Node {
static_assert(std::is_base_of<Element, El>::value);
static constexpr NodeOf *Make(Node *n) { return reinterpret_cast<NodeOf<El>*>(n); }
static constexpr const NodeOf *Make(const Node *n) { return reinterpret_cast<const NodeOf<El>*>(n); }
inline constexpr std::shared_ptr<El> get() const { return std::static_pointer_cast<El>(content); }
};
/// Element hierarchical relative data
struct Hierarchy {
public:
Hierarchy(const transform& relative, const velocity& vel):
relative(relative), vel(vel) { }
transform relative;
velocity vel;
};
struct relative_pos {
node_id parent;
world_pos position;
};
struct relative_transform {
node_id parent;
transform relative;
};
/// Single region element
class Part final : public Element {
public:
Part(glm::usvec3 s): size(s) { }
//TODO: add scale
void free(const node_id& i, Elements&) override;
aabb getBoundingBox(const Elements&) const override {
return aabb(glm::lfvec3(0), size);
}
/// Linear 3d grid of Chunk
/// Size: chunkSize()
using region_t = std::vector<std::shared_ptr<world::EdittableChunk>>;
region_t chunks;
bool empty() const { return chunks.empty(); }
bool loaded() const {
return chunks.size() >= static_cast<size_t>(chunkCount()) && std::all_of(chunks.begin(), chunks.end(),
[](const std::shared_ptr<world::EdittableChunk> &ptr) {return ptr != nullptr; });
}
void allocate() {
chunks.resize(chunkCount());
}
static constexpr chunk_pos ChunkSize(const glm::usvec3& s) { return chunk_pos(1) + glm::divide(s); }
constexpr chunk_pos chunkSize() const { return ChunkSize(size); }
size_t chunkCount() const {
const auto size = chunkSize();
return size.x * size.y * size.z;
}
constexpr bool inRange(const chunk_pos& c) const {
return glm::all(glm::greaterThanEqual(c, chunk_pos(0))) &&
glm::all(glm::lessThan(c, chunkSize()));
}
constexpr size_t getIdx(const chunk_pos& c) const {
return glm::toIdx(c, chunkSize());
}
constexpr region_chunk_pos getPos(size_t i) const {
return glm::fromIdx(i, chunkSize());
}
std::shared_ptr<world::EdittableChunk> findInRange(const chunk_pos& c) const {
assert(inRange(c));
const auto idx = getIdx(c);
if (idx < chunks.size())
return chunks[idx];
return nullptr;
}
void emplace(const chunk_pos& c, const std::shared_ptr<world::EdittableChunk>& ck) {
allocate();
chunks[getIdx(c)] = ck;
}
void emplace(const chunk_pos& c, std::shared_ptr<world::EdittableChunk>&& ck) {
allocate();
chunks[getIdx(c)] = std::move(ck);
}
glm::usvec3 size;
};
using part_id = generational::key<world::Part>;
using part_ref = generational::ref<world::Part>;
class Instance;
struct Model: world::module::model {
Model(const data& m, const geometry::faabb& col, glm::vec3 sc = glm::vec3(1), bool t = false):
model("", m, col, sc), temporary(t) { }
/// Is removed with last instance
bool temporary;
generational::map<Instance> instances;
/// Shared value for models without unique parameters
std::shared_ptr<Instance> origin;
};
using model_id = generational::key<world::Model>;
/// Instanced model element
class Instance final: public Element {
public:
Instance(const model_id& t): type(t) { }
/// Model id
model_id type;
void free(const node_id& i, Elements&) override;
aabb getBoundingBox(const Elements &l) const override;
};
using instance_id = generational::key<world::Instance>;
using instance_ref = generational::ref<world::Instance>;
}