diff --git a/core/dictionary.cpp b/core/dictionary.cpp index b8a57218541c..814a0c5363b0 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -125,6 +125,10 @@ Variant Dictionary::get_or_add(const Variant &p_key, const Variant &p_default) { return *result; } +void Dictionary::set(const Variant &p_key, const Variant &p_value) { + operator[](p_key) = p_value; +} + int Dictionary::size() const { return _p->variant_map.size(); } diff --git a/core/dictionary.h b/core/dictionary.h index dad679f30b44..bd04ab9d5bde 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -59,6 +59,7 @@ class Dictionary { Variant get_valid(const Variant &p_key) const; Variant get(const Variant &p_key, const Variant &p_default) const; Variant get_or_add(const Variant &p_key, const Variant &p_default); + void set(const Variant &p_key, const Variant &p_value); int size() const; bool empty() const; diff --git a/core/translation.cpp b/core/translation.cpp index 4ad17f1d1596..c911e738de11 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -261,6 +261,10 @@ void TranslationServer::init_locale_info() { } String TranslationServer::standardize_locale(const String &p_locale) const { + return _standardize_locale(p_locale, false); +} + +String TranslationServer::_standardize_locale(const String &p_locale, bool p_add_defaults) const { // Replaces '-' with '_' for macOS style locales. String univ_locale = p_locale.replace("-", "_"); @@ -322,24 +326,26 @@ String TranslationServer::standardize_locale(const String &p_locale) const { } // Add script code base on language and country codes for some ambiguous cases. - if (script.empty()) { - for (int i = 0; i < locale_script_info.size(); i++) { - const LocaleScriptInfo &info = locale_script_info[i]; - if (info.name == lang) { - if (country.empty() || info.supported_countries.has(country)) { - script = info.script; - break; + if (p_add_defaults) { + if (script.empty()) { + for (int i = 0; i < locale_script_info.size(); i++) { + const LocaleScriptInfo &info = locale_script_info[i]; + if (info.name == lang) { + if (country.empty() || info.supported_countries.has(country)) { + script = info.script; + break; + } } } } - } - if (!script.empty() && country.empty()) { - // Add conntry code based on script for some ambiguous cases. - for (int i = 0; i < locale_script_info.size(); i++) { - const LocaleScriptInfo &info = locale_script_info[i]; - if (info.name == lang && info.script == script) { - country = info.default_country; - break; + if (!script.empty() && country.empty()) { + // Add conntry code based on script for some ambiguous cases. + for (int i = 0; i < locale_script_info.size(); i++) { + const LocaleScriptInfo &info = locale_script_info[i]; + if (info.name == lang && info.script == script) { + country = info.default_country; + break; + } } } } @@ -359,32 +365,46 @@ String TranslationServer::standardize_locale(const String &p_locale) const { } int TranslationServer::compare_locales(const String &p_locale_a, const String &p_locale_b) const { - String locale_a = standardize_locale(p_locale_a); - String locale_b = standardize_locale(p_locale_b); + if (p_locale_a == p_locale_b) { + // Exact match. + return 10; + } + + const String cache_key = p_locale_a + "|" + p_locale_b; + const int *cached_result = locale_compare_cache.getptr(cache_key); + if (cached_result) { + return *cached_result; + } + + String locale_a = _standardize_locale(p_locale_a, true); + String locale_b = _standardize_locale(p_locale_b, true); if (locale_a == locale_b) { // Exact match. + locale_compare_cache.set(cache_key, 10); return 10; } Vector locale_a_elements = locale_a.split("_"); Vector locale_b_elements = locale_b.split("_"); - if (locale_a_elements[0] == locale_b_elements[0]) { - // Matching language, both locales have extra parts. - // Return number of matching elements. - int matching_elements = 1; - for (int i = 1; i < locale_a_elements.size(); i++) { - for (int j = 1; j < locale_b_elements.size(); j++) { - if (locale_a_elements[i] == locale_b_elements[j]) { - matching_elements++; - } - } - } - return matching_elements; - } else { + if (locale_a_elements[0] != locale_b_elements[0]) { // No match. + locale_compare_cache.set(cache_key, 0); return 0; } + + // Matching language, both locales have extra parts. + // Return number of matching elements. + int matching_elements = 1; + for (int i = 1; i < locale_a_elements.size(); i++) { + for (int j = 1; j < locale_b_elements.size(); j++) { + if (locale_a_elements[i] == locale_b_elements[j]) { + matching_elements++; + } + } + } + locale_compare_cache.set(cache_key, matching_elements); + return matching_elements; } String TranslationServer::get_locale_name(const String &p_locale) const { diff --git a/core/translation.h b/core/translation.h index d4b2b0fb5faa..bbb549de10c5 100644 --- a/core/translation.h +++ b/core/translation.h @@ -87,6 +87,8 @@ class TranslationServer : public Object { Ref tool_translation; Ref doc_translation; + mutable HashMap locale_compare_cache; + bool enabled; static TranslationServer *singleton; @@ -122,6 +124,7 @@ class TranslationServer : public Object { int compare_locales(const String &p_locale_a, const String &p_locale_b) const; String standardize_locale(const String &p_locale) const; + String _standardize_locale(const String &p_locale, bool p_add_defaults) const; Vector get_all_languages() const; String get_language_name(const String &p_language) const; diff --git a/core/ustring.cpp b/core/ustring.cpp index d5543aa05bbc..22e065193996 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -904,13 +904,16 @@ Vector String::split_floats(const String &p_splitter, bool p_allow_empty) int from = 0; int len = length(); + String buffer = *this; while (true) { int end = find(p_splitter, from); if (end < 0) { end = len; } if (p_allow_empty || (end > from)) { - ret.push_back(String::to_double(&c_str()[from])); + buffer[end] = 0; + ret.push_back(String::to_double(&buffer.c_str()[from])); + buffer[end] = _cowdata.get(end); } if (end == len) { @@ -928,6 +931,7 @@ Vector String::split_floats_mk(const Vector &p_splitters, bool p_ int from = 0; int len = length(); + String buffer = *this; while (true) { int idx; int end = findmk(p_splitters, from, &idx); @@ -939,7 +943,9 @@ Vector String::split_floats_mk(const Vector &p_splitters, bool p_ } if (p_allow_empty || (end > from)) { - ret.push_back(String::to_double(&c_str()[from])); + buffer[end] = 0; + ret.push_back(String::to_double(&buffer.c_str()[from])); + buffer[end] = _cowdata.get(end); } if (end == len) { diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 83b3fd7ad71a..902133efb85e 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -562,6 +562,7 @@ struct _VariantCall { VCALL_LOCALMEM1R(Dictionary, duplicate); VCALL_LOCALMEM2R(Dictionary, get); VCALL_LOCALMEM2R(Dictionary, get_or_add); + VCALL_LOCALMEM2(Dictionary, set); VCALL_LOCALMEM2(Array, set); VCALL_LOCALMEM1R(Array, get); @@ -1940,6 +1941,7 @@ void register_variant_methods() { ADDFUNC0R(DICTIONARY, BOOL, Dictionary, empty, varray()); ADDFUNC0NC(DICTIONARY, NIL, Dictionary, clear, varray()); ADDFUNC2NC(DICTIONARY, NIL, Dictionary, merge, DICTIONARY, "dictionary", BOOL, "overwrite", varray(false)); + ADDFUNC2NC(DICTIONARY, NIL, Dictionary, set, NIL, "key", NIL, "value", varray()); ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has, NIL, "key", varray()); ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has_all, ARRAY, "keys", varray()); ADDFUNC1R(DICTIONARY, NIL, Dictionary, find_key, NIL, "value", varray()); @@ -1955,6 +1957,8 @@ void register_variant_methods() { ADDFUNC0R(ARRAY, BOOL, Array, empty, varray()); ADDFUNC0NC(ARRAY, NIL, Array, clear, varray()); ADDFUNC0R(ARRAY, INT, Array, hash, varray()); + ADDFUNC1R(ARRAY, NIL, Array, get, INT, "index", varray()); + ADDFUNC2NC(ARRAY, NIL, Array, set, INT, "index", NIL, "value", varray()); ADDFUNC1NC(ARRAY, NIL, Array, push_back, NIL, "value", varray()); ADDFUNC1NC(ARRAY, NIL, Array, push_front, NIL, "value", varray()); ADDFUNC1NC(ARRAY, NIL, Array, fill, NIL, "value", varray()); @@ -1988,6 +1992,7 @@ void register_variant_methods() { ADDFUNC0R(POOL_BYTE_ARRAY, INT, PoolByteArray, size, varray()); ADDFUNC0R(POOL_BYTE_ARRAY, BOOL, PoolByteArray, empty, varray()); + ADDFUNC1R(POOL_BYTE_ARRAY, INT, PoolByteArray, get, INT, "index", varray()); ADDFUNC2(POOL_BYTE_ARRAY, NIL, PoolByteArray, set, INT, "idx", INT, "byte", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, push_back, INT, "byte", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, fill, INT, "byte", varray()); @@ -2014,6 +2019,7 @@ void register_variant_methods() { ADDFUNC0R(POOL_INT_ARRAY, INT, PoolIntArray, size, varray()); ADDFUNC0R(POOL_INT_ARRAY, BOOL, PoolIntArray, empty, varray()); + ADDFUNC1R(POOL_INT_ARRAY, INT, PoolIntArray, get, INT, "index", varray()); ADDFUNC2(POOL_INT_ARRAY, NIL, PoolIntArray, set, INT, "idx", INT, "integer", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, push_back, INT, "integer", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, fill, INT, "integer", varray()); @@ -2032,6 +2038,7 @@ void register_variant_methods() { ADDFUNC0R(POOL_REAL_ARRAY, INT, PoolRealArray, size, varray()); ADDFUNC0R(POOL_REAL_ARRAY, BOOL, PoolRealArray, empty, varray()); + ADDFUNC1R(POOL_REAL_ARRAY, REAL, PoolRealArray, get, INT, "index", varray()); ADDFUNC2(POOL_REAL_ARRAY, NIL, PoolRealArray, set, INT, "idx", REAL, "value", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, push_back, REAL, "value", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, fill, REAL, "value", varray()); @@ -2050,6 +2057,7 @@ void register_variant_methods() { ADDFUNC0R(POOL_STRING_ARRAY, INT, PoolStringArray, size, varray()); ADDFUNC0R(POOL_STRING_ARRAY, BOOL, PoolStringArray, empty, varray()); + ADDFUNC1R(POOL_STRING_ARRAY, STRING, PoolStringArray, get, INT, "index", varray()); ADDFUNC2(POOL_STRING_ARRAY, NIL, PoolStringArray, set, INT, "idx", STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, push_back, STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, fill, STRING, "string", varray()); @@ -2069,6 +2077,7 @@ void register_variant_methods() { ADDFUNC0R(POOL_VECTOR2_ARRAY, INT, PoolVector2Array, size, varray()); ADDFUNC0R(POOL_VECTOR2_ARRAY, BOOL, PoolVector2Array, empty, varray()); + ADDFUNC1R(POOL_VECTOR2_ARRAY, VECTOR2, PoolVector2Array, get, INT, "index", varray()); ADDFUNC2(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, set, INT, "idx", VECTOR2, "vector2", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, push_back, VECTOR2, "vector2", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, fill, VECTOR2, "vector2", varray()); @@ -2087,6 +2096,7 @@ void register_variant_methods() { ADDFUNC0R(POOL_VECTOR3_ARRAY, INT, PoolVector3Array, size, varray()); ADDFUNC0R(POOL_VECTOR3_ARRAY, BOOL, PoolVector3Array, empty, varray()); + ADDFUNC1R(POOL_VECTOR3_ARRAY, VECTOR3, PoolVector3Array, get, INT, "index", varray()); ADDFUNC2(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, set, INT, "idx", VECTOR3, "vector3", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, push_back, VECTOR3, "vector3", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, fill, VECTOR3, "vector3", varray()); @@ -2105,6 +2115,7 @@ void register_variant_methods() { ADDFUNC0R(POOL_COLOR_ARRAY, INT, PoolColorArray, size, varray()); ADDFUNC0R(POOL_COLOR_ARRAY, BOOL, PoolColorArray, empty, varray()); + ADDFUNC1R(POOL_COLOR_ARRAY, COLOR, PoolColorArray, get, INT, "index", varray()); ADDFUNC2(POOL_COLOR_ARRAY, NIL, PoolColorArray, set, INT, "idx", COLOR, "color", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, push_back, COLOR, "color", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, fill, COLOR, "color", varray()); diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index e537bff81919..b559c6f2fa83 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -211,6 +211,13 @@ [b]Note:[/b] Calling this function is not the same as writing [code]array[0][/code]. If the array is empty, accessing by index will pause project execution when running from the editor. + + + + + Returns the element at the given [code]index[/code] in the array. This is the same as using the [code][][/code] operator ([code]array[index][/code]). + + @@ -329,6 +336,13 @@ Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array. If the adjusted start index is out of bounds, this method searches from the end of the array. + + + + + Sets the value of the element at the given [code]index[/code] to the given [code]value[/code]. This will not change the size of the array, it only changes the value at an index already in the array. This is the same as using the [code][][/code] operator ([code]array[index] = value[/code]). + + Shuffles the array such that the items will have a random order. This method uses the global random number generator common to methods such as [method @GDScript.randi]. Call [method @GDScript.randomize] to ensure that a new seed will be used each time if you want non-reproducible shuffling. diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml index 3b82d98a75cc..2af7ad591f3b 100644 --- a/doc/classes/Dictionary.xml +++ b/doc/classes/Dictionary.xml @@ -187,6 +187,13 @@ Adds elements from [code]dictionary[/code] to this [Dictionary]. By default, duplicate keys will not be copied over, unless [code]overwrite[/code] is [code]true[/code]. + + + + + Sets the value of the element at the given [code]key[/code] to the given [code]value[/code]. This is the same as using the [code][][/code] operator ([code]array[index] = value[/code]). + + diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml index 7dc425881fc2..4d504a49f1d4 100644 --- a/doc/classes/Environment.xml +++ b/doc/classes/Environment.xml @@ -233,6 +233,15 @@ If [code]true[/code], the 7th level of glow is enabled. This is the most "global" level (blurriest). + + The texture that should be used as a glow map to [i]multiply[/i] the resulting glow color according to [member glow_map_strength]. This can be used to create a "lens dirt" effect. The texture's RGB color channels are used for modulation, but the alpha channel is ignored. + [b]Note:[/b] The texture will be stretched to fit the screen. Therefore, it's recommended to use a texture with an aspect ratio that matches your project's base aspect ratio (typically 16:9). + [b]Note:[/b] [member glow_map] has no effect when using the GLES2 rendering method, due to this rendering method using a simpler glow implementation optimized for low-end devices. + + + How strong of an impact the [member glow_map] should have on the overall glow effect. A strength of [code]0.0[/code] means the glow map has no effect on the overall glow effect. A strength of [code]1.0[/code] means the glow has a full effect on the overall glow effect (and can turn off glow entirely in specific areas of the screen if the glow map has black areas). + [b]Note:[/b] [member glow_map_strength] has no effect when using the GLES2 rendering method, due to this rendering method using a simpler glow implementation optimized for low-end devices. + The glow strength. When using the GLES2 renderer, this should be increased to 1.3 to compensate for the lack of HDR rendering. diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index cd64b627c540..0a56d20ca744 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -211,6 +211,7 @@ If [code]exact[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events. [b]Note:[/b] Returning [code]true[/code] does not imply that the action is [i]still[/i] pressed. An action can be pressed and released again rapidly, and [code]true[/code] will still be returned so as not to miss input. [b]Note:[/b] Due to keyboard ghosting, [method is_action_just_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information. + [b]Note:[/b] During input handling (e.g. [method Node._input]), use [method InputEvent.is_action_pressed] instead to query the action state of the current event. @@ -221,6 +222,7 @@ Returns [code]true[/code] when the user [i]stops[/i] pressing the action event in the current frame or physics tick. It will only return [code]true[/code] on the frame or tick that the user releases the button. If [code]exact[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events. [b]Note:[/b] Returning [code]true[/code] does not imply that the action is [i]still[/i] not pressed. An action can be released and pressed again rapidly, and [code]true[/code] will still be returned so as not to miss input. + [b]Note:[/b] During input handling (e.g. [method Node._input]), use [method InputEvent.is_action_released] instead to query the action state of the current event. diff --git a/doc/classes/PoolByteArray.xml b/doc/classes/PoolByteArray.xml index eaabb87d06a5..453fee062ff4 100644 --- a/doc/classes/PoolByteArray.xml +++ b/doc/classes/PoolByteArray.xml @@ -100,6 +100,13 @@ Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed. Returns [code]-1[/code] if [code]from[/code] is out of bounds. + + + + + Returns the byte at the given [code]index[/code] in the array. This is the same as using the [code][][/code] operator ([code]array[index][/code]). + + diff --git a/doc/classes/PoolColorArray.xml b/doc/classes/PoolColorArray.xml index f9a1223d0737..01c7a1c5a534 100644 --- a/doc/classes/PoolColorArray.xml +++ b/doc/classes/PoolColorArray.xml @@ -74,6 +74,13 @@ Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed. Returns [code]-1[/code] if [code]from[/code] is out of bounds. + + + + + Returns the Color at the given [code]index[/code] in the array. This is the same as using the [code][][/code] operator ([code]array[index][/code]). + + diff --git a/doc/classes/PoolIntArray.xml b/doc/classes/PoolIntArray.xml index efb44f7034b3..2275f497edd2 100644 --- a/doc/classes/PoolIntArray.xml +++ b/doc/classes/PoolIntArray.xml @@ -75,6 +75,13 @@ Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed. Returns [code]-1[/code] if [code]from[/code] is out of bounds. + + + + + Returns the integer at the given [code]index[/code] in the array. This is the same as using the [code][][/code] operator ([code]array[index][/code]). + + diff --git a/doc/classes/PoolRealArray.xml b/doc/classes/PoolRealArray.xml index 2e2cd4c44f32..2bec2aa62f21 100644 --- a/doc/classes/PoolRealArray.xml +++ b/doc/classes/PoolRealArray.xml @@ -75,6 +75,13 @@ Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed. Returns [code]-1[/code] if [code]from[/code] is out of bounds. + + + + + Returns the float at the given [code]index[/code] in the array. This is the same as using the [code][][/code] operator ([code]array[index][/code]). + + diff --git a/doc/classes/PoolStringArray.xml b/doc/classes/PoolStringArray.xml index 0c8a4e9a9377..958cd2515f97 100644 --- a/doc/classes/PoolStringArray.xml +++ b/doc/classes/PoolStringArray.xml @@ -75,6 +75,13 @@ Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed. Returns [code]-1[/code] if [code]from[/code] is out of bounds. + + + + + Returns the String at the given [code]index[/code] in the array. This is the same as using the [code][][/code] operator ([code]array[index][/code]). + + diff --git a/doc/classes/PoolVector2Array.xml b/doc/classes/PoolVector2Array.xml index 4da929cb64ab..bc597d470980 100644 --- a/doc/classes/PoolVector2Array.xml +++ b/doc/classes/PoolVector2Array.xml @@ -75,6 +75,13 @@ Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed. Returns [code]-1[/code] if [code]from[/code] is out of bounds. + + + + + Returns the Vector2 at the given [code]index[/code] in the array. This is the same as using the [code][][/code] operator ([code]array[index][/code]). + + diff --git a/doc/classes/PoolVector3Array.xml b/doc/classes/PoolVector3Array.xml index d6d645af8566..b81f6fec141d 100644 --- a/doc/classes/PoolVector3Array.xml +++ b/doc/classes/PoolVector3Array.xml @@ -74,6 +74,13 @@ Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed. Returns [code]-1[/code] if [code]from[/code] is out of bounds. + + + + + Returns the Vector3 at the given [code]index[/code] in the array. This is the same as using the [code][][/code] operator ([code]array[index][/code]). + + diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index 82d3a786127d..027a4a1c2413 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -960,6 +960,15 @@ Sets the variables to be used with the "glow" post-process effect. See [Environment] for more details. + + + + + + + Sets the variables to be used with the glow map post-process effect. See [Environment] for more details. + + diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 7391122b9cd3..7f63ec5f8738 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -66,6 +66,7 @@ class RasterizerSceneDummy : public RasterizerScene { void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale, bool p_high_quality) {} + void environment_set_glow_map(RID p_env, float p_glow_map_strength, RID p_glow_map) {} void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {} diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index ca1efa0b1dfa..d0c2088c1e04 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -848,6 +848,11 @@ void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_ env->glow_high_quality = p_high_quality; } +void RasterizerSceneGLES2::environment_set_glow_map(RID p_env, float p_glow_map_strength, RID p_glow_map) { + Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); +} + void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 3ab55c8ae964..9015f1cc972a 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -486,6 +486,7 @@ class RasterizerSceneGLES2 : public RasterizerScene { virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale, bool p_high_quality); + virtual void environment_set_glow_map(RID p_env, float p_glow_map_strength, RID p_glow_map); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index b514a580faef..029625d01ebe 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -884,6 +884,15 @@ void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_ env->glow_bicubic_upscale = p_bicubic_upscale; env->glow_high_quality = p_high_quality; } + +void RasterizerSceneGLES3::environment_set_glow_map(RID p_env, float p_glow_map_strength, RID p_glow_map) { + Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->glow_map_strength = p_glow_map_strength; + env->glow_map = p_glow_map; +} + void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) { } @@ -4022,7 +4031,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(env->color_correction); if (tex) { state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_COLOR_CORRECTION, true); - WRAPPED_GL_ACTIVE_TEXTURE(GL_TEXTURE3); + WRAPPED_GL_ACTIVE_TEXTURE(GL_TEXTURE4); glBindTexture(tex->target, tex->tex_id); } } @@ -4037,6 +4046,14 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p if (max_glow_level >= 0) { state.tonemap_shader.set_uniform(TonemapShaderGLES3::GLOW_INTENSITY, env->glow_intensity); + state.tonemap_shader.set_uniform(TonemapShaderGLES3::GLOW_MAP_STRENGTH, env->glow_map_strength); + + RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(env->glow_map); + if (tex) { + WRAPPED_GL_ACTIVE_TEXTURE(GL_TEXTURE3); + glBindTexture(tex->target, tex->tex_id); + } + int ss[2] = { storage->frame.current_rt->width, storage->frame.current_rt->height, diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 0463e5948682..52d4cc544158 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -412,6 +412,8 @@ class RasterizerSceneGLES3 : public RasterizerScene { float glow_hdr_luminance_cap; bool glow_bicubic_upscale; bool glow_high_quality; + float glow_map_strength; + RID glow_map; VS::EnvironmentToneMapper tone_mapper; float tone_mapper_exposure; @@ -550,6 +552,7 @@ class RasterizerSceneGLES3 : public RasterizerScene { virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale, bool p_high_quality); + virtual void environment_set_glow_map(RID p_env, float p_glow_map_strength, RID p_glow_map); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness); diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index bdf0bd8d21f2..da9f33516c90 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -42,6 +42,8 @@ uniform highp float auto_exposure_grey; uniform highp sampler2D source_glow; //texunit:2 uniform highp float glow_intensity; +uniform highp float glow_map_strength; +uniform highp sampler2D glow_map; //texunit:3 #endif #ifdef USE_BCS @@ -57,7 +59,7 @@ uniform float sharpen_intensity; #endif #ifdef USE_COLOR_CORRECTION -uniform sampler2D color_correction; //texunit:3 +uniform sampler2D color_correction; //texunit:4 #endif layout(location = 0) out vec4 frag_color; @@ -482,6 +484,9 @@ void main() { #ifdef USING_GLOW vec3 glow = gather_glow(source_glow, uv_interp) * glow_intensity; + if (glow_map_strength > 0.001) { + glow = mix(glow, texture(glow_map, vec2(uv_interp.x, 1.0 - uv_interp.y)).rgb * glow, glow_map_strength); + } // high dynamic range -> SRGB glow = apply_tonemapping(glow, white); diff --git a/main/input_default.cpp b/main/input_default.cpp index 24505577c03b..f632bf45fcd8 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -111,6 +111,12 @@ bool InputDefault::is_action_pressed(const StringName &p_action, bool p_exact) c } bool InputDefault::is_action_just_pressed(const StringName &p_action, bool p_exact) const { +#ifdef TOOLS_ENABLED + if (_currently_parsing_input) { + WARN_PRINT_ONCE("Prefer InputEvent.is_action_pressed() within input event callbacks to prevent detecting duplicates."); + } +#endif + ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action)); const Map::Element *E = action_state.find(p_action); if (!E) { @@ -132,6 +138,12 @@ bool InputDefault::is_action_just_pressed(const StringName &p_action, bool p_exa } bool InputDefault::is_action_just_released(const StringName &p_action, bool p_exact) const { +#ifdef TOOLS_ENABLED + if (_currently_parsing_input) { + WARN_PRINT_ONCE("Prefer InputEvent.is_action_released() within input event callbacks to prevent detecting duplicates."); + } +#endif + ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action)); const Map::Element *E = action_state.find(p_action); if (!E) { @@ -327,6 +339,10 @@ void InputDefault::_parse_input_event_impl(const Ref &p_event, bool // Regardless where the event came from originally, this has to happen on the main thread. DEV_ASSERT(Thread::get_caller_id() == Thread::get_main_id()); +#ifdef TOOLS_ENABLED + InputGuard guard(_currently_parsing_input); +#endif + // Notes on mouse-touch emulation: // - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects // as true mouse events. The only difference is the situation is flagged as emulated so they are not diff --git a/main/input_default.h b/main/input_default.h index 6c0192e0d6fd..19206db8558b 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -114,6 +114,20 @@ class InputDefault : public Input { CursorShape default_shape; +#ifdef TOOLS_ENABLED + // Simple single-threaded detection of whether + // inside `_parse_input_event_impl()`. + bool _currently_parsing_input = false; + class InputGuard { + bool &_currently_parsing; + + public: + InputGuard(bool &r_currently_parsing) : + _currently_parsing(r_currently_parsing) { _currently_parsing = true; } + ~InputGuard() { _currently_parsing = false; } + }; +#endif + public: enum HatMask { HAT_MASK_CENTER = 0, diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp index f773650752d5..e2d4d41f8620 100644 --- a/main/tests/test_string.cpp +++ b/main/tests/test_string.cpp @@ -1254,6 +1254,67 @@ bool test_37() { return true; } +bool test_38() { +#define CHECK_ARR_LEN(arr, len) \ + if (arr.size() != len) { \ + OS::get_singleton()->print("\tFAIL: Length of %s should be %d, got %d\n", #arr, len, arr.size()); \ + return false; \ + } else { \ + OS::get_singleton()->print("\tPASS\n"); \ + } +#define CHECK_ARR_ELEMENT(arr, i, expect) \ + if (ABS(arr[i] - expect) > 0.00001) { \ + OS::get_singleton()->print("\tFAIL: %s[%d] %f != %f\n", #arr, i, arr[i], expect); \ + return false; \ + } else { \ + OS::get_singleton()->print("\tPASS\n"); \ + } + + OS::get_singleton()->print("\n\nTest 38: split_floats\n"); + + { + const String s = "1.2;2.3 4.5"; + const float slices[3] = { 1.2, 2.3, 4.5 }; + + const Vector d_arr = s.split_floats(";"); + CHECK_ARR_LEN(d_arr, 2); + for (int i = 0; i < 2; i++) { + CHECK_ARR_ELEMENT(d_arr, i, slices[i]); + } + + Vector keys; + keys.push_back(";"); + keys.push_back(" "); + const Vector f_arr = s.split_floats_mk(keys); + CHECK_ARR_LEN(f_arr, 3); + for (int i = 0; i < 3; i++) { + CHECK_ARR_ELEMENT(f_arr, i, slices[i]); + } + } + + { + const String s = " -2.0 5"; + const float slices[10] = { 0, -2, 0, 0, 0, 0, 0, 0, 0, 5 }; + + const Vector d_arr = s.split_floats(" "); + CHECK_ARR_LEN(d_arr, 10); + for (int i = 0; i < 10; i++) { + CHECK_ARR_ELEMENT(d_arr, i, slices[i]); + } + + Vector keys; + keys.push_back(";"); + keys.push_back(" "); + const Vector f_arr = s.split_floats_mk(keys); + CHECK_ARR_LEN(f_arr, 10); + for (int i = 0; i < 10; i++) { + CHECK_ARR_ELEMENT(f_arr, i, slices[i]); + } + } + + return true; +} + typedef bool (*TestFunc)(); TestFunc test_funcs[] = { @@ -1295,6 +1356,7 @@ TestFunc test_funcs[] = { test_35, test_36, test_37, + test_38, nullptr }; diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 456daa7a7d7a..6e2293c8411f 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1083,7 +1083,12 @@ Vector3 KinematicBody::_move_and_slide_internal(const Vector3 &p_linear_velocity // We need to check the on_floor_body still exists before accessing. // A valid RID is no guarantee that the object has not been deleted. - if (ObjectDB::get_instance(on_floor_body_id)) { + + // We can only perform the ObjectDB lifetime check on Object derived objects. + // Note that physics also creates RIDs for non-Object derived objects, these cannot + // be lifetime checked through ObjectDB, and therefore there is a still a vulnerability + // to dangling RIDs (access after free) in this scenario. + if (!on_floor_body_id || ObjectDB::get_instance(on_floor_body_id)) { // This approach makes sure there is less delay between the actual body velocity and the one we saved. bs = PhysicsServer::get_singleton()->body_get_direct_state(on_floor_body_rid); } diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 069364e7a391..f528be3a1c7a 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -498,7 +498,7 @@ float Environment::get_ssao_edge_sharpness() const { void Environment::set_glow_enabled(bool p_enabled) { glow_enabled = p_enabled; - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); _change_notify(); } @@ -515,7 +515,7 @@ void Environment::set_glow_level(int p_level, bool p_enabled) { glow_levels &= ~(1 << p_level); } - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } bool Environment::is_glow_level_enabled(int p_level) const { ERR_FAIL_INDEX_V(p_level, VS::MAX_GLOW_LEVELS, false); @@ -525,8 +525,7 @@ bool Environment::is_glow_level_enabled(int p_level) const { void Environment::set_glow_intensity(float p_intensity) { glow_intensity = p_intensity; - - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } float Environment::get_glow_intensity() const { return glow_intensity; @@ -534,7 +533,7 @@ float Environment::get_glow_intensity() const { void Environment::set_glow_strength(float p_strength) { glow_strength = p_strength; - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } float Environment::get_glow_strength() const { return glow_strength; @@ -542,8 +541,7 @@ float Environment::get_glow_strength() const { void Environment::set_glow_bloom(float p_threshold) { glow_bloom = p_threshold; - - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } float Environment::get_glow_bloom() const { return glow_bloom; @@ -551,8 +549,7 @@ float Environment::get_glow_bloom() const { void Environment::set_glow_blend_mode(GlowBlendMode p_mode) { glow_blend_mode = p_mode; - - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } Environment::GlowBlendMode Environment::get_glow_blend_mode() const { return glow_blend_mode; @@ -560,8 +557,7 @@ Environment::GlowBlendMode Environment::get_glow_blend_mode() const { void Environment::set_glow_hdr_bleed_threshold(float p_threshold) { glow_hdr_bleed_threshold = p_threshold; - - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } float Environment::get_glow_hdr_bleed_threshold() const { return glow_hdr_bleed_threshold; @@ -569,8 +565,7 @@ float Environment::get_glow_hdr_bleed_threshold() const { void Environment::set_glow_hdr_luminance_cap(float p_amount) { glow_hdr_luminance_cap = p_amount; - - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } float Environment::get_glow_hdr_luminance_cap() const { return glow_hdr_luminance_cap; @@ -578,8 +573,7 @@ float Environment::get_glow_hdr_luminance_cap() const { void Environment::set_glow_hdr_bleed_scale(float p_scale) { glow_hdr_bleed_scale = p_scale; - - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } float Environment::get_glow_hdr_bleed_scale() const { return glow_hdr_bleed_scale; @@ -587,7 +581,7 @@ float Environment::get_glow_hdr_bleed_scale() const { void Environment::set_glow_bicubic_upscale(bool p_enable) { glow_bicubic_upscale = p_enable; - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } bool Environment::is_glow_bicubic_upscale_enabled() const { @@ -596,13 +590,58 @@ bool Environment::is_glow_bicubic_upscale_enabled() const { void Environment::set_glow_high_quality(bool p_enable) { glow_high_quality = p_enable; - VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, glow_hdr_luminance_cap, glow_bicubic_upscale, glow_high_quality); + _update_glow(); } bool Environment::is_glow_high_quality_enabled() const { return glow_high_quality; } +void Environment::set_glow_map_strength(float p_glow_map_strength) { + glow_map_strength = p_glow_map_strength; + _update_glow_map(); +} + +float Environment::get_glow_map_strength() const { + return glow_map_strength; +} + +void Environment::set_glow_map(Ref p_glow_map) { + glow_map = p_glow_map; + _update_glow_map(); +} + +Ref Environment::get_glow_map() const { + return glow_map; +} + +void Environment::_update_glow() { + VS::get_singleton()->environment_set_glow( + environment, + glow_enabled, + glow_levels, + glow_intensity, + glow_strength, + glow_bloom, + VS::EnvironmentGlowBlendMode(glow_blend_mode), + glow_hdr_bleed_threshold, + glow_hdr_bleed_scale, + glow_hdr_luminance_cap, + glow_bicubic_upscale, + glow_high_quality); +} + +void Environment::_update_glow_map() { + float _glow_map_strength = 0.0f; + RID glow_map_rid; + if (glow_map.is_valid()) { + glow_map_rid = glow_map->get_rid(); + _glow_map_strength = glow_map_strength; + } + + VS::get_singleton()->environment_set_glow_map(environment, _glow_map_strength, glow_map_rid); +} + void Environment::set_dof_blur_far_enabled(bool p_enable) { dof_blur_far_enabled = p_enable; VS::get_singleton()->environment_set_dof_blur_far(environment, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_far_amount, VS::EnvironmentDOFBlurQuality(dof_blur_far_quality)); @@ -1100,6 +1139,12 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_glow_high_quality", "enabled"), &Environment::set_glow_high_quality); ClassDB::bind_method(D_METHOD("is_glow_high_quality_enabled"), &Environment::is_glow_high_quality_enabled); + ClassDB::bind_method(D_METHOD("set_glow_map_strength", "strength"), &Environment::set_glow_map_strength); + ClassDB::bind_method(D_METHOD("get_glow_map_strength"), &Environment::get_glow_map_strength); + + ClassDB::bind_method(D_METHOD("set_glow_map", "mode"), &Environment::set_glow_map); + ClassDB::bind_method(D_METHOD("get_glow_map"), &Environment::get_glow_map); + ADD_GROUP("Glow", "glow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_enabled"), "set_glow_enabled", "is_glow_enabled"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/1"), "set_glow_level", "is_glow_level_enabled", 0); @@ -1119,6 +1164,8 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "glow_hdr_scale", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_scale", "get_glow_hdr_bleed_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_bicubic_upscale"), "set_glow_bicubic_upscale", "is_glow_bicubic_upscale_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_high_quality"), "set_glow_high_quality", "is_glow_high_quality_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "glow_map_strength", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_glow_map_strength", "get_glow_map_strength"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "glow_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_glow_map", "get_glow_map"); ClassDB::bind_method(D_METHOD("set_adjustment_enable", "enabled"), &Environment::set_adjustment_enable); ClassDB::bind_method(D_METHOD("is_adjustment_enabled"), &Environment::is_adjustment_enabled); @@ -1244,6 +1291,7 @@ Environment::Environment() : glow_hdr_bleed_scale = 2.0; glow_bicubic_upscale = false; glow_high_quality = false; + glow_map_strength = 0.8f; dof_blur_far_enabled = false; dof_blur_far_distance = 10; diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 9fbf703e1bcf..2aa1f62a546c 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -147,6 +147,11 @@ class Environment : public Resource { float glow_hdr_luminance_cap; bool glow_bicubic_upscale; bool glow_high_quality; + float glow_map_strength; + Ref glow_map; + + void _update_glow(); + void _update_glow_map(); bool dof_blur_far_enabled; float dof_blur_far_distance; @@ -337,6 +342,12 @@ class Environment : public Resource { void set_glow_high_quality(bool p_enable); bool is_glow_high_quality_enabled() const; + void set_glow_map_strength(float p_glow_map_strength); + float get_glow_map_strength() const; + + void set_glow_map(Ref p_glow_map); + Ref get_glow_map() const; + void set_dof_blur_far_enabled(bool p_enable); bool is_dof_blur_far_enabled() const; diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index a3f221606157..edf7f9451a4e 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -231,12 +231,14 @@ AudioStreamPlaybackMicrophone::AudioStreamPlaybackMicrophone() { //////////////////////////////// void AudioStreamRandomPitch::set_audio_stream(const Ref &p_audio_stream) { + AudioServer::get_singleton()->lock(); audio_stream = p_audio_stream; if (audio_stream.is_valid()) { for (Set::Element *E = playbacks.front(); E; E = E->next()) { E->get()->playback = audio_stream->instance_playback(); } } + AudioServer::get_singleton()->unlock(); } Ref AudioStreamRandomPitch::get_audio_stream() const { diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 17dee11b2884..2b2259cc17f0 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -66,6 +66,7 @@ class RasterizerScene { virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) = 0; virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) = 0; virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale, bool p_high_quality) = 0; + virtual void environment_set_glow_map(RID p_env, float p_glow_map_strength, RID p_glow_map) = 0; virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) = 0; virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) = 0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 589446ce4c33..6d088c09c3ec 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -542,6 +542,7 @@ class VisualServerRaster : public VisualServer { BIND6(environment_set_dof_blur_near, RID, bool, float, float, float, EnvironmentDOFBlurQuality) BIND6(environment_set_dof_blur_far, RID, bool, float, float, float, EnvironmentDOFBlurQuality) BIND12(environment_set_glow, RID, bool, int, float, float, float, EnvironmentGlowBlendMode, float, float, float, bool, bool) + BIND3(environment_set_glow_map, RID, float, RID) BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float) diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index e934962594d3..6ba16fb7786f 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -453,6 +453,7 @@ class VisualServerWrapMT : public VisualServer { FUNC6(environment_set_dof_blur_near, RID, bool, float, float, float, EnvironmentDOFBlurQuality) FUNC6(environment_set_dof_blur_far, RID, bool, float, float, float, EnvironmentDOFBlurQuality) FUNC12(environment_set_glow, RID, bool, int, float, float, float, EnvironmentGlowBlendMode, float, float, float, bool, bool) + FUNC3(environment_set_glow_map, RID, float, RID) FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index a9399e32b0c9..f13470cf11de 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2147,6 +2147,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_dof_blur_near", "env", "enable", "distance", "transition", "far_amount", "quality"), &VisualServer::environment_set_dof_blur_near); ClassDB::bind_method(D_METHOD("environment_set_dof_blur_far", "env", "enable", "distance", "transition", "far_amount", "quality"), &VisualServer::environment_set_dof_blur_far); ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "level_flags", "intensity", "strength", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap", "bicubic_upscale", "high_quality"), &VisualServer::environment_set_glow); + ClassDB::bind_method(D_METHOD("environment_set_glow_map", "env", "glow_map_strength", "glow_map"), &VisualServer::environment_set_glow_map); ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &VisualServer::environment_set_tonemap); ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "ramp"), &VisualServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance", "roughness"), &VisualServer::environment_set_ssr); diff --git a/servers/visual_server.h b/servers/visual_server.h index 71fbaa03da8c..9668be06c56f 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -796,6 +796,7 @@ class VisualServer : public Object { GLOW_BLEND_MODE_REPLACE, }; virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale, bool p_high_quality) = 0; + virtual void environment_set_glow_map(RID p_env, float p_glow_map_strength, RID p_glow_map) = 0; enum EnvironmentToneMapper { ENV_TONE_MAPPER_LINEAR,