#include "terrain.h" #include "terrain/terrain_chunk.h" #include "terrain/terrain_modifier.h" void Terrain::_bind_methods() {} void Terrain::ready() { construct_chunk_grid(); generate_meshes(); } void Terrain::update_modifier_list() { this->modifiers.clear(); for (Variant var : get_children()) { if (TerrainModifier * mod{ cast_to(var) }) { this->modifiers.push_back(mod); } } } void Terrain::construct_chunk_grid() { size_t const chunks_per_side{ this->side_length / this->chunk_size }; Vector3 const origin{ -(float)chunks_per_side / 2.f * (float)this->chunk_size, 0.f, -(float)chunks_per_side / 2.f * (float)this->chunk_size }; for (size_t y{ 0 }; y < chunks_per_side; ++y) { for (size_t x{ 0 }; x < chunks_per_side; ++x) { TerrainChunkMesh *chunk{ memnew(TerrainChunkMesh) }; chunk->set_size(this->chunk_size); chunk->set_detail(this->detail); chunk->set_terrain(this); chunk->set_position(origin + Vector3{ (float)this->chunk_size * (float)x, 0.f, (float)this->chunk_size * (float)y }); add_child(chunk); chunk->set_owner(this); this->meshes.push_back(chunk); } } } void Terrain::generate_meshes() { for (TerrainChunkMesh *mesh : this->meshes) { mesh->update_mesh(); } } void Terrain::child_entered(Node *node) { if (cast_to(node)) { update_modifier_list(); } } void Terrain::child_exiting(Node *node) { if (TerrainModifier * mod{ cast_to(node) }) { this->modifiers.erase(mod); } } void Terrain::_notification(int what) { switch (what) { default: return; case NOTIFICATION_ENTER_TREE: if (!is_ready()) { connect("child_entered_tree", callable_mp(this, &self_type::child_entered)); connect("child_exiting_tree", callable_mp(this, &self_type::child_exiting)); connect("child_order_changed", callable_mp(this, &self_type::update_modifier_list)); } return; return; case NOTIFICATION_READY: ready(); return; } } float Terrain::height_at(Vector2 world_coordinate) { float height{ 0 }; for (TerrainModifier *mod : this->modifiers) { height = mod->evaluate_at(world_coordinate, height); } return height; }