2016-05-09 16:59:54 -07:00
|
|
|
#ifndef VOXEL_MAP_H
|
|
|
|
#define VOXEL_MAP_H
|
|
|
|
|
2020-01-04 11:20:49 -08:00
|
|
|
#include "../util/fixed_array.h"
|
2019-01-01 08:44:19 -08:00
|
|
|
#include "voxel_block.h"
|
2017-08-20 06:48:55 -07:00
|
|
|
|
2016-05-09 16:59:54 -07:00
|
|
|
#include <core/hash_map.h>
|
2017-08-12 16:19:39 -07:00
|
|
|
#include <scene/main/node.h>
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2020-08-29 14:09:54 -07:00
|
|
|
// Infinite voxel storage by means of octants like Gridmap, within a constant LOD.
|
|
|
|
// Convenience functions to access VoxelBuffers internally will lock them to protect against multithreaded access.
|
|
|
|
// However, the map itself is not thread-safe.
|
2020-11-21 10:28:06 -08:00
|
|
|
class VoxelMap {
|
2016-05-09 16:59:54 -07:00
|
|
|
public:
|
2018-09-24 16:54:07 -07:00
|
|
|
// Converts voxel coodinates into block coordinates.
|
|
|
|
// Don't use division because it introduces an offset in negative coordinates.
|
|
|
|
static _FORCE_INLINE_ Vector3i voxel_to_block_b(Vector3i pos, int block_size_pow2) {
|
2019-09-03 14:54:40 -07:00
|
|
|
return pos >> block_size_pow2;
|
2018-09-24 16:54:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
_FORCE_INLINE_ Vector3i voxel_to_block(Vector3i pos) const {
|
|
|
|
return voxel_to_block_b(pos, _block_size_pow2);
|
2016-12-31 19:40:16 -08:00
|
|
|
}
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2017-08-20 06:17:54 -07:00
|
|
|
_FORCE_INLINE_ Vector3i to_local(Vector3i pos) const {
|
2017-03-29 13:36:42 -07:00
|
|
|
return Vector3i(
|
2017-08-20 06:17:54 -07:00
|
|
|
pos.x & _block_size_mask,
|
|
|
|
pos.y & _block_size_mask,
|
|
|
|
pos.z & _block_size_mask);
|
2017-03-29 13:36:42 -07:00
|
|
|
}
|
|
|
|
|
2016-12-31 19:40:16 -08:00
|
|
|
// Converts block coodinates into voxel coordinates
|
2017-08-20 06:17:54 -07:00
|
|
|
_FORCE_INLINE_ Vector3i block_to_voxel(Vector3i bpos) const {
|
|
|
|
return bpos * _block_size;
|
2016-12-31 19:40:16 -08:00
|
|
|
}
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2017-01-02 17:50:19 -08:00
|
|
|
VoxelMap();
|
|
|
|
~VoxelMap();
|
|
|
|
|
2019-08-23 17:44:27 -07:00
|
|
|
void create(unsigned int block_size_po2, int lod_index);
|
|
|
|
|
2017-08-20 06:17:54 -07:00
|
|
|
_FORCE_INLINE_ unsigned int get_block_size() const { return _block_size; }
|
|
|
|
_FORCE_INLINE_ unsigned int get_block_size_pow2() const { return _block_size_pow2; }
|
|
|
|
_FORCE_INLINE_ unsigned int get_block_size_mask() const { return _block_size_mask; }
|
|
|
|
|
2019-08-23 17:44:27 -07:00
|
|
|
void set_lod_index(int lod_index);
|
2019-05-03 16:02:10 -07:00
|
|
|
unsigned int get_lod_index() const;
|
|
|
|
|
2019-09-03 14:54:40 -07:00
|
|
|
int get_voxel(Vector3i pos, unsigned int c = 0) const;
|
2017-01-02 17:50:19 -08:00
|
|
|
void set_voxel(int value, Vector3i pos, unsigned int c = 0);
|
|
|
|
|
2020-01-02 13:03:44 -08:00
|
|
|
float get_voxel_f(Vector3i pos, unsigned int c = VoxelBuffer::CHANNEL_SDF) const;
|
|
|
|
void set_voxel_f(real_t value, Vector3i pos, unsigned int c = VoxelBuffer::CHANNEL_SDF);
|
2019-04-27 16:25:33 -07:00
|
|
|
|
2017-08-12 16:19:39 -07:00
|
|
|
void set_default_voxel(int value, unsigned int channel = 0);
|
|
|
|
int get_default_voxel(unsigned int channel = 0);
|
2017-01-02 17:50:19 -08:00
|
|
|
|
2016-12-31 19:40:16 -08:00
|
|
|
// Gets a copy of all voxels in the area starting at min_pos having the same size as dst_buffer.
|
2017-08-12 16:19:39 -07:00
|
|
|
void get_buffer_copy(Vector3i min_pos, VoxelBuffer &dst_buffer, unsigned int channels_mask = 1);
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2016-12-31 19:40:16 -08:00
|
|
|
// Moves the given buffer into a block of the map. The buffer is referenced, no copy is made.
|
2019-05-08 12:53:51 -07:00
|
|
|
VoxelBlock *set_block_buffer(Vector3i bpos, Ref<VoxelBuffer> buffer);
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2017-08-27 16:47:38 -07:00
|
|
|
struct NoAction {
|
|
|
|
inline void operator()(VoxelBlock *block) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Action_T>
|
|
|
|
void remove_block(Vector3i bpos, Action_T pre_delete) {
|
2019-05-27 16:40:09 -07:00
|
|
|
if (_last_accessed_block && _last_accessed_block->position == bpos) {
|
2020-07-25 15:19:08 -07:00
|
|
|
_last_accessed_block = nullptr;
|
2019-05-27 16:40:09 -07:00
|
|
|
}
|
2020-10-31 20:25:48 -07:00
|
|
|
unsigned int *iptr = _blocks_map.getptr(bpos);
|
|
|
|
if (iptr != nullptr) {
|
|
|
|
const unsigned int i = *iptr;
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
|
|
CRASH_COND(i >= _blocks.size());
|
|
|
|
#endif
|
|
|
|
VoxelBlock *block = _blocks[i];
|
2020-07-25 15:19:08 -07:00
|
|
|
ERR_FAIL_COND(block == nullptr);
|
2017-08-27 16:47:38 -07:00
|
|
|
pre_delete(block);
|
|
|
|
memdelete(block);
|
2020-10-31 20:25:48 -07:00
|
|
|
remove_block_internal(bpos, i);
|
2017-08-27 16:47:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-12 16:19:39 -07:00
|
|
|
VoxelBlock *get_block(Vector3i bpos);
|
2019-05-03 16:02:10 -07:00
|
|
|
const VoxelBlock *get_block(Vector3i bpos) const;
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2016-12-31 19:40:16 -08:00
|
|
|
bool has_block(Vector3i pos) const;
|
|
|
|
bool is_block_surrounded(Vector3i pos) const;
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2017-01-02 17:50:19 -08:00
|
|
|
void clear();
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2019-05-08 12:53:51 -07:00
|
|
|
int get_block_count() const;
|
|
|
|
|
2020-11-21 10:28:06 -08:00
|
|
|
// TODO Rename for_each_block
|
2017-08-27 17:32:23 -07:00
|
|
|
template <typename Op_T>
|
2020-10-31 20:25:48 -07:00
|
|
|
inline void for_all_blocks(Op_T op) {
|
|
|
|
for (auto it = _blocks.begin(); it != _blocks.end(); ++it) {
|
|
|
|
op(*it);
|
2017-08-27 17:32:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-21 10:28:06 -08:00
|
|
|
// TODO Rename for_each_block
|
|
|
|
template <typename Op_T>
|
|
|
|
inline void for_all_blocks(Op_T op) const {
|
|
|
|
for (auto it = _blocks.begin(); it != _blocks.end(); ++it) {
|
|
|
|
op(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-06 15:24:56 -07:00
|
|
|
bool is_area_fully_loaded(const Rect3i voxels_box) const;
|
|
|
|
|
2016-05-09 16:59:54 -07:00
|
|
|
private:
|
2017-08-12 16:19:39 -07:00
|
|
|
void set_block(Vector3i bpos, VoxelBlock *block);
|
2019-04-27 16:25:33 -07:00
|
|
|
VoxelBlock *get_or_create_block_at_voxel_pos(Vector3i pos);
|
2020-10-31 20:25:48 -07:00
|
|
|
void remove_block_internal(Vector3i bpos, unsigned int index);
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2017-08-20 06:17:54 -07:00
|
|
|
void set_block_size_pow2(unsigned int p);
|
2016-05-09 16:59:54 -07:00
|
|
|
|
2017-01-01 17:19:02 -08:00
|
|
|
private:
|
|
|
|
// Voxel values that will be returned if access is out of map bounds
|
2020-01-04 11:20:49 -08:00
|
|
|
FixedArray<uint64_t, VoxelBuffer::MAX_CHANNELS> _default_voxel;
|
2017-01-01 17:19:02 -08:00
|
|
|
|
|
|
|
// Blocks stored with a spatial hash in all 3D directions
|
2020-10-31 20:25:48 -07:00
|
|
|
HashMap<Vector3i, unsigned int, Vector3iHasher> _blocks_map;
|
|
|
|
std::vector<VoxelBlock *> _blocks;
|
2017-01-01 17:19:02 -08:00
|
|
|
|
|
|
|
// Voxel access will most frequently be in contiguous areas, so the same blocks are accessed.
|
|
|
|
// To prevent too much hashing, this reference is checked before.
|
2019-09-03 14:54:40 -07:00
|
|
|
mutable VoxelBlock *_last_accessed_block;
|
2017-08-20 06:17:54 -07:00
|
|
|
|
|
|
|
unsigned int _block_size;
|
|
|
|
unsigned int _block_size_pow2;
|
|
|
|
unsigned int _block_size_mask;
|
2019-05-03 16:02:10 -07:00
|
|
|
|
|
|
|
unsigned int _lod_index = 0;
|
2016-05-09 16:59:54 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // VOXEL_MAP_H
|