190 lines
6.2 KiB
C++
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>;
|
|
}
|