#pragma once #include "Chunk.hpp" #include "../geometry/Faces.hpp" using namespace geometry; namespace world { class EdittableChunk; class ChunkEdits { public: ChunkEdits(EdittableChunk* ptr, bool upToDate = false): parent(ptr), upToDate(upToDate), toUpdate(upToDate ? Faces::None : Faces::All) { } virtual ~ChunkEdits() { } /// Update voxels /// @return if modified neighbors to update virtual std::optional update(float deltaTime, bool animate); /// Notify for render inline void invalidate(Faces faces) { upToDate = false; toUpdate = toUpdate | faces; } void invalidate(chunk_voxel_idx idx); struct EditBody { Voxel value; float delay; }; struct Edit: EditBody { chunk_voxel_idx idx; }; /// Save edits without chunk change void add(const Edit &edit); /// Change chunk and save edit void apply(const Edit &edit); static std::optional getNeighborIdx(chunk_voxel_idx idx, Face dir); using edits_t = robin_hood::unordered_map; /// Get visible changes const edits_t &getEdits() const { return edits; } protected: /// Animated changes edits_t edits; /// Data ptr EdittableChunk *const parent; /// Require update bool upToDate; /// Neighbors to update Faces toUpdate; }; class EdittableChunk: public world::Chunk { public: virtual ~EdittableChunk(); ChunkEdits* setEdits() { assert(edits); return edits.get(); } const ChunkEdits& getEdits() const { assert(edits); return *edits.get(); } /// Direct set without update of voxel at index void set(chunk_voxel_idx idx, const Voxel &voxel); /// Direct set without update of voxel at position void setAt(const chunk_voxel_pos &pos, const Voxel& voxel); /// Convert light to heavy /// Faster to edit void flatten(); /// Convert heavy to light /// Uses less memory void shrink(); protected: EdittableChunk(owner, std::istream& str); EdittableChunk(owner, Voxel); /// NOTE: voxels must be allocated by child constructor EdittableChunk(owner); const std::unique_ptr edits; }; }