2016-05-10 01:59:54 +02:00
|
|
|
#ifndef VOXEL_TERRAIN_H
|
|
|
|
#define VOXEL_TERRAIN_H
|
|
|
|
|
2019-04-24 02:29:47 +02:00
|
|
|
#include "rect3i.h"
|
2018-09-25 01:54:07 +02:00
|
|
|
#include "vector3i.h"
|
2019-04-24 02:29:47 +02:00
|
|
|
#include "voxel_mesh_updater.h"
|
2018-09-25 01:54:07 +02:00
|
|
|
#include "voxel_provider.h"
|
|
|
|
#include "voxel_provider_thread.h"
|
2019-04-24 02:29:47 +02:00
|
|
|
#include "zprofiling.h"
|
2018-09-25 01:54:07 +02:00
|
|
|
|
|
|
|
#include <scene/3d/spatial.h>
|
|
|
|
|
|
|
|
class VoxelMap;
|
|
|
|
class VoxelLibrary;
|
2017-03-26 18:09:37 +02:00
|
|
|
|
2016-05-10 01:59:54 +02:00
|
|
|
// Infinite static terrain made of voxels.
|
|
|
|
// It is loaded around VoxelTerrainStreamers.
|
2019-04-24 02:29:47 +02:00
|
|
|
class VoxelTerrain : public Spatial {
|
2017-08-20 18:37:08 +02:00
|
|
|
GDCLASS(VoxelTerrain, Spatial)
|
2016-05-10 01:59:54 +02:00
|
|
|
public:
|
2018-09-26 02:22:23 +02:00
|
|
|
enum BlockDirtyState {
|
|
|
|
BLOCK_NONE,
|
|
|
|
BLOCK_LOAD,
|
|
|
|
BLOCK_UPDATE_NOT_SENT,
|
|
|
|
BLOCK_UPDATE_SENT,
|
|
|
|
BLOCK_IDLE
|
|
|
|
};
|
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
VoxelTerrain();
|
2018-09-25 01:54:07 +02:00
|
|
|
~VoxelTerrain();
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-02 02:15:57 +01:00
|
|
|
void set_provider(Ref<VoxelProvider> provider);
|
2017-08-15 02:24:52 +02:00
|
|
|
Ref<VoxelProvider> get_provider() const;
|
|
|
|
|
|
|
|
void set_voxel_library(Ref<VoxelLibrary> library);
|
|
|
|
Ref<VoxelLibrary> get_voxel_library() const;
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-03-28 00:56:01 +02:00
|
|
|
void make_block_dirty(Vector3i bpos);
|
2018-09-25 01:54:07 +02:00
|
|
|
//void make_blocks_dirty(Vector3i min, Vector3i size);
|
2017-03-29 22:36:42 +02:00
|
|
|
void make_voxel_dirty(Vector3i pos);
|
2018-10-01 21:48:47 +02:00
|
|
|
void make_area_dirty(Rect3i box);
|
2018-09-25 01:54:07 +02:00
|
|
|
bool is_block_dirty(Vector3i bpos) const;
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-03-26 18:09:37 +02:00
|
|
|
void set_generate_collisions(bool enabled);
|
2017-08-15 02:24:52 +02:00
|
|
|
bool get_generate_collisions() const { return _generate_collisions; }
|
|
|
|
|
|
|
|
int get_view_distance() const;
|
|
|
|
void set_view_distance(int distance_in_voxels);
|
2017-03-26 18:09:37 +02:00
|
|
|
|
2017-03-28 00:56:01 +02:00
|
|
|
void set_viewer_path(NodePath path);
|
2017-08-15 02:24:52 +02:00
|
|
|
NodePath get_viewer_path() const;
|
|
|
|
|
|
|
|
void set_material(int id, Ref<Material> material);
|
|
|
|
Ref<Material> get_material(int id) const;
|
2017-03-28 00:56:01 +02:00
|
|
|
|
2017-01-05 02:39:40 +01:00
|
|
|
Ref<VoxelMap> get_map() { return _map; }
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2018-09-25 01:54:07 +02:00
|
|
|
struct Stats {
|
|
|
|
VoxelMeshUpdater::Stats updater;
|
|
|
|
VoxelProviderThread::Stats provider;
|
|
|
|
uint32_t mesh_alloc_time;
|
2018-09-26 02:22:23 +02:00
|
|
|
int updated_blocks;
|
|
|
|
int dropped_provider_blocks;
|
|
|
|
int dropped_updater_blocks;
|
|
|
|
int remaining_main_thread_blocks;
|
2018-09-29 19:59:19 +02:00
|
|
|
uint64_t time_detect_required_blocks;
|
|
|
|
uint64_t time_send_load_requests;
|
|
|
|
uint64_t time_process_load_responses;
|
|
|
|
uint64_t time_send_update_requests;
|
|
|
|
uint64_t time_process_update_responses;
|
2018-09-26 02:22:23 +02:00
|
|
|
|
2019-04-24 02:29:47 +02:00
|
|
|
Stats() :
|
|
|
|
mesh_alloc_time(0),
|
|
|
|
updated_blocks(0),
|
|
|
|
dropped_provider_blocks(0),
|
|
|
|
dropped_updater_blocks(0),
|
|
|
|
remaining_main_thread_blocks(0),
|
|
|
|
time_detect_required_blocks(0),
|
|
|
|
time_send_load_requests(0),
|
|
|
|
time_process_load_responses(0),
|
|
|
|
time_send_update_requests(0),
|
|
|
|
time_process_update_responses(0) {}
|
2018-09-25 01:54:07 +02:00
|
|
|
};
|
|
|
|
|
2016-05-10 01:59:54 +02:00
|
|
|
protected:
|
2017-01-01 04:40:16 +01:00
|
|
|
void _notification(int p_what);
|
2017-03-28 00:56:01 +02:00
|
|
|
|
|
|
|
private:
|
2017-08-15 02:24:52 +02:00
|
|
|
bool _set(const StringName &p_name, const Variant &p_value);
|
|
|
|
bool _get(const StringName &p_name, Variant &r_ret) const;
|
|
|
|
void _get_property_list(List<PropertyInfo> *p_list) const;
|
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
void _process();
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-08-28 01:47:38 +02:00
|
|
|
void make_all_view_dirty_deferred();
|
2017-08-15 02:24:52 +02:00
|
|
|
|
|
|
|
Spatial *get_viewer(NodePath path) const;
|
2017-03-28 00:56:01 +02:00
|
|
|
|
2017-08-28 01:47:38 +02:00
|
|
|
void immerge_block(Vector3i bpos);
|
|
|
|
|
2018-09-25 01:54:07 +02:00
|
|
|
Dictionary get_statistics() const;
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
static void _bind_methods();
|
2016-05-10 01:59:54 +02:00
|
|
|
|
2017-01-01 04:40:16 +01:00
|
|
|
// Convenience
|
2017-08-20 15:17:54 +02:00
|
|
|
Vector3 _voxel_to_block_binding(Vector3 pos);
|
|
|
|
Vector3 _block_to_voxel_binding(Vector3 pos);
|
2018-09-25 01:54:07 +02:00
|
|
|
//void _force_load_blocks_binding(Vector3 center, Vector3 extents) { force_load_blocks(center, extents); }
|
2017-03-29 22:36:42 +02:00
|
|
|
void _make_voxel_dirty_binding(Vector3 pos) { make_voxel_dirty(pos); }
|
2018-10-01 21:48:47 +02:00
|
|
|
void _make_area_dirty_binding(AABB aabb);
|
2017-03-26 20:07:01 +02:00
|
|
|
Variant _raycast_binding(Vector3 origin, Vector3 direction, real_t max_distance);
|
2017-03-29 22:36:42 +02:00
|
|
|
void set_voxel(Vector3 pos, int value, int c);
|
|
|
|
int get_voxel(Vector3 pos, int c);
|
2018-09-26 02:22:23 +02:00
|
|
|
BlockDirtyState get_block_state(Vector3 p_bpos) const;
|
2018-09-25 01:54:07 +02:00
|
|
|
|
|
|
|
static void remove_positions_outside_box(Vector<Vector3i> &positions, Rect3i box, HashMap<Vector3i, BlockDirtyState, Vector3iHasher> &state_map);
|
|
|
|
|
2017-01-02 02:19:02 +01:00
|
|
|
private:
|
|
|
|
// Voxel storage
|
|
|
|
Ref<VoxelMap> _map;
|
|
|
|
|
2017-08-15 02:24:52 +02:00
|
|
|
// How many blocks to load around the viewer
|
|
|
|
int _view_distance_blocks;
|
|
|
|
|
2017-03-28 00:56:01 +02:00
|
|
|
// TODO Terrains only need to handle the visible portion of voxels, which reduces the bounds blocks to handle.
|
|
|
|
// Therefore, could a simple grid be better to use than a hashmap?
|
|
|
|
|
2018-09-25 01:54:07 +02:00
|
|
|
Vector<Vector3i> _blocks_pending_load;
|
|
|
|
Vector<Vector3i> _blocks_pending_update;
|
2018-09-26 02:22:23 +02:00
|
|
|
HashMap<Vector3i, BlockDirtyState, Vector3iHasher> _dirty_blocks; // TODO Rename _block_states
|
|
|
|
Vector<VoxelMeshUpdater::OutputBlock> _blocks_pending_main_thread_update;
|
2017-04-06 23:44:11 +02:00
|
|
|
|
2017-01-02 02:19:02 +01:00
|
|
|
Ref<VoxelProvider> _provider;
|
2018-09-25 01:54:07 +02:00
|
|
|
VoxelProviderThread *_provider_thread;
|
|
|
|
|
|
|
|
Ref<VoxelLibrary> _library;
|
|
|
|
VoxelMeshUpdater *_block_updater;
|
2017-01-02 02:19:02 +01:00
|
|
|
|
2017-03-28 00:56:01 +02:00
|
|
|
NodePath _viewer_path;
|
2017-08-28 01:47:38 +02:00
|
|
|
Vector3i _last_viewer_block_pos;
|
|
|
|
int _last_view_distance_blocks;
|
2017-03-28 00:56:01 +02:00
|
|
|
|
2017-03-26 18:09:37 +02:00
|
|
|
bool _generate_collisions;
|
2018-09-28 02:10:35 +02:00
|
|
|
bool _run_in_editor;
|
2017-03-26 18:09:37 +02:00
|
|
|
|
2018-09-25 01:54:07 +02:00
|
|
|
Ref<Material> _materials[VoxelMesher::MAX_MATERIALS];
|
|
|
|
|
|
|
|
Stats _stats;
|
2016-05-10 01:59:54 +02:00
|
|
|
};
|
|
|
|
|
2018-09-26 02:22:23 +02:00
|
|
|
VARIANT_ENUM_CAST(VoxelTerrain::BlockDirtyState)
|
|
|
|
|
2016-05-10 01:59:54 +02:00
|
|
|
#endif // VOXEL_TERRAIN_H
|