diff --git a/modules/props/prop_mesher.cpp b/modules/props/prop_mesher.cpp index c791626de..e721c7a6f 100644 --- a/modules/props/prop_mesher.cpp +++ b/modules/props/prop_mesher.cpp @@ -1208,7 +1208,8 @@ void PropMesher::bake_lights(MeshInstance *node, Vector> &ligh for (int i = 0; i < lights.size(); ++i) { Ref light = lights.get(i); - Vector3 lightDir = light->get_world_position() - vertex; + Vector3 light_pos = light->get_world_data_position(); + Vector3 lightDir = light_pos - vertex; float dist2 = lightDir.dot(lightDir); //inverse sqrt diff --git a/modules/terraman/data/terrain_light.cpp b/modules/terraman/data/terrain_light.cpp index 2a634e670..764df2508 100644 --- a/modules/terraman/data/terrain_light.cpp +++ b/modules/terraman/data/terrain_light.cpp @@ -31,22 +31,31 @@ #include "terrain_light.h" -_FORCE_INLINE_ int TerrainLight::get_world_position_x() const { - return _world_position_x; +bool TerrainLight::get_has_owner_chunk() const { + return _has_owner_chunk; } -_FORCE_INLINE_ int TerrainLight::get_world_position_y() const { - return _world_position_y; +void TerrainLight::set_has_owner_chunk(const bool p_value) { + _has_owner_chunk = p_value; } -_FORCE_INLINE_ int TerrainLight::get_world_position_z() const { - return _world_position_z; + +Vector2i TerrainLight::get_owner_chunk_position() const { + return _owner_chunk_position; } -Vector3 TerrainLight::get_world_position() { - return Vector3(_world_position_x, _world_position_y, _world_position_z); +void TerrainLight::set_owner_chunk_position(const Vector2i &p_owner_chunk_position) { + _owner_chunk_position = p_owner_chunk_position; } -void TerrainLight::set_world_position(const int x, const int y, const int z) { - _world_position_x = x; - _world_position_y = y; - _world_position_z = z; + +Vector3i TerrainLight::get_world_data_position() const { + return _world_data_position; +} +void TerrainLight::set_world_data_position(const Vector3i &p_world_data_position) { + if (_world_data_position == p_world_data_position) { + return; + } + + _world_data_position = p_world_data_position; + + emit_signal("light_moved", Ref(this)); } real_t TerrainLight::get_range() const { @@ -98,17 +107,6 @@ void TerrainLight::set_specular(const real_t value) { _specular = value; } -#ifndef DISABLE_DEPRECATED -bool TerrainLight::_set(const StringName &p_name, const Variant &p_value) { - // Convert to range - if (p_name == "light_size") { - set_range(p_value); - } - - return false; -} -#endif - TerrainLight::TerrainLight() { _range = 0; _attenuation = 0; @@ -122,10 +120,19 @@ TerrainLight::~TerrainLight() { } void TerrainLight::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_world_position_x"), &TerrainLight::get_world_position_x); - ClassDB::bind_method(D_METHOD("get_world_position_y"), &TerrainLight::get_world_position_y); - ClassDB::bind_method(D_METHOD("get_world_position_z"), &TerrainLight::get_world_position_z); - ClassDB::bind_method(D_METHOD("set_world_position", "x", "y", "z"), &TerrainLight::set_world_position); + ADD_SIGNAL(MethodInfo("light_moved", PropertyInfo(Variant::OBJECT, "light", PROPERTY_HINT_RESOURCE_TYPE, "TerrainLight"))); + + ClassDB::bind_method(D_METHOD("get_has_owner_chunk"), &TerrainLight::get_has_owner_chunk); + ClassDB::bind_method(D_METHOD("set_has_owner_chunk", "value"), &TerrainLight::set_has_owner_chunk); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "has_owner_chunk"), "set_has_owner_chunk", "get_has_owner_chunk"); + + ClassDB::bind_method(D_METHOD("get_owner_chunk_position"), &TerrainLight::get_owner_chunk_position); + ClassDB::bind_method(D_METHOD("set_owner_chunk_position", "world_data_position"), &TerrainLight::set_owner_chunk_position); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "owner_chunk_position"), "set_owner_chunk_position", "get_owner_chunk_position"); + + ClassDB::bind_method(D_METHOD("get_world_data_position"), &TerrainLight::get_world_data_position); + ClassDB::bind_method(D_METHOD("set_world_data_position", "world_data_position"), &TerrainLight::set_world_data_position); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3I, "world_data_position"), "set_world_data_position", "get_world_data_position"); ClassDB::bind_method(D_METHOD("get_range"), &TerrainLight::get_range); ClassDB::bind_method(D_METHOD("set_range", "value"), &TerrainLight::set_range); diff --git a/modules/terraman/data/terrain_light.h b/modules/terraman/data/terrain_light.h index 62f54f26e..90fd4e871 100644 --- a/modules/terraman/data/terrain_light.h +++ b/modules/terraman/data/terrain_light.h @@ -40,14 +40,14 @@ class TerrainLight : public Reference { GDCLASS(TerrainLight, Reference); public: - int get_world_position_x() const; - int get_world_position_y() const; - int get_world_position_z() const; - Vector3 get_world_position(); - void set_world_position(const int x, const int y, const int z); + bool get_has_owner_chunk() const; + void set_has_owner_chunk(const bool p_value); - Vector3 get_position(); - void set_position(const Vector3 &pos); + Vector2i get_owner_chunk_position() const; + void set_owner_chunk_position(const Vector2i &p_owner_chunk_position); + + Vector3i get_world_data_position() const; + void set_world_data_position(const Vector3i &p_world_data_position); real_t get_range() const; void set_range(const real_t value); @@ -74,20 +74,13 @@ public: ~TerrainLight(); private: -#ifndef DISABLE_DEPRECATED - bool _set(const StringName &p_name, const Variant &p_value); -#endif - static void _bind_methods(); private: - int _chunk_position_x; - int _chunk_position_y; - int _chunk_position_z; + bool _has_owner_chunk; + Vector2i _owner_chunk_position; - int _world_position_x; - int _world_position_y; - int _world_position_z; + Vector3i _world_data_position; real_t _range; real_t _attenuation; diff --git a/modules/terraman/meshers/terrain_mesher.cpp b/modules/terraman/meshers/terrain_mesher.cpp index 39601bff1..8417fa8fc 100644 --- a/modules/terraman/meshers/terrain_mesher.cpp +++ b/modules/terraman/meshers/terrain_mesher.cpp @@ -626,7 +626,8 @@ void TerrainMesher::bake_lights(MeshInstance *node, Vector> &l for (int i = 0; i < lights.size(); ++i) { Ref light = lights.get(i); - Vector3 lightDir = light->get_world_position() - vertex; + Vector3 light_world_position = light->get_world_data_position(); + Vector3 lightDir = light_world_position - vertex; float dist2 = lightDir.dot(lightDir); //inverse sqrt diff --git a/modules/terraman/world/default/terrain_chunk_default.cpp b/modules/terraman/world/default/terrain_chunk_default.cpp index 698a980ea..f1f477770 100644 --- a/modules/terraman/world/default/terrain_chunk_default.cpp +++ b/modules/terraman/world/default/terrain_chunk_default.cpp @@ -679,8 +679,10 @@ void TerrainChunkDefault::draw_debug_voxel_lights() { for (int i = 0; i < _lights.size(); ++i) { Ref v = _lights[i]; - int pos_x = v->get_world_position_x() - (_size_x * _position_x); - int pos_z = v->get_world_position_z() - (_size_z * _position_z); + Vector3i light_pos = v->get_world_data_position(); + + int pos_x = light_pos.x - (_size_x * _position_x); + int pos_z = light_pos.z - (_size_z * _position_z); draw_cross_voxels_fill(Vector3(pos_x, 0, pos_z), 1.0); } @@ -760,9 +762,11 @@ void TerrainChunkDefault::_bake_light(Ref light) { Color color = light->get_color(); int size = light->get_range(); - int local_x = light->get_world_position_x() - (_position_x * _size_x); - int local_y = light->get_world_position_y(); - int local_z = light->get_world_position_z() - (_position_z * _size_z); + Vector3i light_pos = light->get_world_data_position(); + + int local_x = light_pos.x - (_position_x * _size_x); + int local_y = light_pos.y; + int local_z = light_pos.z - (_position_z * _size_z); ERR_FAIL_COND(size < 0); diff --git a/modules/terraman/world/terrain_chunk.cpp b/modules/terraman/world/terrain_chunk.cpp index d8228e3b1..b27f00c13 100644 --- a/modules/terraman/world/terrain_chunk.cpp +++ b/modules/terraman/world/terrain_chunk.cpp @@ -661,6 +661,113 @@ _FORCE_INLINE_ int TerrainChunk::get_data_size() const { return _data_size_x * _data_size_z; } +//Lights +void TerrainChunk::light_add(Ref p_light) { + if (!p_light.is_valid()) { + return; + } + + p_light->set_has_owner_chunk(true); + p_light->set_owner_chunk_position(Vector2i(_position_x, _position_z)); + p_light->connect("light_moved", this, "_on_light_moved"); + + _lights.push_back(p_light); + + TerrainWorld *world = get_voxel_world(); + + if (ObjectDB::instance_validate(world)) { + world->world_light_added(p_light); + } +} +bool TerrainChunk::light_remove(Ref p_light) { + if (!p_light.is_valid()) { + return false; + } + + if (_lights.erase(p_light)) { + p_light->set_has_owner_chunk(false); + p_light->disconnect("light_moved", this, "_on_light_moved"); + + TerrainWorld *world = get_voxel_world(); + + if (ObjectDB::instance_validate(world)) { + world->world_light_removed(p_light); + } + + return true; + } + + return false; +} + +bool TerrainChunk::light_has(const Ref &p_light) { + return _lights.find(p_light) != -1; +} + +Ref TerrainChunk::light_get_index(const int index) { + ERR_FAIL_INDEX_V(index, _lights.size(), Ref()); + + return _lights.get(index); +} +void TerrainChunk::light_remove_index(const int index) { + ERR_FAIL_INDEX(index, _lights.size()); + + Ref light = _lights[index]; + + TerrainWorld *world = get_voxel_world(); + + if (ObjectDB::instance_validate(world)) { + world->world_light_removed(light); + } +} +int TerrainChunk::light_get_count() const { + return _lights.size(); +} +void TerrainChunk::lights_clear() { + TerrainWorld *world = get_voxel_world(); + + if (!ObjectDB::instance_validate(world)) { + world = NULL; + } + + for (int i = 0; i < _lights.size(); ++i) { + Ref light = _lights[i]; + + if (!light.is_valid()) { + continue; + } + + light->set_has_owner_chunk(false); + + if (world) { + world->world_light_removed(light); + } + } + + _lights.clear(); +} + +Vector TerrainChunk::lights_get() { + VARIANT_ARRAY_GET(_lights); +} +void TerrainChunk::lights_set(const Vector &chunks) { + lights_clear(); + + for (int i = 0; i < chunks.size(); ++i) { + Ref light = Ref(chunks[i]); + + light_add(light); + } +} + +void TerrainChunk::_on_light_moved(const Ref &p_light) { + TerrainWorld *world = get_voxel_world(); + + if (ObjectDB::instance_validate(world)) { + world->world_light_moved(p_light); + } +} + //Terra Structures Ref TerrainChunk::voxel_structure_get(const int index) const { @@ -1295,6 +1402,8 @@ TerrainChunk::~TerrainChunk() { _colliders.clear(); _jobs.clear(); + + _lights.clear(); } void TerrainChunk::_enter_tree() { @@ -1654,6 +1763,23 @@ void TerrainChunk::_bind_methods() { ClassDB::bind_method(D_METHOD("get_data_index", "x", "z"), &TerrainChunk::get_data_index); ClassDB::bind_method(D_METHOD("get_data_size"), &TerrainChunk::get_data_size); + // Lights + ClassDB::bind_method(D_METHOD("light_add", "light"), &TerrainChunk::light_add); + ClassDB::bind_method(D_METHOD("light_remove", "light"), &TerrainChunk::light_remove); + ClassDB::bind_method(D_METHOD("light_has", "light"), &TerrainChunk::light_has); + + ClassDB::bind_method(D_METHOD("light_get_index", "index"), &TerrainChunk::light_get_index); + ClassDB::bind_method(D_METHOD("light_remove_index", "index"), &TerrainChunk::light_remove_index); + ClassDB::bind_method(D_METHOD("light_get_count"), &TerrainChunk::light_get_count); + ClassDB::bind_method(D_METHOD("lights_clear"), &TerrainChunk::lights_clear); + + ClassDB::bind_method(D_METHOD("lights_get"), &TerrainChunk::lights_get); + ClassDB::bind_method(D_METHOD("lights_set", "chunks"), &TerrainChunk::lights_set); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lights", PROPERTY_HINT_NONE, "23/20:TerrainLight", PROPERTY_USAGE_DEFAULT, "TerrainLight"), "lights_set", "lights_get"); + + ClassDB::bind_method(D_METHOD("_on_light_moved"), &TerrainChunk::_on_light_moved); + + // Structures ClassDB::bind_method(D_METHOD("voxel_structure_get", "index"), &TerrainChunk::voxel_structure_get); ClassDB::bind_method(D_METHOD("voxel_structure_add", "structure"), &TerrainChunk::voxel_structure_add); ClassDB::bind_method(D_METHOD("voxel_structure_remove", "structure"), &TerrainChunk::voxel_structure_remove); diff --git a/modules/terraman/world/terrain_chunk.h b/modules/terraman/world/terrain_chunk.h index 4564529a6..a7b29f3ad 100644 --- a/modules/terraman/world/terrain_chunk.h +++ b/modules/terraman/world/terrain_chunk.h @@ -217,6 +217,21 @@ public: int get_data_index(const int x, const int z) const; int get_data_size() const; + //Lights + void light_add(Ref p_light); + bool light_remove(Ref p_light); + bool light_has(const Ref &p_light); + + Ref light_get_index(const int index); + void light_remove_index(const int index); + int light_get_count() const; + void lights_clear(); + + Vector lights_get(); + void lights_set(const Vector &chunks); + + void _on_light_moved(const Ref &p_light); + //Terra Structures Ref voxel_structure_get(const int index) const; void voxel_structure_add(const Ref &structure); @@ -421,6 +436,8 @@ protected: Ref _library; + Vector> _lights; + Vector> _voxel_structures; #ifdef MODULE_PROPS_ENABLED diff --git a/modules/terraman/world/terrain_world.cpp b/modules/terraman/world/terrain_world.cpp index 2895706a6..92a63c319 100644 --- a/modules/terraman/world/terrain_world.cpp +++ b/modules/terraman/world/terrain_world.cpp @@ -650,7 +650,7 @@ void TerrainWorld::prop_add(Transform transform, const Ref &prop, cons Ref light; light.instance(); - light->set_world_position(wp.x / get_voxel_scale(), wp.y / get_voxel_scale(), wp.z / get_voxel_scale()); + light->set_world_data_position(Vector3i(wp.x / get_voxel_scale(), wp.y / get_voxel_scale(), wp.z / get_voxel_scale())); light->set_range(light_data->get_light_range()); light->set_attenuation(light_data->get_light_attenuation()); light->set_color(light_data->get_light_color()); @@ -691,8 +691,44 @@ void TerrainWorld::prop_add(Transform transform, const Ref &prop, cons //Lights void TerrainWorld::light_add(const Ref &light) { - _lights.push_back(light); + if (!light.is_valid()) { + return; + } + Vector3i light_world_data_position = light->get_world_data_position(); + + Ref chunk = get_or_create_chunk_at_world_data_position(Vector2i(light_world_data_position.x, light_world_data_position.z)); + + ERR_FAIL_COND(!chunk.is_valid()); + + chunk->light_add(light); +} +void TerrainWorld::light_remove(const Ref &light) { + if (!light.is_valid()) { + return; + } + + Vector3i light_world_data_position = light->get_world_data_position(); + + Ref chunk = get_chunk_at_world_data_position(Vector2i(light_world_data_position.x, light_world_data_position.z)); + + if (!chunk.is_valid()) { + return; + } + + chunk->light_remove(light); +} +void TerrainWorld::lights_clear() { + for (int i = 0; i < _chunks_vector.size(); ++i) { + Ref chunk = _chunks_vector[i]; + + if (chunk.is_valid()) { + chunk->lights_clear(); + } + } +} + +void TerrainWorld::world_light_added(const Ref &light) { for (int i = 0; i < _chunks_vector.size(); ++i) { Ref chunk = _chunks_vector[i]; @@ -701,16 +737,7 @@ void TerrainWorld::light_add(const Ref &light) { } } } -Ref TerrainWorld::light_get(const int index) { - ERR_FAIL_INDEX_V(index, _lights.size(), Ref()); - - return _lights.get(index); -} -void TerrainWorld::light_remove(const int index) { - ERR_FAIL_INDEX(index, _lights.size()); - - Ref light = _lights[index]; - +void TerrainWorld::world_light_removed(const Ref &light) { for (int i = 0; i < _chunks_vector.size(); ++i) { Ref chunk = _chunks_vector[i]; @@ -719,40 +746,10 @@ void TerrainWorld::light_remove(const int index) { } } } -int TerrainWorld::light_get_count() const { - return _lights.size(); -} -void TerrainWorld::lights_clear() { - for (int i = 0; i < _lights.size(); ++i) { - Ref light = _lights[i]; - - if (!light.is_valid()) { - continue; - } - - for (int j = 0; j < _chunks_vector.size(); ++j) { - Ref chunk = _chunks_vector[j]; - - if (chunk.is_valid()) { - chunk->world_light_removed(light); - } - } - } - - _lights.clear(); -} - -Vector TerrainWorld::lights_get() { - VARIANT_ARRAY_GET(_lights); -} -void TerrainWorld::lights_set(const Vector &chunks) { - lights_clear(); - - for (int i = 0; i < chunks.size(); ++i) { - Ref light = Ref(chunks[i]); - - light_add(light); - } +void TerrainWorld::world_light_moved(const Ref &light) { + // TODO better implementation + light_remove(light); + light_add(light); } uint8_t TerrainWorld::get_voxel_at_world_position(const Vector3 &world_position, const int channel_index) { @@ -1281,8 +1278,6 @@ TerrainWorld ::~TerrainWorld() { _generation_queue.clear(); _generating.clear(); - - _lights.clear(); } void TerrainWorld::_generate_chunk(Ref chunk) { @@ -1583,15 +1578,10 @@ void TerrainWorld::_bind_methods() { #endif //Lights - ClassDB::bind_method(D_METHOD("light_add", "light"), &TerrainWorld::light_add); - ClassDB::bind_method(D_METHOD("light_get", "index"), &TerrainWorld::light_get); - ClassDB::bind_method(D_METHOD("light_remove", "index"), &TerrainWorld::light_remove); - ClassDB::bind_method(D_METHOD("light_get_count"), &TerrainWorld::light_get_count); + ClassDB::bind_method(D_METHOD("light_add", "chunk"), &TerrainWorld::light_add); + ClassDB::bind_method(D_METHOD("light_remove", "chunk"), &TerrainWorld::light_remove); ClassDB::bind_method(D_METHOD("lights_clear"), &TerrainWorld::lights_clear); - ClassDB::bind_method(D_METHOD("lights_get"), &TerrainWorld::lights_get); - ClassDB::bind_method(D_METHOD("lights_set", "chunks"), &TerrainWorld::lights_set); - ClassDB::bind_method(D_METHOD("get_voxel_at_world_position", "world_position", "channel_index"), &TerrainWorld::get_voxel_at_world_position); ClassDB::bind_method(D_METHOD("set_voxel_at_world_position", "world_position", "data", "channel_index", "rebuild"), &TerrainWorld::set_voxel_at_world_position, DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_chunk_at_world_position", "world_position"), &TerrainWorld::get_chunk_at_world_position); diff --git a/modules/terraman/world/terrain_world.h b/modules/terraman/world/terrain_world.h index 6af2dd5cc..8a850cf27 100644 --- a/modules/terraman/world/terrain_world.h +++ b/modules/terraman/world/terrain_world.h @@ -181,13 +181,12 @@ public: //Lights void light_add(const Ref &light); - Ref light_get(const int index); - void light_remove(const int index); - int light_get_count() const; + void light_remove(const Ref &light); void lights_clear(); - Vector lights_get(); - void lights_set(const Vector &chunks); + void world_light_added(const Ref &light); + void world_light_removed(const Ref &light); + void world_light_moved(const Ref &light); //Helpers uint8_t get_voxel_at_world_position(const Vector3 &world_position, const int channel_index); @@ -281,8 +280,6 @@ private: Vector> _generating; int _max_frame_chunk_build_steps; int _num_frame_chunk_build_steps; - - Vector> _lights; }; _FORCE_INLINE_ bool operator==(const TerrainWorld::IntPos &a, const TerrainWorld::IntPos &b) {