#pragma once #include "forward.h" #include "../generational/map.hpp" #include "./Registry.hpp" #include "../geometry/math.hpp" #include 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& c): content(c) { absolute = t; } std::shared_ptr content; }; using node_id = generational::key; using node_ref = generational::ref; /// 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 struct NodeOf: Node { static_assert(std::is_base_of::value); static constexpr NodeOf *Make(Node *n) { return reinterpret_cast*>(n); } static constexpr const NodeOf *Make(const Node *n) { return reinterpret_cast*>(n); } inline constexpr std::shared_ptr get() const { return std::static_pointer_cast(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>; region_t chunks; bool empty() const { return chunks.empty(); } bool loaded() const { return chunks.size() >= static_cast(chunkCount()) && std::all_of(chunks.begin(), chunks.end(), [](const std::shared_ptr &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 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& ck) { allocate(); chunks[getIdx(c)] = ck; } void emplace(const chunk_pos& c, std::shared_ptr&& ck) { allocate(); chunks[getIdx(c)] = std::move(ck); } glm::usvec3 size; }; using part_id = generational::key; using part_ref = generational::ref; 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 instances; /// Shared value for models without unique parameters std::shared_ptr origin; }; using model_id = generational::key; /// 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; using instance_ref = generational::ref; }