From 66a2d798b34a64f693fb1a4c602ca2e11563bb29 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sun, 24 Mar 2024 20:57:35 +0100 Subject: [PATCH] Implemented api and data storage for the VertexLights2D singleton. --- doc/classes/@GlobalScope.xml | 2 + doc/classes/ProjectSettings.xml | 2 + .../doc_classes/VertexLights2D.xml | 162 ++++++++++ .../vertex_lights_2d/vertex_light_data.cpp | 93 ++++++ modules/vertex_lights_2d/vertex_light_data.h | 42 ++- modules/vertex_lights_2d/vertex_lights_2d.cpp | 289 ++++++++++++++---- modules/vertex_lights_2d/vertex_lights_2d.h | 61 ++-- 7 files changed, 559 insertions(+), 92 deletions(-) create mode 100644 modules/vertex_lights_2d/doc_classes/VertexLights2D.xml diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 87639d5c7..565cd139a 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -119,6 +119,8 @@ + + diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index e66b6a4a5..7e48abda4 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2121,6 +2121,8 @@ + + Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses (in pixels). diff --git a/modules/vertex_lights_2d/doc_classes/VertexLights2D.xml b/modules/vertex_lights_2d/doc_classes/VertexLights2D.xml new file mode 100644 index 000000000..03debc813 --- /dev/null +++ b/modules/vertex_lights_2d/doc_classes/VertexLights2D.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/vertex_lights_2d/vertex_light_data.cpp b/modules/vertex_lights_2d/vertex_light_data.cpp index 95cef854e..0c72bd226 100644 --- a/modules/vertex_lights_2d/vertex_light_data.cpp +++ b/modules/vertex_lights_2d/vertex_light_data.cpp @@ -31,3 +31,96 @@ #include "vertex_light_data.h" +//VertexLightQuadrant2D + +void VertexLightQuadrant2D::get_lights(List *p_lights) { + for (uint32_t i = 0; i < lights.size(); ++i) { + p_lights->push_back(lights[i]); + } +} + +//VertexLightMap2D + +void VertexLightMap2D::recreate_quadrants() { + List lights; + get_lights(&lights); + + for (HashMap::Element *E = quadrants.front(); E; E = E->next) { + memdelete(E->value()); + } + + quadrants.clear(); + + for (List::Element *E = lights.front(); E; E = E->next()) { + VertexLightData2D *l = E->get(); + add_light(l); + } +} + +void VertexLightMap2D::get_lights(List *p_lights) { + for (HashMap::Element *E = quadrants.front(); E; E = E->next) { + E->value()->get_lights(p_lights); + } +} + +void VertexLightMap2D::add_light(VertexLightData2D *p_light) { + VertexLightQuadrant2D *quadrant = get_quadrant_for_position(p_light->position); + + p_light->map = this; + p_light->quadrant = quadrant; + + quadrant->lights.push_back(p_light); +} +void VertexLightMap2D::remove_light(VertexLightData2D *p_light) { + p_light->map = NULL; + + VertexLightQuadrant2D *quadrant = p_light->quadrant; + + // Quadrant wan not updated properly somewhere! + ERR_FAIL_NULL(quadrant); + + quadrant->lights.erase(p_light); + p_light->quadrant = NULL; + + if (quadrant->lights.size() == 0) { + quadrants.erase(quadrant->position); + + memdelete(quadrant); + } +} + +VertexLightQuadrant2D *VertexLightMap2D::get_quadrant_for_position(const Vector2 &p_position) { + Vector2i quadrant_position = to_quadrant_position(p_position); + + if (!quadrants.has(quadrant_position)) { + VertexLightQuadrant2D *quadrant = memnew(VertexLightQuadrant2D); + quadrant->position = quadrant_position; + quadrants[quadrant_position] = quadrant; + return quadrant; + } + + return quadrants[quadrant_position]; +} + +void VertexLightMap2D::set_light_position(VertexLightData2D *p_light, const Vector2 &p_position) { + remove_light(p_light); + add_light(p_light); +} + +void VertexLightMap2D::clear() { + List lights; + get_lights(&lights); + + for (HashMap::Element *E = quadrants.front(); E; E = E->next) { + memdelete(E->value()); + } + + quadrants.clear(); + + for (List::Element *E = lights.front(); E; E = E->next()) { + VertexLightData2D *l = E->get(); + + l->map = NULL; + l->quadrant = NULL; + } +} diff --git a/modules/vertex_lights_2d/vertex_light_data.h b/modules/vertex_lights_2d/vertex_light_data.h index b3fca57ea..d74f41df2 100644 --- a/modules/vertex_lights_2d/vertex_light_data.h +++ b/modules/vertex_lights_2d/vertex_light_data.h @@ -33,6 +33,7 @@ /*************************************************************************/ #include "core/containers/hash_map.h" +#include "core/containers/list.h" #include "core/containers/rid.h" #include "core/containers/vector.h" #include "core/math/color.h" @@ -52,23 +53,31 @@ public: Vector2i z_range; Vector2i layer_range; int item_cull_mask; - + VertexLightMap2D *map; VertexLightQuadrant2D *quadrant; + RID self; + VertexLightData2D() { - item_cull_mask = 1; map = NULL; quadrant = NULL; + + item_cull_mask = 1; + z_range = Vector2i(-1024, 1024); + mode = VertexLights2D::VERTEX_LIGHT_2D_MODE_ADD; } }; -class VertexLightQuadrant2D : public RID_Data { +class VertexLightQuadrant2D { public: + Vector2i position; LocalVector lights; - + VertexLightMap2D *map; - + + void get_lights(List *p_lights); + VertexLightQuadrant2D() { map = NULL; } @@ -78,6 +87,29 @@ class VertexLightMap2D : public RID_Data { public: HashMap quadrants; Vector2i quadrant_size; + + RID self; + + void recreate_quadrants(); + + void get_lights(List *p_lights); + + void add_light(VertexLightData2D *p_light); + void remove_light(VertexLightData2D *p_light); + + VertexLightQuadrant2D *get_quadrant_for_position(const Vector2 &p_position); + + void set_light_position(VertexLightData2D *p_light, const Vector2 &p_position); + + void clear(); + + _FORCE_INLINE_ Vector2i to_quadrant_position(const Vector2 &p_position) { + return Vector2i(p_position.x / quadrant_size.x, p_position.y / quadrant_size.y); + } + + _FORCE_INLINE_ Vector2 to_position(const Vector2i &p_quadrant_position) { + return Vector2(p_quadrant_position.x * quadrant_size.x, p_quadrant_position.y * quadrant_size.y); + } }; #endif diff --git a/modules/vertex_lights_2d/vertex_lights_2d.cpp b/modules/vertex_lights_2d/vertex_lights_2d.cpp index fba721fc7..abeb777b1 100644 --- a/modules/vertex_lights_2d/vertex_lights_2d.cpp +++ b/modules/vertex_lights_2d/vertex_lights_2d.cpp @@ -35,69 +35,217 @@ #include "vertex_light_data.h" -/* -Transform VertexLights2D::get_transform() const { - return _transform; +// Defaults +Vector2i VertexLights2D::get_default_quadrant_size() const { + return _default_quadrant_size; } -void VertexLights2D::set_transform(const Transform &p_transform) { - _transform = p_transform; +void VertexLights2D::set_default_quadrant_size(const Vector2i &p_size) { + _default_quadrant_size = p_size; } -real_t VertexLights2D::get_range() const { - return _range; -} -void VertexLights2D::set_range(const real_t value) { - _range = value; +// Maps +RID VertexLights2D::map_create() { + VertexLightMap2D *map = memnew(VertexLightMap2D); + RID rid = map_owner.make_rid(map); + map->self = rid; + return rid; } -real_t VertexLights2D::get_attenuation() const { - return _attenuation; +Vector2i VertexLights2D::map_get_quadrant_size(RID p_map) const { + const VertexLightMap2D *map = map_owner.getornull(p_map); + ERR_FAIL_COND_V(map == NULL, Vector2i()); + + return map->quadrant_size; } -void VertexLights2D::set_attenuation(const real_t value) { - _attenuation = value; +void VertexLights2D::map_set_quadrant_size(RID p_map, const Vector2i &p_size) { + VertexLightMap2D *map = map_owner.getornull(p_map); + ERR_FAIL_COND(map == NULL); + + map->quadrant_size = p_size; + map->recreate_quadrants(); } -Color VertexLights2D::get_color() const { - return _color; -} -void VertexLights2D::set_color(const Color value) { - _color = value; +Array VertexLights2D::map_get_lights(RID p_map) const { + VertexLightMap2D *map = map_owner.getornull(p_map); + ERR_FAIL_COND_V(map == NULL, Array()); + + List lights; + map->get_lights(&lights); + + Array arr; + + arr.resize(lights.size()); + + int i = 0; + for (List::Element *E = lights.front(); E; E = E->next()) { + arr[i++] = E->get()->self; + } + + return arr; } -real_t VertexLights2D::get_energy() const { - return _energy; -} -void VertexLights2D::set_energy(const real_t value) { - _energy = value; +void VertexLights2D::map_clear(RID p_map) { + VertexLightMap2D *map = map_owner.getornull(p_map); + ERR_FAIL_COND(map == NULL); + + map->clear(); } -real_t VertexLights2D::get_indirect_energy() const { - return _indirect_energy; -} -void VertexLights2D::set_indirect_energy(const real_t value) { - _indirect_energy = value; +// Lights +RID VertexLights2D::light_create() { + VertexLightData2D *light = memnew(VertexLightData2D); + RID rid = light_owner.make_rid(light); + light->self = rid; + return rid; } -bool VertexLights2D::get_negative() const { - return _negative; +RID VertexLights2D::light_get_map(RID p_light) { + const VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(light == NULL, RID()); + + if (!light->map) { + return RID(); + } + + return light->map->self; } -void VertexLights2D::set_negative(const bool value) { - _negative = value; +void VertexLights2D::light_set_map(RID p_light, RID p_map) { + VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND(light == NULL); + + VertexLightMap2D *map = map_owner.getornull(p_map); + + if (light->map) { + light->map->remove_light(light); + } + + if (map) { + map->add_light(light); + } } -real_t VertexLights2D::get_specular() const { - return _specular; +Vector2 VertexLights2D::light_get_position(RID p_light) { + const VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(light == NULL, Vector2()); + + return light->position; } -void VertexLights2D::set_specular(const real_t value) { - _specular = value; +void VertexLights2D::light_set_position(RID p_light, const Vector2 &p_position) { + VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND(light == NULL); + + if (light->map) { + // This ensure the light gets moved to the proper quadrant + light->map->set_light_position(light, p_position); + return; + } + + light->position = p_position; +} + +Color VertexLights2D::light_get_color(RID p_light) { + const VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(light == NULL, Color()); + + return light->color; +} +void VertexLights2D::light_set_color(RID p_light, const Color &p_color) { + VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND(light == NULL); + + light->color = p_color; +} + +VertexLights2D::VertexLight2DMode VertexLights2D::light_get_mode(RID p_light) { + const VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(light == NULL, VertexLights2D::VERTEX_LIGHT_2D_MODE_ADD); + + return light->mode; +} +void VertexLights2D::light_set_mode(RID p_light, const VertexLights2D::VertexLight2DMode p_mode) { + VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND(light == NULL); + + light->mode = p_mode; +} + +Vector2i VertexLights2D::light_get_z_range(RID p_light) { + const VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(light == NULL, Vector2i()); + + return light->z_range; +} +void VertexLights2D::light_set_z_range(RID p_light, const Vector2i &p_z_range) { + VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND(light == NULL); + + light->z_range = p_z_range; +} + +Vector2i VertexLights2D::light_get_layer_range(RID p_light) { + const VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(light == NULL, Vector2i()); + + return light->layer_range; +} +void VertexLights2D::light_set_layer_range(RID p_light, const Vector2i &p_layer_range) { + VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND(light == NULL); + + light->layer_range = p_layer_range; +} + +int VertexLights2D::light_get_item_cull_mask(RID p_light) { + const VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(light == NULL, 0); + + return light->item_cull_mask; +} +void VertexLights2D::light_set_item_cull_mask(RID p_light, const int p_item_cull_mask) { + VertexLightData2D *light = light_owner.getornull(p_light); + ERR_FAIL_COND(light == NULL); + + light->item_cull_mask = p_item_cull_mask; +} + +// Rest + +void VertexLights2D::free(RID p_rid) { + if (!p_rid.is_valid()) { + ERR_FAIL_MSG("Invalid RID."); + return; + } + + if (map_owner.owns(p_rid)) { + VertexLightMap2D *map = map_owner.get(p_rid); + + map->clear(); + map->self = RID(); + + map_owner.free(p_rid); + memdelete(map); + } else if (light_owner.owns(p_rid)) { + VertexLightData2D *light = light_owner.get(p_rid); + + if (light->map) { + light->map->remove_light(light); + } + + light->self = RID(); + + light_owner.free(p_rid); + memdelete(light); + + } else { + ERR_FAIL_MSG("Invalid RID."); + } } -*/ VertexLights2D::VertexLights2D() { ERR_FAIL_COND(_self); _self = this; - + GLOBAL_DEF("vertex_lights_2d/default_quadrant_size", Vector2i(256, 256)); _default_quadrant_size = GLOBAL_GET("vertex_lights_2d/default_quadrant_size"); } @@ -107,39 +255,50 @@ VertexLights2D::~VertexLights2D() { } void VertexLights2D::_bind_methods() { - /* - ClassDB::bind_method(D_METHOD("get_transform"), &VertexLights2D::get_transform); - ClassDB::bind_method(D_METHOD("set_transform", "transform"), &VertexLights2D::set_transform); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform"), "set_transform", "get_transform"); + ClassDB::bind_method(D_METHOD("get_default_quadrant_size"), &VertexLights2D::get_default_quadrant_size); + ClassDB::bind_method(D_METHOD("set_default_quadrant_size", "size"), &VertexLights2D::set_default_quadrant_size); - ClassDB::bind_method(D_METHOD("get_range"), &VertexLights2D::get_range); - ClassDB::bind_method(D_METHOD("set_range", "value"), &VertexLights2D::set_range); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "light_range"), "set_range", "get_range"); + ClassDB::bind_method(D_METHOD("map_create"), &VertexLights2D::map_create); - ClassDB::bind_method(D_METHOD("get_attenuation"), &VertexLights2D::get_attenuation); - ClassDB::bind_method(D_METHOD("set_attenuation", "value"), &VertexLights2D::set_attenuation); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "light_attenuation"), "set_attenuation", "get_attenuation"); + ClassDB::bind_method(D_METHOD("map_get_quadrant_size", "map"), &VertexLights2D::map_get_quadrant_size); + ClassDB::bind_method(D_METHOD("map_set_quadrant_size", "map", "size"), &VertexLights2D::map_set_quadrant_size); - ClassDB::bind_method(D_METHOD("get_color"), &VertexLights2D::get_color); - ClassDB::bind_method(D_METHOD("set_color", "value"), &VertexLights2D::set_color); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color"), "set_color", "get_color"); + ClassDB::bind_method(D_METHOD("map_get_lights", "map"), &VertexLights2D::map_get_lights); - ClassDB::bind_method(D_METHOD("get_energy"), &VertexLights2D::get_energy); - ClassDB::bind_method(D_METHOD("set_energy", "value"), &VertexLights2D::set_energy); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "light_energy"), "set_energy", "get_energy"); + ClassDB::bind_method(D_METHOD("map_clear", "map"), &VertexLights2D::map_clear); - ClassDB::bind_method(D_METHOD("get_indirect_energy"), &VertexLights2D::get_indirect_energy); - ClassDB::bind_method(D_METHOD("set_indirect_energy", "value"), &VertexLights2D::set_indirect_energy); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "light_indirect_energy"), "set_indirect_energy", "get_indirect_energy"); + // Lights - ClassDB::bind_method(D_METHOD("get_negative"), &VertexLights2D::get_negative); - ClassDB::bind_method(D_METHOD("set_negative", "value"), &VertexLights2D::set_negative); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "get_negative"); + ClassDB::bind_method(D_METHOD("light_create"), &VertexLights2D::light_create); - ClassDB::bind_method(D_METHOD("get_specular"), &VertexLights2D::get_specular); - ClassDB::bind_method(D_METHOD("set_specular", "value"), &VertexLights2D::set_specular); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "light_specular"), "set_specular", "get_specular"); - */ + ClassDB::bind_method(D_METHOD("light_get_map", "light"), &VertexLights2D::light_get_map); + ClassDB::bind_method(D_METHOD("light_set_map", "light", "map"), &VertexLights2D::light_set_map); + + ClassDB::bind_method(D_METHOD("light_get_position", "light"), &VertexLights2D::light_get_position); + ClassDB::bind_method(D_METHOD("light_set_position", "light", "position"), &VertexLights2D::light_set_position); + + ClassDB::bind_method(D_METHOD("light_get_color", "light"), &VertexLights2D::light_get_color); + ClassDB::bind_method(D_METHOD("light_set_color", "light", "color"), &VertexLights2D::light_set_color); + + ClassDB::bind_method(D_METHOD("light_get_mode", "light"), &VertexLights2D::light_get_mode); + ClassDB::bind_method(D_METHOD("light_set_mode", "light", "mode"), &VertexLights2D::light_set_mode); + + ClassDB::bind_method(D_METHOD("light_get_z_range", "light"), &VertexLights2D::light_get_z_range); + ClassDB::bind_method(D_METHOD("light_set_z_range", "light", "z_range"), &VertexLights2D::light_set_z_range); + + ClassDB::bind_method(D_METHOD("light_get_layer_range", "light"), &VertexLights2D::light_get_layer_range); + ClassDB::bind_method(D_METHOD("light_set_layer_range", "light", "layer_range"), &VertexLights2D::light_set_layer_range); + + ClassDB::bind_method(D_METHOD("light_get_item_cull_mask", "light"), &VertexLights2D::light_get_item_cull_mask); + ClassDB::bind_method(D_METHOD("light_set_item_cull_mask", "light", "item_cull_mask"), &VertexLights2D::light_set_item_cull_mask); + + // Rest + + ClassDB::bind_method(D_METHOD("free", "rid"), &VertexLights2D::free); + + BIND_ENUM_CONSTANT(VERTEX_LIGHT_2D_MODE_ADD); + BIND_ENUM_CONSTANT(VERTEX_LIGHT_2D_MODE_SUB); + BIND_ENUM_CONSTANT(VERTEX_LIGHT_2D_MODE_MIX); } VertexLights2D *VertexLights2D::_self = NULL; diff --git a/modules/vertex_lights_2d/vertex_lights_2d.h b/modules/vertex_lights_2d/vertex_lights_2d.h index 216f6f362..8366a8cdf 100644 --- a/modules/vertex_lights_2d/vertex_lights_2d.h +++ b/modules/vertex_lights_2d/vertex_lights_2d.h @@ -43,7 +43,6 @@ class VertexLightMap2D; class VertexLightQuadrant2D; class VertexLightData2D; - class VertexLights2D : public Object { GDCLASS(VertexLights2D, Object); @@ -55,31 +54,50 @@ public: //VERTEX_LIGHT_2D_MODE_MASK }; - /* - Transform get_transform() const; - void set_transform(const Transform &p_transform); + // Defaults + + Vector2i get_default_quadrant_size() const; + void set_default_quadrant_size(const Vector2i &p_size); - real_t get_range() const; - void set_range(const real_t value); + // Maps + + RID map_create(); - real_t get_attenuation() const; - void set_attenuation(const real_t value); + Vector2i map_get_quadrant_size(RID p_map) const; + void map_set_quadrant_size(RID p_map, const Vector2i &p_size); - Color get_color() const; - void set_color(const Color value); + Array map_get_lights(RID p_map) const; + + void map_clear(RID p_map); - real_t get_energy() const; - void set_energy(const real_t value); + // Lights + + RID light_create(); - real_t get_indirect_energy() const; - void set_indirect_energy(const real_t value); + RID light_get_map(RID p_light); + void light_set_map(RID p_light, RID p_map); - bool get_negative() const; - void set_negative(const bool value); + Vector2 light_get_position(RID p_light); + void light_set_position(RID p_light, const Vector2 &p_position); - real_t get_specular() const; - void set_specular(const real_t value); - */ + Color light_get_color(RID p_light); + void light_set_color(RID p_light, const Color &p_color); + + VertexLights2D::VertexLight2DMode light_get_mode(RID p_light); + void light_set_mode(RID p_light, const VertexLights2D::VertexLight2DMode p_mode); + + Vector2i light_get_z_range(RID p_light); + void light_set_z_range(RID p_light, const Vector2i &p_z_range); + + Vector2i light_get_layer_range(RID p_light); + void light_set_layer_range(RID p_light, const Vector2i &p_layer_range); + + int light_get_item_cull_mask(RID p_light); + void light_set_item_cull_mask(RID p_light, const int p_item_cull_mask); + + // Rest + + void free(RID p_rid); _FORCE_INLINE_ static VertexLights2D *get_singleton() { return _self; @@ -92,9 +110,8 @@ protected: static void _bind_methods(); mutable RID_Owner map_owner; - mutable RID_Owner quadrant_owner; - mutable RID_Owner light_data_owner; - + mutable RID_Owner light_owner; + Vector2i _default_quadrant_size; static VertexLights2D *_self;