#pragma once #include "core/math/color.h" #include "core/object/object.h" #include "core/os/semaphore.h" #include "core/os/thread.h" #include "core/variant/callable.h" #include "scene/main/node.h" #include "scene/resources/gradient.h" #include "scene/resources/mesh.h" #include "scene/resources/surface_tool.h" #include "terrain_editor/terrain_chunk.h" #include "terrain_editor/terrain_primitive.h" class TerrainMeshGenerator : public Node { GDCLASS(TerrainMeshGenerator, Node); struct TerrainMeshTask { Ref mesh; Rect2 area; size_t side_points; Ref out_surface; Callable callback; }; static void _bind_methods(); void enter_tree(); void process(); void on_configuration_changed(); protected: void _notification(int what); void rebuild_chunks(); static void background_generation_thread(void *user); Color color_at_height(float height) const; float evaluate_point(Vector2 at) const; void generate_grid(Rect2 area, Ref mesh, size_t side_points); public: void push_task(Rect2 area, Ref mesh, size_t side_points, Callable callback = Callable()); void add_primitive(Ref primitive); void insert_primitive(Ref primitive, int idx); void remove_primitive(Ref primitive); void set_primitives(Array array); Array get_primitives() const; void set_vertex_color_gradient(Ref gradient); Ref get_vertex_color_gradient() const; void set_color_gradient_start_height(float value); float get_color_gradient_start_height() const; void set_color_gradient_end_height(float value); float get_color_gradient_end_height() const; void set_chunk_count(int num); int get_chunk_count() const; void set_chunk_scene(Ref scene); Ref get_chunk_scene() const; private: // main thread exclusive data Ref chunk_scene{}; Vector chunks{}; // worker thread owned data Mutex settings_lock{}; // needs to be locked to modify any of the below, worker thread locks while working Array primitives_buffer{}; // main thread buffer for primitives Vector> primitives{}; // work thread buffer for primitives Ref vertex_color_gradient{}; float color_gradient_start_height{ 0.f }; float color_gradient_end_height{ 10.f }; int chunks_per_side{ 10 }; Thread thread{}; Mutex input_lock{}; bool end_thread{ false }; Vector input_queue{}; Semaphore work_signal{}; Mutex output_lock{}; Vector output_queue{}; private: Callable generation_changed{ callable_mp(this, &self_type::on_configuration_changed) }; public: static String const sig_primitives_changed; static String const sig_primitive_list_changed; };