diff options
108 files changed, 1346 insertions, 792 deletions
diff --git a/core/image.cpp b/core/image.cpp index 10778eced6..5ce744f709 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -83,6 +83,7 @@ const char *Image::format_names[Image::FORMAT_MAX] = { }; SavePNGFunc Image::save_png_func = NULL; +SaveEXRFunc Image::save_exr_func = NULL; void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel) { @@ -1917,6 +1918,14 @@ Error Image::save_png(const String &p_path) const { return save_png_func(p_path, Ref<Image>((Image *)this)); } +Error Image::save_exr(const String &p_path, bool p_grayscale) const { + + if (save_exr_func == NULL) + return ERR_UNAVAILABLE; + + return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale); +} + int Image::get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps) { int mm; @@ -2746,6 +2755,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("load", "path"), &Image::load); ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png); + ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false)); ClassDB::bind_method(D_METHOD("detect_alpha"), &Image::detect_alpha); ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible); diff --git a/core/image.h b/core/image.h index cc796789cd..d17571399d 100644 --- a/core/image.h +++ b/core/image.h @@ -49,11 +49,14 @@ class Image; typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img); typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size); +typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale); + class Image : public Resource { GDCLASS(Image, Resource); public: static SavePNGFunc save_png_func; + static SaveEXRFunc save_exr_func; enum { MAX_WIDTH = 16384, // force a limit somehow @@ -258,6 +261,7 @@ public: Error load(const String &p_path); Error save_png(const String &p_path) const; + Error save_exr(const String &p_path, bool p_grayscale) const; /** * create an empty image diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index 6c4310a572..102cd9cf6c 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -208,7 +208,8 @@ void FileAccessCompressed::seek(size_t p_position) { if (p_position == read_total) { at_end = true; } else { - + at_end = false; + read_eof = false; int block_idx = p_position / block_size; if (block_idx != read_block) { diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index a29b9d1ddb..35af58ad07 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -940,8 +940,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { ERR_EXPLAIN("Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt)); ERR_FAIL_COND_V(obj == NULL, false); - ResourceFormatLoader *crl = NULL; - crl = Object::cast_to<ResourceFormatLoader>(obj); + ResourceFormatLoader *crl = Object::cast_to<ResourceFormatLoader>(obj); crl->set_script(s.get_ref_ptr()); ResourceLoader::add_resource_format_loader(crl); diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index e2c1c3402a..369cd93442 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -222,8 +222,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { ERR_EXPLAIN("Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt)); ERR_FAIL_COND_V(obj == NULL, false); - ResourceFormatSaver *crl = NULL; - crl = Object::cast_to<ResourceFormatSaver>(obj); + ResourceFormatSaver *crl = Object::cast_to<ResourceFormatSaver>(obj); crl->set_script(s.get_ref_ptr()); ResourceSaver::add_resource_format_saver(crl); diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp index 9b342ef913..48a30f6702 100644 --- a/core/pool_allocator.cpp +++ b/core/pool_allocator.cpp @@ -539,6 +539,10 @@ void PoolAllocator::unlock(ID p_mem) { return; mt_lock(); Entry *e = get_entry(p_mem); + if (!e) { + mt_unlock(); + ERR_FAIL_COND(!e); + } if (e->lock == 0) { mt_unlock(); ERR_PRINT("e->lock == 0"); diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index e7ff7a3aef..5f01e043c4 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -357,10 +357,11 @@ void ScriptDebuggerRemote::_get_output() { locking = false; } - if (n_errors_dropped > 0) { + if (n_errors_dropped == 1) { + // Only print one message about dropping per second OutputError oe; oe.error = "TOO_MANY_ERRORS"; - oe.error_descr = "Too many errors! " + String::num_int64(n_errors_dropped) + " errors were dropped."; + oe.error_descr = "Too many errors! Ignoring errors for up to 1 second."; oe.warning = false; uint64_t time = OS::get_singleton()->get_ticks_msec(); oe.hr = time / 3600000; @@ -368,7 +369,20 @@ void ScriptDebuggerRemote::_get_output() { oe.sec = (time / 1000) % 60; oe.msec = time % 1000; errors.push_back(oe); - n_errors_dropped = 0; + } + + if (n_warnings_dropped == 1) { + // Only print one message about dropping per second + OutputError oe; + oe.error = "TOO_MANY_WARNINGS"; + oe.error_descr = "Too many warnings! Ignoring warnings for up to 1 second."; + oe.warning = true; + uint64_t time = OS::get_singleton()->get_ticks_msec(); + oe.hr = time / 3600000; + oe.min = (time / 60000) % 60; + oe.sec = (time / 1000) % 60; + oe.msec = time % 1000; + errors.push_back(oe); } while (errors.size()) { @@ -934,6 +948,19 @@ void ScriptDebuggerRemote::send_error(const String &p_func, const String &p_file oe.msec = time % 1000; Array cstack; + uint64_t ticks = OS::get_singleton()->get_ticks_usec() / 1000; + msec_count += ticks - last_msec; + last_msec = ticks; + + if (msec_count > 1000) { + msec_count = 0; + + err_count = 0; + n_errors_dropped = 0; + warn_count = 0; + n_warnings_dropped = 0; + } + cstack.resize(p_stack_info.size() * 3); for (int i = 0; i < p_stack_info.size(); i++) { cstack[i * 3 + 0] = p_stack_info[i].file; @@ -942,15 +969,28 @@ void ScriptDebuggerRemote::send_error(const String &p_func, const String &p_file } oe.callstack = cstack; + if (oe.warning) { + warn_count++; + } else { + err_count++; + } mutex->lock(); if (!locking && tcp_client->is_connected_to_host()) { - if (errors.size() >= max_errors_per_frame) { - n_errors_dropped++; + if (oe.warning) { + if (warn_count > max_warnings_per_second) { + n_warnings_dropped++; + } else { + errors.push_back(oe); + } } else { - errors.push_back(oe); + if (err_count > max_errors_per_second) { + n_errors_dropped++; + } else { + errors.push_back(oe); + } } } @@ -1070,10 +1110,13 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() : mutex(Mutex::create()), max_messages_per_frame(GLOBAL_GET("network/limits/debugger_stdout/max_messages_per_frame")), n_messages_dropped(0), - max_errors_per_frame(GLOBAL_GET("network/limits/debugger_stdout/max_errors_per_frame")), + max_errors_per_second(GLOBAL_GET("network/limits/debugger_stdout/max_errors_per_second")), + max_warnings_per_second(GLOBAL_GET("network/limits/debugger_stdout/max_warnings_per_second")), n_errors_dropped(0), max_cps(GLOBAL_GET("network/limits/debugger_stdout/max_chars_per_second")), char_count(0), + err_count(0), + warn_count(0), last_msec(0), msec_count(0), locking(false), diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h index 1fc9d7c7f1..a5bfd7a32d 100644 --- a/core/script_debugger_remote.h +++ b/core/script_debugger_remote.h @@ -91,11 +91,15 @@ class ScriptDebuggerRemote : public ScriptDebugger { int max_messages_per_frame; int n_messages_dropped; List<OutputError> errors; - int max_errors_per_frame; + int max_errors_per_second; + int max_warnings_per_second; int n_errors_dropped; + int n_warnings_dropped; int max_cps; int char_count; + int err_count; + int warn_count; uint64_t last_msec; uint64_t msec_count; diff --git a/core/translation.cpp b/core/translation.cpp index 0b55badc61..a3ff971f45 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -1044,6 +1044,13 @@ StringName TranslationServer::translate(const StringName &p_message) const { if (!enabled) return p_message; + // Locale can be of the form 'll_CC', i.e. language code and regional code, + // e.g. 'en_US', 'en_GB', etc. It might also be simply 'll', e.g. 'en'. + // To find the relevant translation, we look for those with locale starting + // with the language code, and then if any is an exact match for the long + // form. If not found, we fall back to a near match (another locale with + // same language code). + StringName res; bool near_match = false; const CharType *lptr = &locale[0]; @@ -1053,13 +1060,11 @@ StringName TranslationServer::translate(const StringName &p_message) const { const Ref<Translation> &t = E->get(); String l = t->get_locale(); if (lptr[0] != l[0] || lptr[1] != l[1]) - continue; // locale not match - - //near match - bool match = (l != locale); + continue; // Language code does not match. - if (near_match && !match) - continue; //only near-match once + bool exact_match = (l == locale); + if (!exact_match && near_match) + continue; // Only near-match once, but keep looking for exact matches. StringName r = t->get_message(p_message); @@ -1068,43 +1073,38 @@ StringName TranslationServer::translate(const StringName &p_message) const { res = r; - if (match) + if (exact_match) break; else near_match = true; } - if (!res) { - //try again with fallback - if (fallback.length() >= 2) { - - const CharType *fptr = &fallback[0]; - near_match = false; - for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) { + if (!res && fallback.length() >= 2) { + // Try again with the fallback locale. + const CharType *fptr = &fallback[0]; + near_match = false; + for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) { - const Ref<Translation> &t = E->get(); - String l = t->get_locale(); - if (fptr[0] != l[0] || fptr[1] != l[1]) - continue; // locale not match + const Ref<Translation> &t = E->get(); + String l = t->get_locale(); + if (fptr[0] != l[0] || fptr[1] != l[1]) + continue; // Language code does not match. - //near match - bool match = (l != fallback); + bool exact_match = (l == fallback); + if (!exact_match && near_match) + continue; // Only near-match once, but keep looking for exact matches. - if (near_match && !match) - continue; //only near-match once + StringName r = t->get_message(p_message); - StringName r = t->get_message(p_message); + if (!r) + continue; - if (!r) - continue; + res = r; - res = r; - - if (match) - break; - else - near_match = true; - } + if (exact_match) + break; + else + near_match = true; } } diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml index 7581ae6935..6f82b103db 100644 --- a/doc/classes/AudioServer.xml +++ b/doc/classes/AudioServer.xml @@ -42,6 +42,7 @@ <return type="Array"> </return> <description> + Returns the names of all audio input devices detected on the system. </description> </method> <method name="capture_set_device"> @@ -52,6 +53,20 @@ <description> </description> </method> + <method name="capture_start"> + <return type="int" enum="Error"> + </return> + <description> + Attempts to start recording from the audio driver's capture device. On success, the return value is [constant OK]. + </description> + </method> + <method name="capture_stop"> + <return type="int" enum="Error"> + </return> + <description> + Attempts to stop recording from the audio driver's capture device. On success, the return value is [constant OK]. + </description> + </method> <method name="generate_bus_layout" qualifiers="const"> <return type="AudioBusLayout"> </return> @@ -158,11 +173,32 @@ Returns the volume of the bus at index [code]bus_idx[/code] in dB. </description> </method> + <method name="get_capture_buffer"> + <return type="PoolIntArray"> + </return> + <description> + Returns an [PoolIntArray] containing audio frames from the capture device. + </description> + </method> + <method name="get_capture_position"> + <return type="int"> + </return> + <description> + Returns the write position of the capture device buffer. + </description> + </method> + <method name="get_capture_size"> + <return type="int"> + </return> + <description> + Returns the size of the capture device buffer. + </description> + </method> <method name="get_device_list"> <return type="Array"> </return> <description> - Returns the names of all audio devices detected on the system. + Returns the names of all audio output devices detected on the system. </description> </method> <method name="get_mix_rate" qualifiers="const"> @@ -388,7 +424,10 @@ Number of available audio buses. </member> <member name="device" type="String" setter="set_device" getter="get_device" default=""Default""> - Name of the current device (see [method get_device_list]). + Name of the current device for audio output (see [method get_device_list]). + </member> + <member name="capture_device" type="String" setter="capture_set_device" getter="capture_get_device" default=""Default""> + Name of the current device for audio input (see [method capture_get_device_list]). </member> <member name="global_rate_scale" type="float" setter="set_global_rate_scale" getter="get_global_rate_scale" default="1.0"> Scales the rate at which audio is played (i.e. setting it to [code]0.5[/code] will make the audio be played twice as fast). diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml index 750b6851b6..f524a02934 100644 --- a/doc/classes/Camera2D.xml +++ b/doc/classes/Camera2D.xml @@ -154,9 +154,11 @@ </member> <member name="offset_h" type="float" setter="set_h_offset" getter="get_h_offset" default="0.0"> The horizontal offset of the camera, relative to the drag margins. + [b]Note:[/b] Offset H is used only to force offset relative to margins. It's not updated in any way if drag margins are enabled and can be used to set inital offset. </member> <member name="offset_v" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0"> The vertical offset of the camera, relative to the drag margins. + [b]Note:[/b] Used the same as [member offset_h]. </member> <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Camera2D.Camera2DProcessMode" default="1"> </member> diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml index 80b5e90717..93c42a85a3 100644 --- a/doc/classes/CheckBox.xml +++ b/doc/classes/CheckBox.xml @@ -14,6 +14,7 @@ </constants> <theme_items> <theme_item name="check_vadjust" type="int" default="0"> + The vertical offset used when rendering the check icons. </theme_item> <theme_item name="checked" type="Texture"> </theme_item> diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml index f4d0e0657b..4744894fc1 100644 --- a/doc/classes/CheckButton.xml +++ b/doc/classes/CheckButton.xml @@ -14,6 +14,7 @@ </constants> <theme_items> <theme_item name="check_vadjust" type="int" default="0"> + The vertical offset used when rendering the icons. </theme_item> <theme_item name="disabled" type="StyleBox"> </theme_item> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 69fec750a2..6c3cf66c20 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -21,13 +21,16 @@ <return type="bool"> </return> <description> + Virtual method to be implemented by the user. Returns whether [method _gui_input] should not be called for children controls outside this control's rectangle. Input will be clipped to the Rect of this [Control]. Similar to [member rect_clip_content], but doesn't affect visibility. + If not overriden, defaults to [code]false[/code]. </description> </method> <method name="_get_minimum_size" qualifiers="virtual"> <return type="Vector2"> </return> <description> - Returns the minimum size for this control. See [member rect_min_size]. + Virtual method to be implemented by the user. Returns the minimum size for this control. Alternative to [member rect_min_size] for controlling minimum size via code. The actual minimum size will be the max value of these two (in each axis separately). + If not overriden, defaults to [constant Vector2.ZERO]. </description> </method> <method name="_gui_input" qualifiers="virtual"> @@ -36,8 +39,20 @@ <argument index="0" name="event" type="InputEvent"> </argument> <description> - Use this method to process and accept inputs on UI elements. See [method accept_event]. - Replaces Godot 2's [code]_input_event[/code]. + Virtual method to be implemented by the user. Use this method to process and accept inputs on UI elements. See [method accept_event]. + Example: clicking a control. + [codeblock] + func _gui_input(event): + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT and event.pressed: + print("I've been clicked D:") + [/codeblock] + The event won't trigger if: + * clicking outside the control (see [method has_point]); + * control has [member mouse_filter] set to [member MOUSE_FILTER_IGNORE]; + * control is obstructed by another [Control] on top of it, which doesn't have [member mouse_filter] set to [member MOUSE_FILTER_IGNORE]; + * control's parent has [member mouse_filter] set to [member MOUSE_FILTER_STOP] or has accepted the event; + * it happens outside parent's rectangle and the parent has either [member rect_clip_content] or [member _clips_input] enabled. </description> </method> <method name="_make_custom_tooltip" qualifiers="virtual"> @@ -46,6 +61,23 @@ <argument index="0" name="for_text" type="String"> </argument> <description> + Virtual method to be implemented by the user. Returns a [Control] node that should be used as a tooltip instead of the default one. Use [code]for_text[/code] parameter to determine what text the tooltip should contain (likely the contents of [member hint_tooltip]). + The returned node must be of type [Control] or Control-derieved. It can have child nodes of any type. It is freed when the tooltip disappears, so make sure you always provide a new instance, not e.g. a node from scene. When null or non-Control node is returned, the default tooltip will be used instead. + [b]Note:[/b] The tooltip is shrunk to miminal size. If you want to ensure it's fully visible, you might want to set its [member rect_min_size] to some non-zero value. + Example of usage with custom-constructed node: + [codeblock] + func _make_custom_tooltip(for_text): + var label = Label.new() + label.text = for_text + return label + [/codeblock] + Example of usage with custom scene instance: + [codeblock] + func _make_custom_tooltip(for_text): + var tooltip = preload("SomeTooltipScene.tscn").instance() + tooltip.get_node("Label").text = for_text + return tooltip + [/codeblock] </description> </method> <method name="accept_event"> @@ -63,7 +95,7 @@ <argument index="1" name="color" type="Color"> </argument> <description> - Overrides the color in the [member theme] resource the node uses. + Overrides the [Color] with given [code]name[/code] in the [member theme] resource the control uses. If the [code]color[/code] is empty or invalid, the override is cleared and the color from assigned [Theme] is used. </description> </method> <method name="add_constant_override"> @@ -74,7 +106,7 @@ <argument index="1" name="constant" type="int"> </argument> <description> - Overrides an integer constant in the [member theme] resource the node uses. If the [code]constant[/code] is invalid, Godot clears the override. + Overrides an integer constant with given [code]name[/code] in the [member theme] resource the control uses. If the [code]constant[/code] is empty or invalid, the override is cleared and the constant from assigned [Theme] is used. </description> </method> <method name="add_font_override"> @@ -85,7 +117,7 @@ <argument index="1" name="font" type="Font"> </argument> <description> - Overrides the [code]name[/code] font in the [member theme] resource the node uses. If [code]font[/code] is empty, Godot clears the override. + Overrides the font with given [code]name[/code] in the [member theme] resource the control uses. If [code]font[/code] is empty or invalid, the override is cleared and the font from assigned [Theme] is used. </description> </method> <method name="add_icon_override"> @@ -96,7 +128,7 @@ <argument index="1" name="texture" type="Texture"> </argument> <description> - Overrides the [code]name[/code] icon in the [member theme] resource the node uses. If [code]icon[/code] is empty, Godot clears the override. + Overrides the icon with given [code]name[/code] in the [member theme] resource the control uses. If [code]icon[/code] is empty or invalid, the override is cleared and the icon from assigned [Theme] is used. </description> </method> <method name="add_shader_override"> @@ -107,7 +139,7 @@ <argument index="1" name="shader" type="Shader"> </argument> <description> - Overrides the [code]name[/code] shader in the [member theme] resource the node uses. If [code]shader[/code] is empty, Godot clears the override. + Overrides the [Shader] with given [code]name[/code] in the [member theme] resource the control uses. If [code]shader[/code] is empty or invalid, the override is cleared and the shader from assigned [Theme] is used. </description> </method> <method name="add_stylebox_override"> @@ -118,7 +150,7 @@ <argument index="1" name="stylebox" type="StyleBox"> </argument> <description> - Overrides the [code]name[/code] [StyleBox] in the [member theme] resource the node uses. If [code]stylebox[/code] is empty, Godot clears the override. + Overrides the [StyleBox] with given [code]name[/code] in the [member theme] resource the control uses. If [code]stylebox[/code] is empty or invalid, the override is cleared and the [StyleBox] from assigned [Theme] is used. </description> </method> <method name="can_drop_data" qualifiers="virtual"> @@ -132,8 +164,6 @@ Godot calls this method to test if [code]data[/code] from a control's [method get_drag_data] can be dropped at [code]position[/code]. [code]position[/code] is local to this control. This method should only be used to test the data. Process the data in [method drop_data]. [codeblock] - extends Control - func can_drop_data(position, data): # Check position if it is relevant to you # Otherwise, just check data @@ -151,8 +181,6 @@ <description> Godot calls this method to pass you the [code]data[/code] from a control's [method get_drag_data] result. Godot first calls [method can_drop_data] to test if [code]data[/code] is allowed to drop at [code]position[/code] where [code]position[/code] is local to this control. [codeblock] - extends ColorRect - func can_drop_data(position, data): return typeof(data) == TYPE_DICTIONARY and data.has("color") @@ -179,6 +207,7 @@ <argument index="0" name="margin" type="int" enum="Margin"> </argument> <description> + Returns the anchor identified by [code]margin[/code] constant from [enum Margin] enum. A getter method for [member anchor_bottom], [member anchor_left], [member anchor_right] and [member anchor_top]. </description> </method> <method name="get_begin" qualifiers="const"> @@ -196,12 +225,18 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns a color from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code]. + [codeblock] + func _ready(): + modulate = get_color("font_color", "Button") #get the color defined for button fonts + [/codeblock] </description> </method> <method name="get_combined_minimum_size" qualifiers="const"> <return type="Vector2"> </return> <description> + Returns combined minimum size from [member rect_min_size] and [method get_minimum_size]. </description> </method> <method name="get_constant" qualifiers="const"> @@ -212,6 +247,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns a constant from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code]. </description> </method> <method name="get_cursor_shape" qualifiers="const"> @@ -232,8 +268,6 @@ Godot calls this method to get data that can be dragged and dropped onto controls that expect drop data. Returns [code]null[/code] if there is no data to drag. Controls that want to receive drop data should implement [method can_drop_data] and [method drop_data]. [code]position[/code] is local to this control. Drag may be forced with [method force_drag]. A preview that will follow the mouse that should represent the data can be set with [method set_drag_preview]. A good time to set the preview is in this method. [codeblock] - extends Control - func get_drag_data(position): var mydata = make_data() set_drag_preview(make_preview(mydata)) @@ -254,6 +288,7 @@ <argument index="0" name="margin" type="int" enum="Margin"> </argument> <description> + Returns the focus neighbour identified by [code]margin[/code] constant from [enum Margin] enum. A getter method for [member focus_neighbour_bottom], [member focus_neighbour_left], [member focus_neighbour_right] and [member focus_neighbour_top]. </description> </method> <method name="get_focus_owner" qualifiers="const"> @@ -271,6 +306,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns a font from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code]. </description> </method> <method name="get_global_rect" qualifiers="const"> @@ -288,6 +324,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns an icon from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code]. </description> </method> <method name="get_margin" qualifiers="const"> @@ -296,6 +333,7 @@ <argument index="0" name="margin" type="int" enum="Margin"> </argument> <description> + Returns the anchor identified by [code]margin[/code] constant from [enum Margin] enum. A getter method for [member margin_bottom], [member margin_left], [member margin_right] and [member margin_top]. </description> </method> <method name="get_minimum_size" qualifiers="const"> @@ -341,6 +379,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns a [StyleBox] from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code]. </description> </method> <method name="get_tooltip" qualifiers="const"> @@ -349,13 +388,18 @@ <argument index="0" name="at_position" type="Vector2" default="Vector2( 0, 0 )"> </argument> <description> - Returns the tooltip, which will appear when the cursor is resting over this control. + Returns the tooltip, which will appear when the cursor is resting over this control. See [member]hint_tooltip[/member]. </description> </method> <method name="grab_click_focus"> <return type="void"> </return> <description> + Creates an [InputEventMouseButton] that attempts to click the control. If the event is received, the control aquires focus. + [codeblock] + func _process(delta): + grab_click_focus() #when clicking another Control node, this node will be clicked instead + [/codeblock] </description> </method> <method name="grab_focus"> @@ -373,6 +417,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns [code]true[/code] if [Color] with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme]. </description> </method> <method name="has_color_override" qualifiers="const"> @@ -381,6 +426,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if [Color] with given [code]name[/code] has a valid override in this [Control] node. </description> </method> <method name="has_constant" qualifiers="const"> @@ -391,6 +437,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns [code]true[/code] if constant with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme]. </description> </method> <method name="has_constant_override" qualifiers="const"> @@ -399,6 +446,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if constant with given [code]name[/code] has a valid override in this [Control] node. </description> </method> <method name="has_focus" qualifiers="const"> @@ -416,6 +464,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns [code]true[/code] if font with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme]. </description> </method> <method name="has_font_override" qualifiers="const"> @@ -424,6 +473,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if font with given [code]name[/code] has a valid override in this [Control] node. </description> </method> <method name="has_icon" qualifiers="const"> @@ -434,6 +484,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns [code]true[/code] if icon with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme]. </description> </method> <method name="has_icon_override" qualifiers="const"> @@ -442,6 +493,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if icon with given [code]name[/code] has a valid override in this [Control] node. </description> </method> <method name="has_point" qualifiers="virtual"> @@ -450,6 +502,9 @@ <argument index="0" name="point" type="Vector2"> </argument> <description> + Virtual method to be implemented by the user. Returns whether the given [code]point[/code] is inside this control. + If not overriden, default behavior is checking if the point is within control's Rect. + [b]Node:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code]. </description> </method> <method name="has_shader_override" qualifiers="const"> @@ -458,6 +513,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if [Shader] with given [code]name[/code] has a valid override in this [Control] node. </description> </method> <method name="has_stylebox" qualifiers="const"> @@ -468,6 +524,7 @@ <argument index="1" name="type" type="String" default=""""> </argument> <description> + Returns [code]true[/code] if [StyleBox] with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme]. </description> </method> <method name="has_stylebox_override" qualifiers="const"> @@ -476,12 +533,14 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if [StyleBox] with given [code]name[/code] has a valid override in this [Control] node. </description> </method> <method name="minimum_size_changed"> <return type="void"> </return> <description> + Invalidates the size cache in this node and in parent nodes up to toplevel. Intended to be used with [method get_minimum_size] when the return value is changed. Setting [member rect_min_size] directly calls this method automatically. </description> </method> <method name="release_focus"> @@ -503,6 +562,9 @@ <argument index="3" name="push_opposite_anchor" type="bool" default="true"> </argument> <description> + Sets the anchor identified by [code]margin[/code] constant from [enum Margin] enum to value [code]anchor[/code]. A setter method for [member anchor_bottom], [member anchor_left], [member anchor_right] and [member anchor_top]. + If [code]keep_margin[/code] is [code]true[/code], margins aren't updated after this operation. + If [code]push_opposite_anchor[/code] is [code]true[/code] and the opposite anchor overlaps this anchor, the opposite one will have its value overriden. For example, when setting left anchor to 1 and the right anchor has value of 0.5, the right anchor will also get value of 1. If [code]push_opposite_anchor[/code] was [code]false[/code], the left anchor would get value 0.5. </description> </method> <method name="set_anchor_and_margin"> @@ -517,6 +579,7 @@ <argument index="3" name="push_opposite_anchor" type="bool" default="false"> </argument> <description> + Works the same as [method set_anchor], but instead of [code]keep_margin[/code] argument and automatic update of margin, it allows to set the margin offset yourself (see [method set_margin]). </description> </method> <method name="set_anchors_and_margins_preset"> @@ -529,6 +592,7 @@ <argument index="2" name="margin" type="int" default="0"> </argument> <description> + Sets both anchor preset and margin preset. See [method set_anchors_preset] and [method set_margins_preset]. </description> </method> <method name="set_anchors_preset"> @@ -539,6 +603,8 @@ <argument index="1" name="keep_margins" type="bool" default="false"> </argument> <description> + Sets the anchors to a [code]preset[/code] from [enum Control.LayoutPreset] enum. This is code equivalent of using the Layout menu in 2D editor. + If [code]keep_margins[/code] is [code]true[/code], control's position will also be updated. </description> </method> <method name="set_begin"> @@ -547,7 +613,7 @@ <argument index="0" name="position" type="Vector2"> </argument> <description> - Sets [member margin_left] and [member margin_top] at the same time. + Sets [member margin_left] and [member margin_top] at the same time. Equivalent of changing [member rect_position]. </description> </method> <method name="set_drag_forwarding"> @@ -606,6 +672,7 @@ <argument index="1" name="neighbour" type="NodePath"> </argument> <description> + Sets the anchor identified by [code]margin[/code] constant from [enum Margin] enum to [Control] at [code]neighbor[/code] node path. A setter method for [member focus_neighbour_bottom], [member focus_neighbour_left], [member focus_neighbour_right] and [member focus_neighbour_top]. </description> </method> <method name="set_global_position"> @@ -616,6 +683,8 @@ <argument index="1" name="keep_margins" type="bool" default="false"> </argument> <description> + Sets the [member rect_global_position] to given [code]position[/code]. + If [code]keep_margins[/code] is [code]true[/code], control's anchors will be updated instead of margins. </description> </method> <method name="set_margin"> @@ -626,6 +695,7 @@ <argument index="1" name="offset" type="float"> </argument> <description> + Sets the margin identified by [code]margin[/code] constant from [enum Margin] enum to given [code]offset[/code]. A setter method for [member margin_bottom], [member margin_left], [member margin_right] and [member margin_top]. </description> </method> <method name="set_margins_preset"> @@ -638,6 +708,9 @@ <argument index="2" name="margin" type="int" default="0"> </argument> <description> + Sets the margins to a [code]preset[/code] from [enum Control.LayoutPreset] enum. This is code equivalent of using the Layout menu in 2D editor. + Use parameter [code]resize_mode[/code] with constants from [enum Control.LayoutPresetMode] to better determine the resulting size of the [Control]. Constant size will be ignored if used with presets that change size, e.g. [code]PRESET_LEFT_WIDE[/code]. + Use parameter [code]margin[/code] to determine the gap between the [Control] and the edges. </description> </method> <method name="set_position"> @@ -648,6 +721,8 @@ <argument index="1" name="keep_margins" type="bool" default="false"> </argument> <description> + Sets the [member rect_position] to given [code]position[/code]. + If [code]keep_margins[/code] is [code]true[/code], control's anchors will be updated instead of margins. </description> </method> <method name="set_rotation"> @@ -667,6 +742,8 @@ <argument index="1" name="keep_margins" type="bool" default="false"> </argument> <description> + Sets the size (see [member rect_size]). + If [code]keep_margins[/code] is [code]true[/code], control's anchors will be updated instead of margins. </description> </method> <method name="show_modal"> @@ -676,6 +753,7 @@ </argument> <description> Displays a control as modal. Control must be a subwindow. Modal controls capture the input signals until closed or the area outside them is accessed. When a modal control loses focus, or the ESC key is pressed, they automatically hide. Modal controls are used extensively for popup dialogs and menus. + If [code]exclusive[/code] is [code]true[/code], other controls will not receive input and clicking outside this control will not close it. </description> </method> <method name="warp_mouse"> @@ -684,21 +762,22 @@ <argument index="0" name="to_position" type="Vector2"> </argument> <description> + Moves the mouse cursor to [code]to_position[/code], relative to [member rect_position] of this [Control]. </description> </method> </methods> <members> <member name="anchor_bottom" type="float" setter="_set_anchor" getter="get_anchor" default="0.0"> - Anchors the bottom edge of the node to the origin, the center, or the end of its parent control. It changes how the bottom margin updates when the node moves or changes size. You can use one of the [code]ANCHOR_*[/code] constants for convenience. + Anchors the bottom edge of the node to the origin, the center, or the end of its parent control. It changes how the bottom margin updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience. </member> <member name="anchor_left" type="float" setter="_set_anchor" getter="get_anchor" default="0.0"> - Anchors the left edge of the node to the origin, the center or the end of its parent control. It changes how the left margin updates when the node moves or changes size. You can use one of the [code]ANCHOR_*[/code] constants for convenience. + Anchors the left edge of the node to the origin, the center or the end of its parent control. It changes how the left margin updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience. </member> <member name="anchor_right" type="float" setter="_set_anchor" getter="get_anchor" default="0.0"> - Anchors the right edge of the node to the origin, the center or the end of its parent control. It changes how the right margin updates when the node moves or changes size. You can use one of the [code]ANCHOR_*[/code] constants for convenience. + Anchors the right edge of the node to the origin, the center or the end of its parent control. It changes how the right margin updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience. </member> <member name="anchor_top" type="float" setter="_set_anchor" getter="get_anchor" default="0.0"> - Anchors the top edge of the node to the origin, the center or the end of its parent control. It changes how the top margin updates when the node moves or changes size. You can use one of the [code]ANCHOR_*[/code] constants for convenience. + Anchors the top edge of the node to the origin, the center or the end of its parent control. It changes how the top margin updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience. </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0"> The focus access mode for the control (None, Click or All). Only one Control can be focused at the same time, and it will receive keyboard signals. @@ -730,7 +809,7 @@ Controls the direction on the vertical axis in which the control should grow if its vertical minimum size is changed to be greater than its current size, as the control always has to be at least the minimum size. </member> <member name="hint_tooltip" type="String" setter="set_tooltip" getter="_get_tooltip" default=""""> - Changes the tooltip text. The tooltip appears when the user's mouse cursor stays idle over this control for a few moments, provided that the [member mouse_filter] property is not [constant MOUSE_FILTER_IGNORE]. + Changes the tooltip text. The tooltip appears when the user's mouse cursor stays idle over this control for a few moments, provided that the [member mouse_filter] property is not [constant MOUSE_FILTER_IGNORE]. You can change the time required for the tooltip to appear with [code]gui/timers/tooltip_delay_sec[/code] option in Project Settings. </member> <member name="margin_bottom" type="float" setter="set_margin" getter="get_margin" default="0.0"> Distance between the node's bottom edge and its parent control, based on [member anchor_bottom]. @@ -780,13 +859,13 @@ The size of the node's bounding rectangle, in pixels. [Container] nodes update this property automatically. </member> <member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" default="1"> - Tells the parent [Container] nodes how they should resize and place the node on the X axis. Use one of the [code]SIZE_*[/code] constants to change the flags. See the constants to learn what each does. + Tells the parent [Container] nodes how they should resize and place the node on the X axis. Use one of the [enum SizeFlags] constants to change the flags. See the constants to learn what each does. </member> <member name="size_flags_stretch_ratio" type="float" setter="set_stretch_ratio" getter="get_stretch_ratio" default="1.0"> If the node and at least one of its neighbours uses the [constant SIZE_EXPAND] size flag, the parent [Container] will let it take more or less space depending on this property. If this node has a stretch ratio of 2 and its neighbour a ratio of 1, this node will take two thirds of the available space. </member> <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" default="1"> - Tells the parent [Container] nodes how they should resize and place the node on the Y axis. Use one of the [code]SIZE_*[/code] constants to change the flags. See the constants to learn what each does. + Tells the parent [Container] nodes how they should resize and place the node on the Y axis. Use one of the [enum SizeFlags] constants to change the flags. See the constants to learn what each does. </member> <member name="theme" type="Theme" setter="set_theme" getter="get_theme"> Changing this property replaces the current [Theme] resource this node and all its [Control] children use. @@ -978,12 +1057,16 @@ Snap all 4 anchors to the respective corners of the parent control. Set all 4 margins to 0 after you applied this preset and the [Control] will fit its parent control. This is equivalent to the "Full Rect" layout option in the editor. Use with [method set_anchors_preset]. </constant> <constant name="PRESET_MODE_MINSIZE" value="0" enum="LayoutPresetMode"> + The control will be resized to its minimum size. </constant> <constant name="PRESET_MODE_KEEP_WIDTH" value="1" enum="LayoutPresetMode"> + The control's width will not change. </constant> <constant name="PRESET_MODE_KEEP_HEIGHT" value="2" enum="LayoutPresetMode"> + The control's height will not change. </constant> <constant name="PRESET_MODE_KEEP_SIZE" value="3" enum="LayoutPresetMode"> + The control's size will not change. </constant> <constant name="SIZE_FILL" value="1" enum="SizeFlags"> Tells the parent [Container] to expand the bounds of this node to fill all the available space without pushing any other node. Use with [member size_flags_horizontal] and [member size_flags_vertical]. diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 8cd69ba0da..a4df0d5c19 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -415,6 +415,17 @@ Saves the image as a PNG file to [code]path[/code]. </description> </method> + <method name="save_exr" qualifiers="const"> + <return type="int" enum="Error"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="grayscale" type="bool" default="false"> + </argument> + <description> + Saves the image as an EXR file to [code]path[/code]. If grayscale is true and the image has only one channel, it will be saved explicitely as monochrome rather than one red channel. This function will return [constant ERR_UNAVAILABLE] if Godot was compiled without the TinyEXR module. + </description> + </method> <method name="set_pixel"> <return type="void"> </return> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 80d21e07ea..9f18eea0d4 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -650,12 +650,15 @@ <member name="network/limits/debugger_stdout/max_chars_per_second" type="int" setter="" getter="" default="2048"> Maximum amount of characters allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection. </member> - <member name="network/limits/debugger_stdout/max_errors_per_frame" type="int" setter="" getter="" default="10"> - Maximum amount of errors allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection. + <member name="network/limits/debugger_stdout/max_errors_per_second" type="int" setter="" getter="" default="100"> + Maximum number of errors allowed to be sent as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection. </member> <member name="network/limits/debugger_stdout/max_messages_per_frame" type="int" setter="" getter="" default="10"> Maximum amount of messages allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection. </member> + <member name="network/limits/debugger_stdout/max_warnings_per_second" type="int" setter="" getter="" default="100"> + Maximum number of warnings allowed to be sent as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection. + </member> <member name="network/limits/packet_peer_stream/max_buffer_po2" type="int" setter="" getter="" default="16"> Default size of packet peer stream for deserializing Godot data. Over this size, data is dropped. </member> diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 97d16d3a6a..3b06c47244 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -233,11 +233,11 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, if (result == noErr) { for (int i = 0; i < inNumberFrames * ad->capture_channels; i++) { int32_t sample = ad->input_buf[i] << 16; - ad->input_buffer_write(sample); + ad->capture_buffer_write(sample); if (ad->capture_channels == 1) { - // In case input device is single channel convert it to Stereo - ad->input_buffer_write(sample); + // In case capture device is single channel convert it to Stereo + ad->capture_buffer_write(sample); } } } else { @@ -487,7 +487,7 @@ void AudioDriverCoreAudio::capture_finish() { Error AudioDriverCoreAudio::capture_start() { - input_buffer_init(buffer_frames); + capture_buffer_init(buffer_frames); OSStatus result = AudioOutputUnitStart(input_unit); if (result != noErr) { @@ -642,9 +642,9 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { ERR_FAIL_COND(result != noErr); if (capture) { - // Reset audio input to keep synchronisation. - input_position = 0; - input_size = 0; + // Reset audio capture to keep synchronisation. + capture_position = 0; + capture_size = 0; } } } diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 23b01b4e09..453abeb853 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -1910,14 +1910,14 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas } } -void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform) { +void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform, bool accum_pass) { RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; //common parameters float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY]; float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - float sign = light_ptr->negative ? -1 : 1; + float sign = (light_ptr->negative && !accum_pass) ? -1 : 1; //inverse color for base pass lights only state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular); Color color = light_ptr->color * sign * energy * Math_PI; @@ -2310,6 +2310,11 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, if (accum_pass) { //accum pass force pass blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD; + if (rebind_light && light && light->light_ptr->negative) { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB; + } } if (prev_blend_mode != blend_mode) { @@ -2553,7 +2558,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, } if (rebind_light && light) { - _setup_light(light, shadow_atlas, p_view_transform); + _setup_light(light, shadow_atlas, p_view_transform, accum_pass); } if (rebind_reflection && (refprobe_1 || refprobe_2)) { diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index c95385eb24..f60ca9675e 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -694,7 +694,7 @@ public: _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0)); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); _FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas); - _FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform); + _FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform, bool accum_pass); _FORCE_INLINE_ void _setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env); _FORCE_INLINE_ void _render_geometry(RenderList::Element *p_element); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 25bab0e97a..935cb32fda 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -449,7 +449,9 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener SL::VariableDeclarationNode *var_dec_node = (SL::VariableDeclarationNode *)p_node; StringBuffer<> declaration; - + if (var_dec_node->is_const) { + declaration += "const "; + } declaration += _prestr(var_dec_node->precision); declaration += _typestr(var_dec_node->datatype); @@ -512,14 +514,16 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::Node::TYPE_ARRAY_DECLARATION: { - SL::ArrayDeclarationNode *var_dec_node = (SL::ArrayDeclarationNode *)p_node; + SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node; StringBuffer<> declaration; + if (arr_dec_node->is_const) { + declaration += "const "; + } + declaration += _prestr(arr_dec_node->precision); + declaration += _typestr(arr_dec_node->datatype); - declaration += _prestr(var_dec_node->precision); - declaration += _typestr(var_dec_node->datatype); - - for (int i = 0; i < var_dec_node->declarations.size(); i++) { + for (int i = 0; i < arr_dec_node->declarations.size(); i++) { if (i > 0) { declaration += ","; @@ -527,20 +531,20 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener declaration += " "; - declaration += _mkid(var_dec_node->declarations[i].name); + declaration += _mkid(arr_dec_node->declarations[i].name); declaration += "["; - declaration += itos(var_dec_node->declarations[i].size); + declaration += itos(arr_dec_node->declarations[i].size); declaration += "]"; - int sz = var_dec_node->declarations[i].initializer.size(); + int sz = arr_dec_node->declarations[i].initializer.size(); if (sz > 0) { declaration += "="; - declaration += _typestr(var_dec_node->datatype); + declaration += _typestr(arr_dec_node->datatype); declaration += "["; declaration += itos(sz); declaration += "]"; declaration += "("; for (int j = 0; j < sz; j++) { - declaration += _dump_node_code(var_dec_node->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + declaration += _dump_node_code(arr_dec_node->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); if (j != sz - 1) { declaration += ", "; } @@ -552,46 +556,46 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += declaration.as_string(); } break; case SL::Node::TYPE_ARRAY: { - SL::ArrayNode *var_node = (SL::ArrayNode *)p_node; + SL::ArrayNode *arr_node = (SL::ArrayNode *)p_node; - if (p_assigning && p_actions.write_flag_pointers.has(var_node->name)) { - *p_actions.write_flag_pointers[var_node->name] = true; + if (p_assigning && p_actions.write_flag_pointers.has(arr_node->name)) { + *p_actions.write_flag_pointers[arr_node->name] = true; } - if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { - String define = p_default_actions.usage_defines[var_node->name]; + if (p_default_actions.usage_defines.has(arr_node->name) && !used_name_defines.has(arr_node->name)) { + String define = p_default_actions.usage_defines[arr_node->name]; if (define.begins_with("@")) { define = p_default_actions.usage_defines[define.substr(1, define.length())]; } r_gen_code.custom_defines.push_back(define.utf8()); - used_name_defines.insert(var_node->name); + used_name_defines.insert(arr_node->name); } - if (p_actions.usage_flag_pointers.has(var_node->name) && !used_flag_pointers.has(var_node->name)) { - *p_actions.usage_flag_pointers[var_node->name] = true; - used_flag_pointers.insert(var_node->name); + if (p_actions.usage_flag_pointers.has(arr_node->name) && !used_flag_pointers.has(arr_node->name)) { + *p_actions.usage_flag_pointers[arr_node->name] = true; + used_flag_pointers.insert(arr_node->name); } - if (p_default_actions.renames.has(var_node->name)) { - code += p_default_actions.renames[var_node->name]; + if (p_default_actions.renames.has(arr_node->name)) { + code += p_default_actions.renames[arr_node->name]; } else { - code += _mkid(var_node->name); + code += _mkid(arr_node->name); } - if (var_node->call_expression != NULL) { + if (arr_node->call_expression != NULL) { code += "."; - code += _dump_node_code(var_node->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _dump_node_code(arr_node->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); } - if (var_node->index_expression != NULL) { + if (arr_node->index_expression != NULL) { code += "["; - code += _dump_node_code(var_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _dump_node_code(arr_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; } - if (var_node->name == time_name) { + if (arr_node->name == time_name) { if (current_func_name == vertex_name) { r_gen_code.uses_vertex_time = true; } diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index e0ca388da9..c7040c232b 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2522,8 +2522,8 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int v = value; GLuint *gui = (GLuint *)data; - gui[0] = v & 1 ? GL_TRUE : GL_FALSE; - gui[1] = v & 2 ? GL_TRUE : GL_FALSE; + gui[0] = (v & 1) ? GL_TRUE : GL_FALSE; + gui[1] = (v & 2) ? GL_TRUE : GL_FALSE; } break; case ShaderLanguage::TYPE_BVEC3: { diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index f826bdf5a2..d48ee7709c 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -555,7 +555,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener case SL::Node::TYPE_VARIABLE_DECLARATION: { SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node; - String declaration = _prestr(vdnode->precision) + _typestr(vdnode->datatype); + String declaration; + if (vdnode->is_const) { + declaration += "const "; + } + declaration += _prestr(vdnode->precision); + declaration += _typestr(vdnode->datatype); for (int i = 0; i < vdnode->declarations.size(); i++) { if (i > 0) { declaration += ","; @@ -609,29 +614,34 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::Node::TYPE_ARRAY_DECLARATION: { - SL::ArrayDeclarationNode *vdnode = (SL::ArrayDeclarationNode *)p_node; + SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node; - String declaration = _prestr(vdnode->precision) + _typestr(vdnode->datatype); - for (int i = 0; i < vdnode->declarations.size(); i++) { + String declaration; + if (adnode->is_const) { + declaration += "const "; + } + declaration += _prestr(adnode->precision); + declaration += _typestr(adnode->datatype); + for (int i = 0; i < adnode->declarations.size(); i++) { if (i > 0) { declaration += ","; } else { declaration += " "; } - declaration += _mkid(vdnode->declarations[i].name); + declaration += _mkid(adnode->declarations[i].name); declaration += "["; - declaration += itos(vdnode->declarations[i].size); + declaration += itos(adnode->declarations[i].size); declaration += "]"; - int sz = vdnode->declarations[i].initializer.size(); + int sz = adnode->declarations[i].initializer.size(); if (sz > 0) { declaration += "="; - declaration += _typestr(vdnode->datatype); + declaration += _typestr(adnode->datatype); declaration += "["; declaration += itos(sz); declaration += "]"; declaration += "("; for (int j = 0; j < sz; j++) { - declaration += _dump_node_code(vdnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); if (j != sz - 1) { declaration += ", "; } @@ -643,43 +653,43 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener code += declaration; } break; case SL::Node::TYPE_ARRAY: { - SL::ArrayNode *vnode = (SL::ArrayNode *)p_node; + SL::ArrayNode *anode = (SL::ArrayNode *)p_node; - if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) { - *p_actions.write_flag_pointers[vnode->name] = true; + if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) { + *p_actions.write_flag_pointers[anode->name] = true; } - if (p_default_actions.usage_defines.has(vnode->name) && !used_name_defines.has(vnode->name)) { - String define = p_default_actions.usage_defines[vnode->name]; + if (p_default_actions.usage_defines.has(anode->name) && !used_name_defines.has(anode->name)) { + String define = p_default_actions.usage_defines[anode->name]; if (define.begins_with("@")) { define = p_default_actions.usage_defines[define.substr(1, define.length())]; } r_gen_code.defines.push_back(define.utf8()); - used_name_defines.insert(vnode->name); + used_name_defines.insert(anode->name); } - if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) { - *p_actions.usage_flag_pointers[vnode->name] = true; - used_flag_pointers.insert(vnode->name); + if (p_actions.usage_flag_pointers.has(anode->name) && !used_flag_pointers.has(anode->name)) { + *p_actions.usage_flag_pointers[anode->name] = true; + used_flag_pointers.insert(anode->name); } - if (p_default_actions.renames.has(vnode->name)) - code = p_default_actions.renames[vnode->name]; + if (p_default_actions.renames.has(anode->name)) + code = p_default_actions.renames[anode->name]; else - code = _mkid(vnode->name); + code = _mkid(anode->name); - if (vnode->call_expression != NULL) { + if (anode->call_expression != NULL) { code += "."; - code += _dump_node_code(vnode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _dump_node_code(anode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); } - if (vnode->index_expression != NULL) { + if (anode->index_expression != NULL) { code += "["; - code += _dump_node_code(vnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; } - if (vnode->name == time_name) { + if (anode->name == time_name) { if (current_func_name == vertex_name) { r_gen_code.uses_vertex_time = true; } diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index a61fa449f1..7ba2175652 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -227,8 +227,8 @@ Error AudioDriverPulseAudio::init_device() { samples_out.resize(pa_buffer_size); // Reset audio input to keep synchronisation. - input_position = 0; - input_size = 0; + capture_position = 0; + capture_size = 0; return OK; } @@ -266,7 +266,10 @@ Error AudioDriverPulseAudio::init() { } while (pa_ready == 0) { - pa_mainloop_iterate(pa_ml, 1, NULL); + ret = pa_mainloop_iterate(pa_ml, 1, NULL); + if (ret < 0) { + ERR_PRINT("pa_mainloop_iterate error"); + } } if (pa_ready < 0) { @@ -460,7 +463,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { size_t bytes = pa_stream_readable_size(ad->pa_rec_str); if (bytes > 0) { const void *ptr = NULL; - size_t maxbytes = ad->input_buffer.size() * sizeof(int16_t); + size_t maxbytes = ad->capture_buffer.size() * sizeof(int16_t); bytes = MIN(bytes, maxbytes); ret = pa_stream_peek(ad->pa_rec_str, &ptr, &bytes); @@ -470,11 +473,11 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { int16_t *srcptr = (int16_t *)ptr; for (size_t i = bytes >> 1; i > 0; i--) { int32_t sample = int32_t(*srcptr++) << 16; - ad->input_buffer_write(sample); + ad->capture_buffer_write(sample); if (ad->pa_rec_map.channels == 1) { - // In case input device is single channel convert it to Stereo - ad->input_buffer_write(sample); + // In case capture device is single channel convert it to Stereo + ad->capture_buffer_write(sample); } } @@ -661,7 +664,7 @@ Error AudioDriverPulseAudio::capture_init_device() { break; default: - WARN_PRINTS("PulseAudio: Unsupported number of input channels: " + itos(pa_rec_map.channels)); + WARN_PRINTS("PulseAudio: Unsupported number of capture channels: " + itos(pa_rec_map.channels)); pa_channel_map_init_stereo(&pa_rec_map); break; } @@ -693,10 +696,10 @@ Error AudioDriverPulseAudio::capture_init_device() { ERR_FAIL_V(ERR_CANT_OPEN); } - input_buffer_init(input_buffer_frames); + capture_buffer_init(input_buffer_frames); - print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels"); - print_verbose("PulseAudio: input buffer frames: " + itos(input_buffer_frames) + " calculated latency: " + itos(input_buffer_frames * 1000 / mix_rate) + "ms"); + print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " capture channels"); + print_verbose("PulseAudio: capture buffer frames: " + itos(input_buffer_frames) + " calculated latency: " + itos(input_buffer_frames * 1000 / mix_rate) + "ms"); return OK; } diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index fea38ee95d..b0f102f1a3 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -343,8 +343,8 @@ Error AudioDriverWASAPI::init_render_device(bool reinit) { // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) samples_in.resize(buffer_frames * channels); - input_position = 0; - input_size = 0; + capture_position = 0; + capture_size = 0; print_verbose("WASAPI: detected " + itos(channels) + " channels"); print_verbose("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); @@ -363,7 +363,7 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) { HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); - input_buffer_init(max_frames); + capture_buffer_init(max_frames); return OK; } @@ -716,8 +716,8 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } } - ad->input_buffer_write(l); - ad->input_buffer_write(r); + ad->capture_buffer_write(l); + ad->capture_buffer_write(r); } read_frames += num_frames_available; diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 9b376ae090..014bb08144 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -31,6 +31,7 @@ #include "animation_track_editor.h" #include "animation_track_editor_plugins.h" +#include "core/os/input.h" #include "core/os/keyboard.h" #include "editor/animation_bezier_editor.h" #include "editor/plugins/animation_player_editor_plugin.h" @@ -4082,6 +4083,10 @@ bool AnimationTrackEditor::is_selection_active() const { return selection.size(); } +bool AnimationTrackEditor::is_snap_enabled() const { + return snap->is_pressed() ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL); +} + void AnimationTrackEditor::_update_tracks() { int selected = _get_track_selected(); @@ -5679,7 +5684,7 @@ void AnimationTrackEditor::_selection_changed() { float AnimationTrackEditor::snap_time(float p_value) { - if (snap->is_pressed()) { + if (is_snap_enabled()) { double snap_increment; if (timeline->is_using_fps() && step->get_value() > 0) @@ -5857,7 +5862,7 @@ AnimationTrackEditor::AnimationTrackEditor() { step = memnew(EditorSpinSlider); step->set_min(0); step->set_max(1000000); - step->set_step(0.01); + step->set_step(0.001); step->set_hide_slider(true); step->set_custom_minimum_size(Size2(100, 0) * EDSCALE); step->set_tooltip(TTR("Animation step value.")); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 9e16f2faf7..96fd10effd 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -520,8 +520,8 @@ public: bool is_key_selected(int p_track, int p_key) const; bool is_selection_active() const; bool is_moving_selection() const; + bool is_snap_enabled() const; float get_moving_selection_offset() const; - bool is_snap_enabled(); float snap_time(float p_value); bool is_grouping_tracks(); diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp index 57c00e1bef..edd59f3057 100644 --- a/editor/collada/collada.cpp +++ b/editor/collada/collada.cpp @@ -1696,7 +1696,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { } } - } else if (section == "node") { + } else { /* Found a child node!! what to do..*/ diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 70bbd0fd6c..8b3e108690 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -378,7 +378,7 @@ bool EditorPropertyRevert::get_instanced_node_original_property(Node *p_node, co node = node->get_owner(); } - if (!found) { + if (!found && node) { //if not found, try default class value Variant attempt = ClassDB::class_get_default_property_value(node->get_class_name(), p_prop); if (attempt.get_type() != Variant::NIL) { @@ -1302,6 +1302,7 @@ void EditorInspector::remove_inspector_plugin(const Ref<EditorInspectorPlugin> & } } + ERR_FAIL_COND(idx == -1); for (int i = idx; i < inspector_plugin_count - 1; i++) { inspector_plugins[i] = inspector_plugins[i + 1]; } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index faa936bd64..ae2a6d2802 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -334,6 +334,11 @@ void EditorNode::_notification(int p_what) { OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/unfocused_low_processor_mode_sleep_usec"))); } break; + case MainLoop::NOTIFICATION_WM_ABOUT: { + + show_about(); + } break; + case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { _menu_option_confirm(FILE_QUIT, false); @@ -1576,6 +1581,7 @@ void EditorNode::push_item(Object *p_object, const String &p_property, bool p_in get_inspector()->edit(NULL); node_dock->set_node(NULL); scene_tree_dock->set_selected(NULL); + inspector_dock->update(NULL); return; } @@ -1664,9 +1670,10 @@ void EditorNode::_edit_current() { Resource *current_res = Object::cast_to<Resource>(current_obj); ERR_FAIL_COND(!current_res); - scene_tree_dock->set_selected(NULL); get_inspector()->edit(current_res); + scene_tree_dock->set_selected(NULL); node_dock->set_node(NULL); + inspector_dock->update(NULL); EditorNode::get_singleton()->get_import_dock()->set_edit_path(current_res->get_path()); int subr_idx = current_res->get_path().find("::"); @@ -1693,9 +1700,11 @@ void EditorNode::_edit_current() { if (current_node->is_inside_tree()) { node_dock->set_node(current_node); scene_tree_dock->set_selected(current_node); + inspector_dock->update(current_node); } else { node_dock->set_node(NULL); scene_tree_dock->set_selected(NULL); + inspector_dock->update(NULL); } if (get_edited_scene() && get_edited_scene()->get_filename() != String()) { @@ -1715,6 +1724,8 @@ void EditorNode::_edit_current() { get_inspector()->edit(current_obj); node_dock->set_node(NULL); + scene_tree_dock->set_selected(NULL); + inspector_dock->update(NULL); } inspector_dock->set_warning(editable_warning); @@ -2777,6 +2788,20 @@ void EditorNode::_editor_select(int p_which) { } } +void EditorNode::select_editor_by_name(const String &p_name) { + ERR_FAIL_COND(p_name == ""); + + for (int i = 0; i < main_editor_buttons.size(); i++) { + if (main_editor_buttons[i]->get_text() == p_name) { + _editor_select(i); + return; + } + } + + ERR_EXPLAIN("The editor name '" + p_name + "' was not found."); + ERR_FAIL(); +} + void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) { if (p_editor->has_main_screen()) { @@ -5943,7 +5968,7 @@ EditorNode::EditorNode() { recent_scenes->connect("id_pressed", this, "_open_recent_scene"); p->add_separator(); - p->add_item(TTR("Quit"), FILE_QUIT, KEY_MASK_CMD + KEY_Q); + p->add_shortcut(ED_SHORTCUT("editor/file_quit", TTR("Quit"), KEY_MASK_CMD + KEY_Q), FILE_QUIT, true); project_menu = memnew(MenuButton); project_menu->set_flat(false); @@ -5977,9 +6002,9 @@ EditorNode::EditorNode() { p->add_separator(); #ifdef OSX_ENABLED - p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q); + p->add_shortcut(ED_SHORTCUT("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q), RUN_PROJECT_MANAGER, true); #else - p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_Q); + p->add_shortcut(ED_SHORTCUT("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_Q), RUN_PROJECT_MANAGER, true); #endif menu_hb->add_spacer(); diff --git a/editor/editor_node.h b/editor/editor_node.h index 75827cc65f..8d536a1b86 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -732,6 +732,8 @@ public: bool item_has_editor(Object *p_object); void hide_top_editors(); + void select_editor_by_name(const String &p_name); + void open_request(const String &p_path); bool is_changing_scene() const; diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index c2a845653e..4b6afcbb86 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -149,6 +149,10 @@ Vector<Ref<Texture> > EditorInterface::make_mesh_previews(const Vector<Ref<Mesh> return textures; } +void EditorInterface::set_main_screen_editor(const String &p_name) { + EditorNode::get_singleton()->select_editor_by_name(p_name); +} + Control *EditorInterface::get_editor_viewport() { return EditorNode::get_singleton()->get_viewport(); @@ -260,6 +264,10 @@ void EditorInterface::save_scene_as(const String &p_scene, bool p_with_preview) EditorNode::get_singleton()->save_scene_to_path(p_scene, p_with_preview); } +void EditorInterface::set_distraction_free_mode(bool p_enter) { + EditorNode::get_singleton()->set_distraction_free_mode(p_enter); +} + EditorInterface *EditorInterface::singleton = NULL; void EditorInterface::_bind_methods() { @@ -288,6 +296,9 @@ void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene); ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true)); + + ClassDB::bind_method(D_METHOD("set_main_screen_editor", "name"), &EditorInterface::set_main_screen_editor); + ClassDB::bind_method(D_METHOD("set_distraction_free_mode", "enter"), &EditorInterface::set_distraction_free_mode); } EditorInterface::EditorInterface() { @@ -315,7 +326,8 @@ void EditorPlugin::remove_autoload_singleton(const String &p_name) { Ref<ConfigFile> EditorPlugin::get_config() { Ref<ConfigFile> cf = memnew(ConfigFile); - cf->load(_dir_cache.plus_file("plugin.cfg")); + Error err = cf->load(_dir_cache.plus_file("plugin.cfg")); + ERR_FAIL_COND_V(err != OK, cf); return cf; } diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 75c230adb7..52ab444522 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -103,6 +103,9 @@ public: Vector<Ref<Texture> > make_mesh_previews(const Vector<Ref<Mesh> > &p_meshes, Vector<Transform> *p_transforms, int p_preview_size); + void set_main_screen_editor(const String &p_name); + void set_distraction_free_mode(bool p_enter); + EditorInterface(); }; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 45000517cb..e3f2a888d6 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -773,10 +773,16 @@ void EditorSettings::create() { if (d->file_exists(exe_path + "/._sc_")) { self_contained = true; - extra_config->load(exe_path + "/._sc_"); + Error err = extra_config->load(exe_path + "/._sc_"); + if (err != OK) { + ERR_PRINTS("Can't load config from path: " + exe_path + "/._sc_"); + } } else if (d->file_exists(exe_path + "/_sc_")) { self_contained = true; - extra_config->load(exe_path + "/_sc_"); + Error err = extra_config->load(exe_path + "/_sc_"); + if (err != OK) { + ERR_PRINTS("Can't load config from path: " + exe_path + "/_sc_"); + } } memdelete(d); @@ -1208,9 +1214,12 @@ String EditorSettings::get_feature_profiles_dir() const { void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) { Ref<ConfigFile> cf = memnew(ConfigFile); String path = get_project_settings_dir().plus_file("project_metadata.cfg"); - cf->load(path); + Error err; + err = cf->load(path); + ERR_FAIL_COND(err != OK); cf->set_value(p_section, p_key, p_data); - cf->save(path); + err = cf->save(path); + ERR_FAIL_COND(err != OK); } Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const { diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index e1ab5c62a7..8665467f2d 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -524,6 +524,7 @@ FindInFilesPanel::FindInFilesPanel() { _progress_bar = memnew(ProgressBar); _progress_bar->set_h_size_flags(SIZE_EXPAND_FILL); + _progress_bar->set_v_size_flags(SIZE_SHRINK_CENTER); hbc->add_child(_progress_bar); set_progress_visible(false); diff --git a/editor/icons/icon_key_animation.svg b/editor/icons/icon_key_animation.svg index a09567498f..6db513ca26 100644 --- a/editor/icons/icon_key_animation.svg +++ b/editor/icons/icon_key_animation.svg @@ -1,65 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="8" - height="8" - version="1.1" - viewBox="0 0 8 8" - id="svg6" - sodipodi:docname="icon_key_animation.svg" - inkscape:version="0.92.3 (2405546, 2018-03-11)"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1852" - inkscape:window-height="781" - id="namedview8" - showgrid="false" - inkscape:zoom="29.5" - inkscape:cx="-10.271186" - inkscape:cy="3.4149032" - inkscape:window-x="68" - inkscape:window-y="117" - inkscape:window-maximized="0" - inkscape:current-layer="g4" /> - <g - transform="translate(0 -1044.4)" - id="g4"> - <rect - transform="rotate(-45)" - x="-741.53" - y="741.08" - width="6.1027" - height="6.1027" - ry=".76286" - fill="#ea686c" - id="rect2" - style="fill:#b76ef0;fill-opacity:1" /> - </g> -</svg> +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#b76ef0" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_key_audio.svg b/editor/icons/icon_key_audio.svg index 7c728bfd01..75576885ec 100644 --- a/editor/icons/icon_key_audio.svg +++ b/editor/icons/icon_key_audio.svg @@ -1,65 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="8" - height="8" - version="1.1" - viewBox="0 0 8 8" - id="svg6" - sodipodi:docname="icon_key_audio.svg" - inkscape:version="0.92.3 (2405546, 2018-03-11)"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1053" - inkscape:window-height="591" - id="namedview8" - showgrid="false" - inkscape:zoom="29.5" - inkscape:cx="4" - inkscape:cy="4" - inkscape:window-x="67" - inkscape:window-y="27" - inkscape:window-maximized="0" - inkscape:current-layer="g4" /> - <g - transform="translate(0 -1044.4)" - id="g4"> - <rect - transform="rotate(-45)" - x="-741.53" - y="741.08" - width="6.1027" - height="6.1027" - ry=".76286" - fill="#ea686c" - id="rect2" - style="fill:#eae668;fill-opacity:1" /> - </g> -</svg> +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#eae668" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_key_bezier.svg b/editor/icons/icon_key_bezier.svg index 62af6fdb34..dc5800fd5a 100644 --- a/editor/icons/icon_key_bezier.svg +++ b/editor/icons/icon_key_bezier.svg @@ -1,65 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="8" - height="8" - version="1.1" - viewBox="0 0 8 8" - id="svg6" - sodipodi:docname="icon_key_bezier.svg" - inkscape:version="0.92.3 (2405546, 2018-03-11)"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1852" - inkscape:window-height="781" - id="namedview8" - showgrid="false" - inkscape:zoom="29.5" - inkscape:cx="-17.152542" - inkscape:cy="3.4149032" - inkscape:window-x="67" - inkscape:window-y="27" - inkscape:window-maximized="0" - inkscape:current-layer="g4" /> - <g - transform="translate(0 -1044.4)" - id="g4"> - <rect - transform="rotate(-45)" - x="-741.53" - y="741.08" - width="6.1027" - height="6.1027" - ry=".76286" - fill="#ea686c" - id="rect2" - style="fill:#5792f6;fill-opacity:1" /> - </g> -</svg> +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#5792f6" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_key_call.svg b/editor/icons/icon_key_call.svg index e702898288..6cc442c391 100644 --- a/editor/icons/icon_key_call.svg +++ b/editor/icons/icon_key_call.svg @@ -1,64 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="8" - height="8" - version="1.1" - viewBox="0 0 8 8" - id="svg6" - sodipodi:docname="icon_key_call.svg" - inkscape:version="0.92.3 (2405546, 2018-03-11)"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="836" - inkscape:window-height="480" - id="namedview8" - showgrid="false" - inkscape:zoom="29.5" - inkscape:cx="4" - inkscape:cy="4" - inkscape:window-x="67" - inkscape:window-y="27" - inkscape:window-maximized="0" - inkscape:current-layer="g4" /> - <g - transform="translate(0 -1044.4)" - id="g4"> - <rect - transform="rotate(-45)" - x="-741.53" - y="741.08" - width="6.1027" - height="6.1027" - ry=".76286" - fill="#adf18f" - id="rect2" - style="fill:#66f376;fill-opacity:1" /> - </g> -</svg> +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#66f376" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_key_selected.svg b/editor/icons/icon_key_selected.svg index 2842fd93eb..6594aec6ee 100644 --- a/editor/icons/icon_key_selected.svg +++ b/editor/icons/icon_key_selected.svg @@ -1,76 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="8" - height="8" - version="1.1" - viewBox="0 0 8 8" - id="svg6" - sodipodi:docname="icon_key_selected.svg" - inkscape:version="0.92.3 (2405546, 2018-03-11)"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1568" - inkscape:window-height="767" - id="namedview8" - showgrid="false" - inkscape:zoom="41.7193" - inkscape:cx="-0.48848775" - inkscape:cy="3.5639274" - inkscape:window-x="67" - inkscape:window-y="27" - inkscape:window-maximized="0" - inkscape:current-layer="g4-3" /> - <g - transform="translate(0 -1044.4)" - id="g4"> - <rect - transform="rotate(-45)" - x="-741.53" - y="741.08" - width="6.1027" - height="6.1027" - ry=".76286" - fill="#84c2ff" - id="rect2" /> - </g> - <g - transform="translate(0,-1044.4)" - id="g4-3"> - <rect - style="fill:#003e7a;fill-opacity:1;stroke-width:0.56281364" - transform="matrix(0.71728847,-0.69677633,0.71728847,0.69677633,0,0)" - x="-751.20953" - y="753.42743" - width="3.4346831" - height="3.4346831" - ry="0.42934799" - id="rect2-6" /> - </g> -</svg> +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#84c2ff" height="6.1027" ry=".76286" transform="matrix(.87871827 -.87871827 .87871827 .87871827 .03288 -1297.7965)" width="6.1027" x="-741.53003" y="741.08002"/><rect fill="#003e7a" height="3.434683" ry=".429348" stroke-width=".562814" transform="matrix(.89137101 -.86588067 .89137101 .86588067 -.038545 -1297.8361)" width="3.434683" x="-751.20953" y="753.42743"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_key_value.svg b/editor/icons/icon_key_value.svg index 61032a1e16..8a4787d6ed 100644 --- a/editor/icons/icon_key_value.svg +++ b/editor/icons/icon_key_value.svg @@ -1,5 +1 @@ -<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1044.4)"> -<rect transform="rotate(-45)" x="-741.53" y="741.08" width="6.1027" height="6.1027" ry=".76286" fill="#e0e0e0"/> -</g> -</svg> +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#e0e0e0" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 1.002946 -1043.3636)" width="6.1027" x="-741.53003" y="741.08002"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_key_xform.svg b/editor/icons/icon_key_xform.svg index fd22b67f52..4a567075a7 100644 --- a/editor/icons/icon_key_xform.svg +++ b/editor/icons/icon_key_xform.svg @@ -1,64 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="8" - height="8" - version="1.1" - viewBox="0 0 8 8" - id="svg6" - sodipodi:docname="icon_key_xform.svg" - inkscape:version="0.92.3 (2405546, 2018-03-11)"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="836" - inkscape:window-height="480" - id="namedview8" - showgrid="false" - inkscape:zoom="29.5" - inkscape:cx="4" - inkscape:cy="4" - inkscape:window-x="67" - inkscape:window-y="27" - inkscape:window-maximized="0" - inkscape:current-layer="g4" /> - <g - transform="translate(0 -1044.4)" - id="g4"> - <rect - transform="rotate(-45)" - x="-741.53" - y="741.08" - width="6.1027" - height="6.1027" - ry=".76286" - fill="#ea686c" - id="rect2" - style="fill:#ea9568;fill-opacity:1" /> - </g> -</svg> +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#ea9568" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
\ No newline at end of file diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index 12bf544357..23056d25c0 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -130,7 +130,8 @@ void PluginConfigDialog::_notification(int p_what) { void PluginConfigDialog::config(const String &p_config_path) { if (p_config_path.length()) { Ref<ConfigFile> cf = memnew(ConfigFile); - cf->load(p_config_path); + Error err = cf->load(p_config_path); + ERR_FAIL_COND(err != OK); name_edit->set_text(cf->get_value("plugin", "name", "")); subfolder_edit->set_text(p_config_path.get_base_dir().get_basename().get_file()); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 5163b372b2..f42716c827 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" +#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/project_settings.h" #include "editor/animation_track_editor.h" @@ -293,10 +294,6 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { } } frame->set_max(anim->get_length()); - if (anim->get_step()) - frame->set_step(anim->get_step()); - else - frame->set_step(0.00001); } else { track_editor->set_animation(Ref<Animation>()); @@ -1008,7 +1005,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set) { }; updating = true; - String current = player->get_assigned_animation(); //animation->get_item_text( animation->get_selected() ); + String current = player->get_assigned_animation(); if (current == "" || !player->has_animation(current)) { updating = false; current = ""; @@ -1018,14 +1015,9 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set) { Ref<Animation> anim; anim = player->get_animation(current); - float pos = anim->get_length() * (p_value / frame->get_max()); - float step = anim->get_step(); - if (step) { - pos = Math::stepify(pos, step); - if (pos < 0) - pos = 0; - if (pos >= anim->get_length()) - pos = anim->get_length(); + float pos = CLAMP(anim->get_length() * (p_value / frame->get_max()), 0, anim->get_length()); + if (track_editor->is_snap_enabled()) { + pos = Math::stepify(pos, anim->get_step()); } if (player->is_valid() && !p_set) { @@ -1063,14 +1055,6 @@ void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len) frame->set_max(p_len); } -void AnimationPlayerEditor::_animation_key_editor_anim_step_changed(float p_len) { - - if (p_len) - frame->set_step(p_len); - else - frame->set_step(0.00001); -} - void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) { if (!is_visible_in_tree()) @@ -1081,8 +1065,10 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) if (player->is_playing()) return; + Ref<Animation> anim = player->get_animation(player->get_assigned_animation()); + updating = true; - frame->set_value(p_pos); + frame->set_value(Math::stepify(p_pos, track_editor->is_snap_enabled() ? anim->get_step() : 0)); updating = false; _seek_value_changed(p_pos, !p_drag); @@ -1558,7 +1544,6 @@ void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_list_changed"), &AnimationPlayerEditor::_list_changed); ClassDB::bind_method(D_METHOD("_animation_key_editor_seek"), &AnimationPlayerEditor::_animation_key_editor_seek); ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_len_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_len_changed); - ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_step_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_step_changed); ClassDB::bind_method(D_METHOD("_hide_anim_editors"), &AnimationPlayerEditor::_hide_anim_editors); ClassDB::bind_method(D_METHOD("_animation_duplicate"), &AnimationPlayerEditor::_animation_duplicate); ClassDB::bind_method(D_METHOD("_blend_editor_next_changed"), &AnimationPlayerEditor::_blend_editor_next_changed); @@ -1621,6 +1606,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay hb->add_child(frame); frame->set_custom_minimum_size(Size2(60, 0)); frame->set_stretch_ratio(2); + frame->set_step(0.0001); frame->set_tooltip(TTR("Animation position (in seconds).")); hb->add_child(memnew(VSeparator)); @@ -1774,7 +1760,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay track_editor->set_v_size_flags(SIZE_EXPAND_FILL); track_editor->connect("timeline_changed", this, "_animation_key_editor_seek"); track_editor->connect("animation_len_changed", this, "_animation_key_editor_anim_len_changed"); - track_editor->connect("animation_step_changed", this, "_animation_key_editor_anim_step_changed"); _update_player(); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 398ef6ff14..22152fa8f4 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -203,7 +203,6 @@ class AnimationPlayerEditor : public VBoxContainer { void _animation_key_editor_seek(float p_pos, bool p_drag); void _animation_key_editor_anim_len_changed(float p_len); - void _animation_key_editor_anim_step_changed(float p_len); void _unhandled_key_input(const Ref<InputEvent> &p_ev); void _animation_tool_menu(int p_option); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 31b11d8bea..b5231ce468 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -333,18 +333,14 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int switch (p_status) { - case HTTPRequest::RESULT_CANT_RESOLVE: { - error_text = TTR("Can't resolve hostname:") + " " + host; - status->set_text(TTR("Can't resolve.")); - } break; - case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED: + case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH: case HTTPRequest::RESULT_CONNECTION_ERROR: - case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH: { + case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED: { error_text = TTR("Connection error, please try again."); status->set_text(TTR("Can't connect.")); } break; - case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR: - case HTTPRequest::RESULT_CANT_CONNECT: { + case HTTPRequest::RESULT_CANT_CONNECT: + case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR: { error_text = TTR("Can't connect to host:") + " " + host; status->set_text(TTR("Can't connect.")); } break; @@ -352,14 +348,27 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int error_text = TTR("No response from host:") + " " + host; status->set_text(TTR("No response.")); } break; + case HTTPRequest::RESULT_CANT_RESOLVE: { + error_text = TTR("Can't resolve hostname:") + " " + host; + status->set_text(TTR("Can't resolve.")); + } break; case HTTPRequest::RESULT_REQUEST_FAILED: { error_text = TTR("Request failed, return code:") + " " + itos(p_code); status->set_text(TTR("Request Failed.")); } break; + case HTTPRequest::RESULT_DOWNLOAD_FILE_CANT_OPEN: + case HTTPRequest::RESULT_DOWNLOAD_FILE_WRITE_ERROR: { + error_text = TTR("Cannot save response to") + " " + download->get_download_file(); + status->set_text(TTR("Write error.")); + } break; case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: { error_text = TTR("Request failed, too many redirects"); status->set_text(TTR("Redirect Loop.")); } break; + case HTTPRequest::RESULT_TIMEOUT: { + error_text = TTR("Request failed, timeout"); + status->set_text(TTR("Timeout.")); + } break; default: { if (p_code != 200) { error_text = TTR("Request failed, return code:") + " " + itos(p_code); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 9418349d71..16cc9978ee 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -44,6 +44,7 @@ #include "editor/script_editor_debugger.h" #include "scene/main/viewport.h" #include "script_text_editor.h" +#include "text_editor.h" /*** SCRIPT EDITOR ****/ @@ -2988,18 +2989,38 @@ void ScriptEditor::_on_find_in_files_requested(String text) { void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_number, int begin, int end) { - RES res = ResourceLoader::load(fpath); - if (fpath.get_extension() == "shader") { - ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_singleton()->get_editor_data().get_editor("Shader")); - shader_editor->edit(res.ptr()); - shader_editor->make_visible(true); - shader_editor->get_shader_editor()->goto_line_selection(line_number - 1, begin, end); - } else { - edit(res); + if (ResourceLoader::exists(fpath)) { + RES res = ResourceLoader::load(fpath); + + if (fpath.get_extension() == "shader") { + ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_singleton()->get_editor_data().get_editor("Shader")); + shader_editor->edit(res.ptr()); + shader_editor->make_visible(true); + shader_editor->get_shader_editor()->goto_line_selection(line_number - 1, begin, end); + return; + } else { + Ref<Script> script = res; + if (script.is_valid()) { + edit(script); + + ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor()); + if (ste) { + ste->goto_line_selection(line_number - 1, begin, end); + } + return; + } + } + } + + // If the file is not a valid resource/script, load it as a text file. + Error err; + Ref<TextFile> text_file = _load_text_file(fpath, &err); + if (text_file.is_valid()) { + edit(text_file); - ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor()); - if (ste) { - ste->goto_line_selection(line_number - 1, begin, end); + TextEditor *te = Object::cast_to<TextEditor>(_get_current_editor()); + if (te) { + te->goto_line_selection(line_number - 1, begin, end); } } } diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 34d8e6aff5..a8fbadb773 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -313,6 +313,11 @@ void TextEditor::goto_line(int p_line, bool p_with_error) { code_editor->goto_line(p_line); } +void TextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { + + code_editor->goto_line_selection(p_line, p_begin, p_end); +} + void TextEditor::set_executing_line(int p_line) { code_editor->set_executing_line(p_line); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 3a330576ae..c0d4052646 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -131,6 +131,7 @@ public: virtual Vector<String> get_functions(); virtual void get_breakpoints(List<int> *p_breakpoints); virtual void goto_line(int p_line, bool p_with_error = false); + void goto_line_selection(int p_line, int p_begin, int p_end); virtual void set_executing_line(int p_line); virtual void clear_executing_line(); virtual void trim_trailing_whitespace(); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index c956409966..88c5204074 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -2429,6 +2429,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Max", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), VisualShaderNodeVectorOp::OP_MAX, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), VisualShaderNodeVectorOp::OP_MIN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeVectorInterp", TTR("Linear interpolation between two vectors."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeVectorScalarMix", TTR("Linear interpolation between two vectors using scalar."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_VECTOR)); diff --git a/main/main.cpp b/main/main.cpp index 7e69864e1e..39cd2548fb 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -783,8 +783,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_chars_per_second", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_chars_per_second", PROPERTY_HINT_RANGE, "0, 4096, 1, or_greater")); GLOBAL_DEF("network/limits/debugger_stdout/max_messages_per_frame", 10); ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_messages_per_frame", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_messages_per_frame", PROPERTY_HINT_RANGE, "0, 20, 1, or_greater")); - GLOBAL_DEF("network/limits/debugger_stdout/max_errors_per_frame", 10); - ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_errors_per_frame", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_errors_per_frame", PROPERTY_HINT_RANGE, "0, 20, 1, or_greater")); + GLOBAL_DEF("network/limits/debugger_stdout/max_errors_per_second", 100); + ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_errors_per_second", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_errors_per_second", PROPERTY_HINT_RANGE, "0, 200, 1, or_greater")); + GLOBAL_DEF("network/limits/debugger_stdout/max_warnings_per_second", 100); + ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_warnings_per_second", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_warnings_per_second", PROPERTY_HINT_RANGE, "0, 200, 1, or_greater")); if (debug_mode == "remote") { diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 9d632aaf83..f475ba23f6 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -1234,7 +1234,7 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran ERR_FAIL_COND_V(shape_idx < 0 || shape_idx >= cs->getNumChildShapes(), false); if (cs->getChildShape(shape_idx)->isConvex()) { - if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(cs->getChildShape(shape_idx)), otherObject, shape_idx, shape_transform, otherObject->getWorldTransform() * cs->getChildTransform(shape_idx), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { + if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(cs->getChildShape(shape_idx)), otherObject, kinIndex, shape_idx, shape_transform, otherObject->getWorldTransform() * cs->getChildTransform(shape_idx), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { penetration = true; } @@ -1245,7 +1245,7 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran } } } else if (otherObject->getCollisionShape()->isConvex()) { /// Execute GJK test against object shape - if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(otherObject->getCollisionShape()), otherObject, 0, shape_transform, otherObject->getWorldTransform(), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { + if (RFP_convex_convex_test(kin_shape.shape, static_cast<const btConvexShape *>(otherObject->getCollisionShape()), otherObject, kinIndex, 0, shape_transform, otherObject->getWorldTransform(), p_recover_movement_scale, r_delta_recover_movement, r_recover_result)) { penetration = true; } @@ -1261,7 +1261,7 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran return penetration; } -bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { +bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { // Initialize GJK input btGjkPairDetector::ClosestPointInput gjk_input; @@ -1279,6 +1279,7 @@ bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const bt if (r_recover_result) { if (result.m_distance < r_recover_result->penetration_distance) { r_recover_result->hasPenetration = true; + r_recover_result->local_shape_most_recovered = p_shapeId_A; r_recover_result->other_collision_object = p_objectB; r_recover_result->other_compound_shape_index = p_shapeId_B; r_recover_result->penetration_distance = result.m_distance; @@ -1314,6 +1315,7 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC if (r_recover_result) { if (contactPointResult.m_penetration_distance < r_recover_result->penetration_distance) { r_recover_result->hasPenetration = true; + r_recover_result->local_shape_most_recovered = p_shapeId_A; r_recover_result->other_collision_object = p_objectB; r_recover_result->other_compound_shape_index = p_shapeId_B; r_recover_result->penetration_distance = contactPointResult.m_penetration_distance; diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index eb4a065e54..ecf8a2db9d 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -208,7 +208,7 @@ private: bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); /// This is an API that recover a kinematic object from penetration /// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions - bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); + bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); /// This is an API that recover a kinematic object from penetration /// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 846c84d222..f8d201b4ca 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -2913,11 +2913,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call r_error.error = Variant::CallError::CALL_OK; REF ref; - Object *owner = NULL; ERR_FAIL_NULL_V(native, Variant()); - owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native)); + Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native)); Reference *r = Object::cast_to<Reference>(owner); if (r) { diff --git a/modules/mono/glue/Managed/Files/AABB.cs b/modules/mono/glue/Managed/Files/AABB.cs index a2ebbc0736..98a73382f4 100644 --- a/modules/mono/glue/Managed/Files/AABB.cs +++ b/modules/mono/glue/Managed/Files/AABB.cs @@ -5,6 +5,7 @@ // file: core/variant_call.cpp // commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685 using System; +using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else @@ -13,6 +14,8 @@ using real_t = System.Single; namespace Godot { + [Serializable] + [StructLayout(LayoutKind.Sequential)] public struct AABB : IEquatable<AABB> { private Vector3 _position; diff --git a/modules/mono/glue/Managed/Files/Basis.cs b/modules/mono/glue/Managed/Files/Basis.cs index 5a6a5ff658..421532b68f 100644 --- a/modules/mono/glue/Managed/Files/Basis.cs +++ b/modules/mono/glue/Managed/Files/Basis.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Basis : IEquatable<Basis> { diff --git a/modules/mono/glue/Managed/Files/Color.cs b/modules/mono/glue/Managed/Files/Color.cs index da57a7f9ae..447697c671 100644 --- a/modules/mono/glue/Managed/Files/Color.cs +++ b/modules/mono/glue/Managed/Files/Color.cs @@ -1,7 +1,10 @@ using System; +using System.Runtime.InteropServices; namespace Godot { + [Serializable] + [StructLayout(LayoutKind.Sequential)] public struct Color : IEquatable<Color> { public float r; diff --git a/modules/mono/glue/Managed/Files/Plane.cs b/modules/mono/glue/Managed/Files/Plane.cs index e16d4315be..a13161d2e6 100644 --- a/modules/mono/glue/Managed/Files/Plane.cs +++ b/modules/mono/glue/Managed/Files/Plane.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else @@ -7,6 +8,8 @@ using real_t = System.Single; namespace Godot { + [Serializable] + [StructLayout(LayoutKind.Sequential)] public struct Plane : IEquatable<Plane> { private Vector3 _normal; diff --git a/modules/mono/glue/Managed/Files/Quat.cs b/modules/mono/glue/Managed/Files/Quat.cs index f1d97b9b5c..845c7c730e 100644 --- a/modules/mono/glue/Managed/Files/Quat.cs +++ b/modules/mono/glue/Managed/Files/Quat.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Quat : IEquatable<Quat> { diff --git a/modules/mono/glue/Managed/Files/Rect2.cs b/modules/mono/glue/Managed/Files/Rect2.cs index 888f300347..f3dc9d8490 100644 --- a/modules/mono/glue/Managed/Files/Rect2.cs +++ b/modules/mono/glue/Managed/Files/Rect2.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Rect2 : IEquatable<Rect2> { diff --git a/modules/mono/glue/Managed/Files/Transform.cs b/modules/mono/glue/Managed/Files/Transform.cs index de70ccbe98..cc4d26158d 100644 --- a/modules/mono/glue/Managed/Files/Transform.cs +++ b/modules/mono/glue/Managed/Files/Transform.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Transform : IEquatable<Transform> { diff --git a/modules/mono/glue/Managed/Files/Transform2D.cs b/modules/mono/glue/Managed/Files/Transform2D.cs index 12a3811230..814332dc07 100644 --- a/modules/mono/glue/Managed/Files/Transform2D.cs +++ b/modules/mono/glue/Managed/Files/Transform2D.cs @@ -8,6 +8,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Transform2D : IEquatable<Transform2D> { diff --git a/modules/mono/glue/Managed/Files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs index 3fb40d8a61..b1c1dae3c2 100644 --- a/modules/mono/glue/Managed/Files/Vector2.cs +++ b/modules/mono/glue/Managed/Files/Vector2.cs @@ -14,6 +14,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Vector2 : IEquatable<Vector2> { diff --git a/modules/mono/glue/Managed/Files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs index 68601da1e7..c2da7b8bb1 100644 --- a/modules/mono/glue/Managed/Files/Vector3.cs +++ b/modules/mono/glue/Managed/Files/Vector3.cs @@ -14,6 +14,7 @@ using real_t = System.Single; namespace Godot { + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Vector3 : IEquatable<Vector3> { diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp new file mode 100644 index 0000000000..e1d42d3217 --- /dev/null +++ b/modules/tinyexr/image_saver_tinyexr.cpp @@ -0,0 +1,279 @@ +/*************************************************************************/ +/* image_saver_tinyexr.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "image_saver_tinyexr.h" +#include "core/math/math_funcs.h" + +#include "thirdparty/tinyexr/tinyexr.h" + +static bool is_supported_format(Image::Format p_format) { + // This is checked before anything else. + // Mostly uncompressed formats are considered. + switch (p_format) { + case Image::FORMAT_RF: + case Image::FORMAT_RGF: + case Image::FORMAT_RGBF: + case Image::FORMAT_RGBAF: + case Image::FORMAT_RH: + case Image::FORMAT_RGH: + case Image::FORMAT_RGBH: + case Image::FORMAT_RGBAH: + case Image::FORMAT_R8: + case Image::FORMAT_RG8: + case Image::FORMAT_RGB8: + case Image::FORMAT_RGBA8: + return true; + default: + return false; + } +} + +enum SrcPixelType { + SRC_FLOAT, + SRC_HALF, + SRC_BYTE +}; + +static SrcPixelType get_source_pixel_type(Image::Format p_format) { + switch (p_format) { + case Image::FORMAT_RF: + case Image::FORMAT_RGF: + case Image::FORMAT_RGBF: + case Image::FORMAT_RGBAF: + return SRC_FLOAT; + case Image::FORMAT_RH: + case Image::FORMAT_RGH: + case Image::FORMAT_RGBH: + case Image::FORMAT_RGBAH: + return SRC_HALF; + case Image::FORMAT_R8: + case Image::FORMAT_RG8: + case Image::FORMAT_RGB8: + case Image::FORMAT_RGBA8: + return SRC_BYTE; + default: + CRASH_NOW(); + } +} + +static int get_target_pixel_type(Image::Format p_format) { + switch (p_format) { + case Image::FORMAT_RF: + case Image::FORMAT_RGF: + case Image::FORMAT_RGBF: + case Image::FORMAT_RGBAF: + return TINYEXR_PIXELTYPE_FLOAT; + case Image::FORMAT_RH: + case Image::FORMAT_RGH: + case Image::FORMAT_RGBH: + case Image::FORMAT_RGBAH: + // EXR doesn't support 8-bit channels so in that case we'll convert + case Image::FORMAT_R8: + case Image::FORMAT_RG8: + case Image::FORMAT_RGB8: + case Image::FORMAT_RGBA8: + return TINYEXR_PIXELTYPE_HALF; + default: + CRASH_NOW(); + } +} + +static int get_pixel_type_size(int p_pixel_type) { + switch (p_pixel_type) { + case TINYEXR_PIXELTYPE_HALF: + return 2; + case TINYEXR_PIXELTYPE_FLOAT: + return 4; + } + CRASH_NOW(); +} + +static int get_channel_count(Image::Format p_format) { + switch (p_format) { + case Image::FORMAT_RF: + case Image::FORMAT_RH: + case Image::FORMAT_R8: + return 1; + case Image::FORMAT_RGF: + case Image::FORMAT_RGH: + case Image::FORMAT_RG8: + return 2; + case Image::FORMAT_RGBF: + case Image::FORMAT_RGBH: + case Image::FORMAT_RGB8: + return 3; + case Image::FORMAT_RGBAF: + case Image::FORMAT_RGBAH: + case Image::FORMAT_RGBA8: + return 4; + default: + CRASH_NOW(); + } +} + +Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) { + + Image::Format format = p_img->get_format(); + + if (!is_supported_format(format)) { + // Format not supported + print_error("Image format not supported for saving as EXR. Consider saving as PNG."); + return ERR_UNAVAILABLE; + } + + EXRHeader header; + InitEXRHeader(&header); + + EXRImage image; + InitEXRImage(&image); + + const int max_channels = 4; + + // Godot does not support more than 4 channels, + // so we can preallocate header infos on the stack and use only the subset we need + PoolByteArray channels[max_channels]; + unsigned char *channels_ptrs[max_channels]; + EXRChannelInfo channel_infos[max_channels]; + int pixel_types[max_channels]; + int requested_pixel_types[max_channels] = { -1 }; + + // Gimp and Blender are a bit annoying so order of channels isn't straightforward. + const int channel_mappings[4][4] = { + { 0 }, // R + { 1, 0 }, // GR + { 2, 1, 0 }, // BGR + { 2, 1, 0, 3 } // BGRA + }; + + int channel_count = get_channel_count(format); + ERR_FAIL_COND_V(p_grayscale && channel_count != 1, ERR_INVALID_PARAMETER); + + int target_pixel_type = get_target_pixel_type(format); + int target_pixel_type_size = get_pixel_type_size(target_pixel_type); + SrcPixelType src_pixel_type = get_source_pixel_type(format); + const int pixel_count = p_img->get_width() * p_img->get_height(); + + const int *channel_mapping = channel_mappings[channel_count - 1]; + + { + PoolByteArray src_data = p_img->get_data(); + PoolByteArray::Read src_r = src_data.read(); + + for (int channel_index = 0; channel_index < channel_count; ++channel_index) { + + // De-interleave channels + + PoolByteArray &dst = channels[channel_index]; + dst.resize(pixel_count * target_pixel_type_size); + + PoolByteArray::Write dst_w = dst.write(); + + if (src_pixel_type == SRC_FLOAT && target_pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + + // Note: we don't save mipmaps + CRASH_COND(src_data.size() < pixel_count * channel_count * target_pixel_type_size); + + const float *src_rp = (float *)src_r.ptr(); + float *dst_wp = (float *)dst_w.ptr(); + + for (int i = 0; i < pixel_count; ++i) { + dst_wp[i] = src_rp[channel_index + i * channel_count]; + } + + } else if (src_pixel_type == SRC_HALF && target_pixel_type == TINYEXR_PIXELTYPE_HALF) { + + CRASH_COND(src_data.size() < pixel_count * channel_count * target_pixel_type_size); + + const uint16_t *src_rp = (uint16_t *)src_r.ptr(); + uint16_t *dst_wp = (uint16_t *)dst_w.ptr(); + + for (int i = 0; i < pixel_count; ++i) { + dst_wp[i] = src_rp[channel_index + i * channel_count]; + } + + } else if (src_pixel_type == SRC_BYTE && target_pixel_type == TINYEXR_PIXELTYPE_HALF) { + + CRASH_COND(src_data.size() < pixel_count * channel_count); + + const uint8_t *src_rp = (uint8_t *)src_r.ptr(); + uint16_t *dst_wp = (uint16_t *)dst_w.ptr(); + + for (int i = 0; i < pixel_count; ++i) { + dst_wp[i] = Math::make_half_float(src_rp[channel_index + i * channel_count] / 255.f); + } + + } else { + CRASH_NOW(); + } + + int remapped_index = channel_mapping[channel_index]; + + channels_ptrs[remapped_index] = dst_w.ptr(); + + // No conversion + pixel_types[remapped_index] = target_pixel_type; + requested_pixel_types[remapped_index] = target_pixel_type; + + // Write channel name + if (p_grayscale) { + channel_infos[remapped_index].name[0] = 'Y'; + channel_infos[remapped_index].name[1] = '\0'; + } else { + const char *rgba = "RGBA"; + channel_infos[remapped_index].name[0] = rgba[channel_index]; + channel_infos[remapped_index].name[1] = '\0'; + } + } + } + + image.images = channels_ptrs; + image.num_channels = channel_count; + image.width = p_img->get_width(); + image.height = p_img->get_height(); + + header.num_channels = image.num_channels; + header.channels = channel_infos; + header.pixel_types = pixel_types; + header.requested_pixel_types = requested_pixel_types; + // TODO DEBUG REMOVE + for (int i = 0; i < 4; ++i) { + print_line(String("requested_pixel_types{0}: {1}").format(varray(i, requested_pixel_types[i]))); + } + + CharString utf8_filename = p_path.utf8(); + const char *err; + int ret = SaveEXRImageToFile(&image, &header, utf8_filename.ptr(), &err); + if (ret != TINYEXR_SUCCESS) { + print_error(String("Saving EXR failed. Error: {0}").format(varray(err))); + return ERR_FILE_CANT_WRITE; + } + + return OK; +} diff --git a/modules/tinyexr/image_saver_tinyexr.h b/modules/tinyexr/image_saver_tinyexr.h new file mode 100644 index 0000000000..298bd1d21c --- /dev/null +++ b/modules/tinyexr/image_saver_tinyexr.h @@ -0,0 +1,38 @@ +/*************************************************************************/ +/* image_saver_tinyexr.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef IMAGE_SAVER_TINYEXR_H +#define IMAGE_SAVER_TINYEXR_H + +#include "core/os/os.h" + +Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale); + +#endif // IMAGE_SAVER_TINYEXR_H diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp index 5473a55687..233b3afa08 100644 --- a/modules/tinyexr/register_types.cpp +++ b/modules/tinyexr/register_types.cpp @@ -31,6 +31,7 @@ #include "register_types.h" #include "image_loader_tinyexr.h" +#include "image_saver_tinyexr.h" static ImageLoaderTinyEXR *image_loader_tinyexr = NULL; @@ -38,9 +39,13 @@ void register_tinyexr_types() { image_loader_tinyexr = memnew(ImageLoaderTinyEXR); ImageLoader::add_image_format_loader(image_loader_tinyexr); + + Image::save_exr_func = save_exr; } void unregister_tinyexr_types() { memdelete(image_loader_tinyexr); + + Image::save_exr_func = NULL; } diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp index 41828f040e..764807cffd 100644 --- a/modules/visual_script/visual_script_property_selector.cpp +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -130,12 +130,14 @@ void VisualScriptPropertySelector::_update_search() { { String b = String(E->get()); category = search_options->create_item(root); - category->set_text(0, b.replace_first("*", "")); - category->set_selectable(0, false); - Ref<Texture> icon; - String rep = b.replace("*", ""); - icon = EditorNode::get_singleton()->get_class_icon(rep); - category->set_icon(0, icon); + if (category) { + category->set_text(0, b.replace_first("*", "")); + category->set_selectable(0, false); + Ref<Texture> icon; + String rep = b.replace("*", ""); + icon = EditorNode::get_singleton()->get_class_icon(rep); + category->set_icon(0, icon); + } } if (properties || seq_connect) { if (instance) { diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp index 1232fc7453..3f7fd07997 100644 --- a/platform/android/audio_driver_opensl.cpp +++ b/platform/android/audio_driver_opensl.cpp @@ -215,8 +215,8 @@ void AudioDriverOpenSL::_record_buffer_callback(SLAndroidSimpleBufferQueueItf qu for (int i = 0; i < rec_buffer.size(); i++) { int32_t sample = rec_buffer[i] << 16; - input_buffer_write(sample); - input_buffer_write(sample); // call twice to convert to Stereo + capture_buffer_write(sample); + capture_buffer_write(sample); // call twice to convert to Stereo } SLresult res = (*recordBufferQueueItf)->Enqueue(recordBufferQueueItf, rec_buffer.ptrw(), rec_buffer.size() * sizeof(int16_t)); @@ -287,7 +287,7 @@ Error AudioDriverOpenSL::capture_init_device() { const int rec_buffer_frames = 2048; rec_buffer.resize(rec_buffer_frames); - input_buffer_init(rec_buffer_frames); + capture_buffer_init(rec_buffer_frames); res = (*recordBufferQueueItf)->Enqueue(recordBufferQueueItf, rec_buffer.ptrw(), rec_buffer.size() * sizeof(int16_t)); ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 1b9d31d752..2fba8bbf7f 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -847,6 +847,138 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { uint32_t name = decode_uint32(&p_manifest[iofs + 12]); String tname = string_table[name]; + int dof_index = p_preset->get("graphics/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof + + if (tname == "uses-feature" && dof_index > 0) { + if (xr_mode_index == 0) { + WARN_PRINT("VR DOF feature setting is only valid for oculus HMDs with an XR mode set to VR"); + } + ofs += 24; // skip over end tag + + // save manifest ending so we can restore it + Vector<uint8_t> manifest_end; + uint32_t manifest_cur_size = p_manifest.size(); + + manifest_end.resize(p_manifest.size() - ofs); + memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size()); + + int32_t attr_name_string = string_table.find("name"); + ERR_EXPLAIN("Template does not have 'name' attribute"); + ERR_FAIL_COND(attr_name_string == -1); + + int32_t ns_android_string = string_table.find("http://schemas.android.com/apk/res/android"); + if (ns_android_string == -1) { + string_table.push_back("http://schemas.android.com/apk/res/android"); + ns_android_string = string_table.size() - 1; + } + + int32_t attr_uses_permission_string = string_table.find("uses-feature"); + if (attr_uses_permission_string == -1) { + string_table.push_back("uses-feature"); + attr_uses_permission_string = string_table.size() - 1; + } + + int32_t attr_required_string = string_table.find("required"); + if (attr_required_string == -1) { + string_table.push_back("required"); + attr_required_string = string_table.size() - 1; + } + + int32_t attr_version_string = string_table.find("version"); + if (attr_version_string == -1) { + string_table.push_back("version"); + attr_version_string = string_table.size() - 1; + } + + String required_value_string; + if (dof_index == 1) { + required_value_string = "false"; + } else if (dof_index == 2) { + required_value_string = "true"; + } else { + ERR_EXPLAIN("Unknown dof index " + itos(dof_index)); + ERR_FAIL(); + } + int32_t required_value = string_table.find(required_value_string); + if (required_value == -1) { + string_table.push_back(required_value_string); + required_value = string_table.size() - 1; + } + + int32_t version_value = string_table.find("1"); + if (version_value == -1) { + string_table.push_back("1"); + version_value = string_table.size() - 1; + } + + int32_t feature_string = string_table.find("android.hardware.vr.headtracking"); + if (feature_string == -1) { + string_table.push_back("android.hardware.vr.headtracking"); + feature_string = string_table.size() - 1; + } + + { + manifest_cur_size += 96 + 20; // node and three attrs + end node + p_manifest.resize(manifest_cur_size); + + // start tag + encode_uint16(0x102, &p_manifest.write[ofs]); // type + encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize + encode_uint32(96, &p_manifest.write[ofs + 4]); // size + encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno + encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment + encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns + encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name + encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start + encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size + encode_uint16(3, &p_manifest.write[ofs + 28]); // num_attrs + encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index + encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index + encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index + + // android:name attribute + encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns + encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name' + encode_uint32(feature_string, &p_manifest.write[ofs + 44]); // raw_value + encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size + p_manifest.write[ofs + 50] = 0; // typedvalue_always0 + p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string) + encode_uint32(feature_string, &p_manifest.write[ofs + 52]); // typedvalue reference + + // android:required attribute + encode_uint32(ns_android_string, &p_manifest.write[ofs + 56]); // ns + encode_uint32(attr_required_string, &p_manifest.write[ofs + 60]); // 'name' + encode_uint32(required_value, &p_manifest.write[ofs + 64]); // raw_value + encode_uint16(8, &p_manifest.write[ofs + 68]); // typedvalue_size + p_manifest.write[ofs + 70] = 0; // typedvalue_always0 + p_manifest.write[ofs + 71] = 0x03; // typedvalue_type (string) + encode_uint32(required_value, &p_manifest.write[ofs + 72]); // typedvalue reference + + // android:version attribute + encode_uint32(ns_android_string, &p_manifest.write[ofs + 76]); // ns + encode_uint32(attr_version_string, &p_manifest.write[ofs + 80]); // 'name' + encode_uint32(version_value, &p_manifest.write[ofs + 84]); // raw_value + encode_uint16(8, &p_manifest.write[ofs + 88]); // typedvalue_size + p_manifest.write[ofs + 90] = 0; // typedvalue_always0 + p_manifest.write[ofs + 91] = 0x03; // typedvalue_type (string) + encode_uint32(version_value, &p_manifest.write[ofs + 92]); // typedvalue reference + + ofs += 96; + + // end tag + encode_uint16(0x103, &p_manifest.write[ofs]); // type + encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize + encode_uint32(24, &p_manifest.write[ofs + 4]); // size + encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno + encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment + encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns + encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name + + ofs += 24; + } + memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size()); + ofs -= 24; // go back over back end + } if (tname == "manifest") { // save manifest ending so we can restore it @@ -1156,6 +1288,7 @@ public: virtual void get_export_options(List<ExportOption> *r_options) { r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); diff --git a/platform/server/detect.py b/platform/server/detect.py index 185dce8128..b6028c20e3 100644 --- a/platform/server/detect.py +++ b/platform/server/detect.py @@ -35,6 +35,7 @@ def get_opts(): BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False), BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False), BoolVariable('use_lsan', 'Use LLVM/GCC compiler leak sanitizer (LSAN))', False), + BoolVariable('use_tsan', 'Use LLVM/GCC compiler thread sanitizer (TSAN))', False), EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')), BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False), BoolVariable('execinfo', 'Use libexecinfo on systems where glibc is not available', False), @@ -99,7 +100,7 @@ def configure(env): env.extra_suffix = ".llvm" + env.extra_suffix - if env['use_ubsan'] or env['use_asan'] or env['use_lsan']: + if env['use_ubsan'] or env['use_asan'] or env['use_lsan'] or env['use_tsan']: env.extra_suffix += "s" if env['use_ubsan']: @@ -114,6 +115,10 @@ def configure(env): env.Append(CCFLAGS=['-fsanitize=leak']) env.Append(LINKFLAGS=['-fsanitize=leak']) + if env['use_tsan']: + env.Append(CCFLAGS=['-fsanitize=thread']) + env.Append(LINKFLAGS=['-fsanitize=thread']) + if env['use_lto']: env.Append(CCFLAGS=['-flto']) if not env['use_llvm'] and env.GetOption("num_jobs") > 1: diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 07470cec92..db4575a0cb 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -719,7 +719,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) pressrc = 0; } } - } else if (mouse_mode != MOUSE_MODE_CAPTURED) { + } else { // for reasons unknown to mankind, wheel comes in screen coordinates POINT coords; coords.x = mb->get_position().x; diff --git a/platform/x11/detect.py b/platform/x11/detect.py index f3a486df02..b8ff97279d 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -64,6 +64,7 @@ def get_opts(): BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False), BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False), BoolVariable('use_lsan', 'Use LLVM/GCC compiler leak sanitizer (LSAN))', False), + BoolVariable('use_tsan', 'Use LLVM/GCC compiler thread sanitizer (TSAN))', False), BoolVariable('pulseaudio', 'Detect and use PulseAudio', True), BoolVariable('udev', 'Use udev for gamepad connection callbacks', False), EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')), @@ -140,7 +141,7 @@ def configure(env): print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.") sys.exit(255) - if env['use_ubsan'] or env['use_asan'] or env['use_lsan']: + if env['use_ubsan'] or env['use_asan'] or env['use_lsan'] or env['use_tsan']: env.extra_suffix += "s" if env['use_ubsan']: @@ -155,6 +156,10 @@ def configure(env): env.Append(CCFLAGS=['-fsanitize=leak']) env.Append(LINKFLAGS=['-fsanitize=leak']) + if env['use_tsan']: + env.Append(CCFLAGS=['-fsanitize=thread']) + env.Append(LINKFLAGS=['-fsanitize=thread']) + if env['use_lto']: if not env['use_llvm'] and env.GetOption("num_jobs") > 1: env.Append(CCFLAGS=['-flto']) diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 6011941142..3e8902314c 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -106,7 +106,7 @@ Transform2D Camera2D::get_camera_transform() { if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) { - if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint()) { + if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint() && !h_offset_changed) { camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_LEFT])); camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_RIGHT])); } else { @@ -116,9 +116,11 @@ Transform2D Camera2D::get_camera_transform() { } else { camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs; } + + h_offset_changed = false; } - if (v_drag_enabled && !Engine::get_singleton()->is_editor_hint()) { + if (v_drag_enabled && !Engine::get_singleton()->is_editor_hint() && !v_offset_changed) { camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_TOP])); camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_BOTTOM])); @@ -130,6 +132,8 @@ Transform2D Camera2D::get_camera_transform() { } else { camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs; } + + v_offset_changed = false; } } else if (anchor_mode == ANCHOR_MODE_FIXED_TOP_LEFT) { @@ -554,6 +558,7 @@ bool Camera2D::is_v_drag_enabled() const { void Camera2D::set_v_offset(float p_offset) { v_ofs = p_offset; + v_offset_changed = true; _update_scroll(); } @@ -565,6 +570,7 @@ float Camera2D::get_v_offset() const { void Camera2D::set_h_offset(float p_offset) { h_ofs = p_offset; + h_offset_changed = true; _update_scroll(); } float Camera2D::get_h_offset() const { @@ -750,8 +756,8 @@ void Camera2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "smoothing_speed"), "set_follow_smoothing", "get_follow_smoothing"); ADD_GROUP("Offset", "offset_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset_v", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset_h", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_h_offset", "get_h_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset_v", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_v_offset", "get_v_offset"); ADD_GROUP("Drag Margin", "drag_margin_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "drag_margin_left", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_LEFT); @@ -799,9 +805,12 @@ Camera2D::Camera2D() { limit_drawing_enabled = false; margin_drawing_enabled = false; - h_drag_enabled = true; - v_drag_enabled = true; + h_drag_enabled = false; + v_drag_enabled = false; h_ofs = 0; v_ofs = 0; + h_offset_changed = false; + v_offset_changed = false; + set_notify_transform(true); } diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 7f16ecff41..bb3c76b30c 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -77,6 +77,9 @@ protected: float h_ofs; float v_ofs; + bool h_offset_changed; + bool v_offset_changed; + Point2 camera_screen_center; void _update_process_mode(); void _update_scroll(); diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h index 490db31cdb..5e6717a3f5 100644 --- a/scene/2d/sprite.h +++ b/scene/2d/sprite.h @@ -110,7 +110,7 @@ public: void set_frame(int p_frame); int get_frame() const; - void set_frame_coords(const Vector2 &p_row); + void set_frame_coords(const Vector2 &p_coord); Vector2 get_frame_coords() const; void set_vframes(int p_amount); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index c79cd80e2e..2cd05b5c50 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1203,6 +1203,8 @@ void TileMap::clear() { void TileMap::_set_tile_data(const PoolVector<int> &p_data) { + ERR_FAIL_COND(format > FORMAT_2); + int c = p_data.size(); PoolVector<int>::Read r = p_data.read(); @@ -1245,8 +1247,6 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) { set_cell(x, y, v, flip_h, flip_v, transpose, Vector2(coord_x, coord_y)); } - - format = FORMAT_2; } PoolVector<int> TileMap::_get_tile_data() const { @@ -1255,7 +1255,7 @@ PoolVector<int> TileMap::_get_tile_data() const { data.resize(tile_map.size() * 3); PoolVector<int>::Write w = data.write(); - format = FORMAT_2; + // Save in highest format int idx = 0; for (const Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) { @@ -1560,7 +1560,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { if (p_name == "format") { if (p_value.get_type() == Variant::INT) { - format = (DataFormat)(p_value.operator int64_t()); + format = (DataFormat)(p_value.operator int64_t()); // Set format used for loading return true; } } else if (p_name == "tile_data") { @@ -1576,7 +1576,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "format") { - r_ret = format; + r_ret = FORMAT_2; // When saving, always save highest format return true; } else if (p_name == "tile_data") { r_ret = _get_tile_data(); @@ -1909,6 +1909,8 @@ void TileMap::_bind_methods() { ADD_GROUP("Occluder", "occluder_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "occluder_light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask"); + ADD_PROPERTY_DEFAULT("format", FORMAT_1); + ADD_SIGNAL(MethodInfo("settings_changed")); BIND_CONSTANT(INVALID_CELL); @@ -1957,7 +1959,7 @@ TileMap::TileMap() { centered_textures = false; occluder_light_mask = 1; clip_uv = false; - format = FORMAT_1; //Always initialize with the lowest format + format = FORMAT_1; // Assume lowest possible format if none is present fp_adjust = 0.00001; tile_origin = TILE_ORIGIN_TOP_LEFT; diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 5ae9b153f9..97a426b5b9 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -173,7 +173,7 @@ public: void set_frame(int p_frame); int get_frame() const; - void set_frame_coords(const Vector2 &p_row); + void set_frame_coords(const Vector2 &p_coord); Vector2 get_frame_coords() const; void set_vframes(int p_amount); diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index dded44b990..416a291da1 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -266,7 +266,7 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) { // fill in weights - if (point_lower == -1) { + if (point_lower == -1 && point_higher != -1) { // we are on the left side, no other point to the left // we just play the next point. diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index 95d4644004..75031f0149 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -527,7 +527,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { } } - if (new_closest != closest) { + if (new_closest != closest && new_closest != -1) { float from = 0; if (blend_mode == BLEND_MODE_DISCRETE_CARRY && closest != -1) { diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index f1ce948c43..6e69ee61e3 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -235,6 +235,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta if (cost < least_cost) { least_cost_transition = E; + least_cost = cost; } } diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index 1d8b74d9db..8744407763 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -79,7 +79,7 @@ void CheckBox::_notification(int p_what) { Vector2 ofs; ofs.x = sb->get_margin(MARGIN_LEFT); - ofs.y = int((get_size().height - get_icon_size().height) / 2); + ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_constant("check_vadjust"); if (is_pressed()) on->draw(ci, ofs); diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index a2d0f388c4..f47547f2cc 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -76,7 +76,7 @@ void CheckButton::_notification(int p_what) { Size2 tex_size = get_icon_size(); ofs.x = get_size().width - (tex_size.width + sb->get_margin(MARGIN_RIGHT)); - ofs.y = (get_size().height - tex_size.height) / 2; + ofs.y = (get_size().height - tex_size.height) / 2 + get_constant("check_vadjust"); if (is_pressed()) on->draw(ci, ofs); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 5ec6c68163..3246b9f3ec 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1772,17 +1772,6 @@ void Control::set_global_position(const Point2 &p_point, bool p_keep_margins) { set_position(inv.xform(p_point), p_keep_margins); } -Rect2 Control::_compute_child_rect(const float p_anchors[4], const float p_margins[4]) const { - - Rect2 anchorable = get_parent_anchorable_rect(); - Rect2 result = anchorable; - for (int i = 0; i < 4; i++) { - result.grow_margin((Margin)i, p_anchors[i] * anchorable.get_size()[i % 2] + p_margins[i]); - } - - return result; -} - void Control::_compute_anchors(Rect2 p_rect, const float p_margins[4], float (&r_anchors)[4]) { Size2 parent_rect_size = get_parent_anchorable_rect().size; diff --git a/scene/gui/control.h b/scene/gui/control.h index 1a59a6d2e4..eae889a667 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -230,7 +230,6 @@ private: void _update_scroll(); void _resize(const Size2 &p_size); - Rect2 _compute_child_rect(const float p_anchors[4], const float p_margins[4]) const; void _compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]); void _compute_anchors(Rect2 p_rect, const float p_margins[4], float (&r_anchors)[4]); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 4da11b671e..59bbdad97a 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -219,6 +219,14 @@ void WindowDialog::_notification(int p_what) { close_button->set_begin(Point2(-get_constant("close_h_ofs", "WindowDialog"), -get_constant("close_v_ofs", "WindowDialog"))); } break; + case NOTIFICATION_TRANSLATION_CHANGED: { + String new_title = tr(title); + if (title != new_title) { + title = new_title; + update(); + } + } break; + case NOTIFICATION_MOUSE_EXIT: { // Reset the mouse cursor when leaving the resizable window border. if (resizable && !drag_type) { @@ -226,11 +234,13 @@ void WindowDialog::_notification(int p_what) { set_default_cursor_shape(CURSOR_ARROW); } } break; + #ifdef TOOLS_ENABLED case NOTIFICATION_POST_POPUP: { if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton()) EditorNode::get_singleton()->dim_editor(true); } break; + case NOTIFICATION_POPUP_HIDE: { if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton()) EditorNode::get_singleton()->dim_editor(false); @@ -272,8 +282,11 @@ int WindowDialog::_drag_hit_test(const Point2 &pos) const { void WindowDialog::set_title(const String &p_title) { - title = tr(p_title); - update(); + String new_title = tr(p_title); + if (title != new_title) { + title = new_title; + update(); + } } String WindowDialog::get_title() const { @@ -296,8 +309,8 @@ Size2 WindowDialog::get_minimum_size() const { const int padding = button_width / 2; const int button_area = button_width + padding; - // as the title gets centered, title_width + close_button_width is not enough. - // we want a width w, such that w / 2 - title_width / 2 >= button_area, i.e. + // As the title gets centered, title_width + close_button_width is not enough. + // We want a width w, such that w / 2 - title_width / 2 >= button_area, i.e. // w >= 2 * button_area + title_width return Size2(2 * button_area + title_width, 1); @@ -324,7 +337,6 @@ void WindowDialog::_bind_methods() { WindowDialog::WindowDialog() { - //title="Hello!"; drag_type = DRAG_NONE; resizable = false; close_button = memnew(TextureButton); @@ -340,7 +352,6 @@ WindowDialog::~WindowDialog() { void PopupDialog::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { - RID ci = get_canvas_item(); get_stylebox("panel", "PopupMenu")->draw(ci, Rect2(Point2(), get_size())); } @@ -362,15 +373,15 @@ void AcceptDialog::_post_popup() { void AcceptDialog::_notification(int p_what) { - if (p_what == NOTIFICATION_MODAL_CLOSE) { - - cancel_pressed(); - } else if (p_what == NOTIFICATION_READY) { - - _update_child_rects(); - } else if (p_what == NOTIFICATION_RESIZED) { + switch (p_what) { + case NOTIFICATION_MODAL_CLOSE: { + cancel_pressed(); + } break; - _update_child_rects(); + case NOTIFICATION_READY: + case NOTIFICATION_RESIZED: { + _update_child_rects(); + } break; } } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index caa0da5d1f..1f0ccffab2 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -408,7 +408,6 @@ void Node::set_physics_process(bool p_process) { else remove_from_group("physics_process"); - data.physics_process = p_process; _change_notify("physics_process"); } @@ -429,7 +428,6 @@ void Node::set_physics_process_internal(bool p_process_internal) { else remove_from_group("physics_process_internal"); - data.physics_process_internal = p_process_internal; _change_notify("physics_process_internal"); } @@ -811,7 +809,6 @@ void Node::set_process(bool p_idle_process) { else remove_from_group("idle_process"); - data.idle_process = p_idle_process; _change_notify("idle_process"); } @@ -832,7 +829,6 @@ void Node::set_process_internal(bool p_idle_process_internal) { else remove_from_group("idle_process_internal"); - data.idle_process_internal = p_idle_process_internal; _change_notify("idle_process_internal"); } @@ -1021,7 +1017,7 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) { if (!unique) { - node_hrcr_count.ref(); + ERR_FAIL_COND(!node_hrcr_count.ref()); String name = "@" + String(p_child->get_name()) + "@" + itos(node_hrcr_count.get()); p_child->data.name = name; } @@ -1269,6 +1265,7 @@ void Node::remove_child(Node *p_child) { } } + ERR_EXPLAIN("Cannot remove child node " + p_child->to_string() + " as it is not in our list of children"); ERR_FAIL_COND(idx == -1); //ERR_FAIL_COND( p_child->data.blocked > 0 ); @@ -2198,8 +2195,11 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p ERR_EXPLAIN("Node: Could not duplicate: " + String(get_class())); ERR_FAIL_COND(!obj); node = Object::cast_to<Node>(obj); - if (!node) + if (!node) { memdelete(obj); + ERR_EXPLAIN("Node: Could not duplicate: " + String(get_class())); + ERR_FAIL(); + } } List<PropertyInfo> plist; @@ -2295,16 +2295,16 @@ Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const { ERR_FAIL_COND_V(get_filename() != "", NULL); - Node *node = NULL; - Object *obj = ClassDB::instance(get_class()); ERR_EXPLAIN("Node: Could not duplicate: " + String(get_class())); ERR_FAIL_COND_V(!obj, NULL); - node = Object::cast_to<Node>(obj); - if (!node) - memdelete(obj); - ERR_FAIL_COND_V(!node, NULL); + Node *node = Object::cast_to<Node>(obj); + if (!node) { + memdelete(obj); + ERR_EXPLAIN("Node: Could not duplicate: " + String(get_class())); + ERR_FAIL_V(NULL); + } node->set_name(get_name()); List<PropertyInfo> plist; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index dbf3150ae0..2668acd3d5 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -37,7 +37,6 @@ #include "core/os/os.h" #include "core/print_string.h" #include "core/project_settings.h" -#include "editor/editor_node.h" #include "main/input_default.h" #include "node.h" #include "scene/resources/dynamic_font.h" @@ -647,7 +646,8 @@ void SceneTree::_notification(int p_notification) { case NOTIFICATION_WM_MOUSE_ENTER: case NOTIFICATION_WM_MOUSE_EXIT: case NOTIFICATION_WM_FOCUS_IN: - case NOTIFICATION_WM_FOCUS_OUT: { + case NOTIFICATION_WM_FOCUS_OUT: + case NOTIFICATION_WM_ABOUT: { if (p_notification == NOTIFICATION_WM_FOCUS_IN) { InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); @@ -671,19 +671,6 @@ void SceneTree::_notification(int p_notification) { } break; - case NOTIFICATION_WM_ABOUT: { - -#ifdef TOOLS_ENABLED - if (EditorNode::get_singleton()) { - EditorNode::get_singleton()->show_about(); - } else { -#endif - get_root()->propagate_notification(p_notification); -#ifdef TOOLS_ENABLED - } -#endif - } break; - case NOTIFICATION_CRASH: { get_root()->propagate_notification(p_notification); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 974c9771e0..fd7cd3c17b 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -509,6 +509,7 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeVectorRefract>(); ClassDB::register_class<VisualShaderNodeScalarInterp>(); ClassDB::register_class<VisualShaderNodeVectorInterp>(); + ClassDB::register_class<VisualShaderNodeVectorScalarMix>(); ClassDB::register_class<VisualShaderNodeVectorCompose>(); ClassDB::register_class<VisualShaderNodeTransformCompose>(); ClassDB::register_class<VisualShaderNodeVectorDecompose>(); diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index cf37c57407..11904b7aff 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -339,7 +339,7 @@ static const unsigned char toggle_off_png[] = { }; static const unsigned char toggle_off_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0x4e, 0xe8, 0x1b, 0x92, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x12, 0x0, 0x0, 0xb, 0x12, 0x1, 0xd2, 0xdd, 0x7e, 0xfc, 0x0, 0x0, 0x6, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x58, 0x47, 0xed, 0x59, 0x4b, 0x6f, 0x1b, 0x55, 0x14, 0x3e, 0xb6, 0xc7, 0x8e, 0xed, 0xf1, 0x2b, 0x7e, 0x84, 0xb8, 0x49, 0x8a, 0x48, 0x36, 0x55, 0x37, 0x48, 0x5d, 0x64, 0xc1, 0x3a, 0x42, 0x82, 0x14, 0x89, 0x56, 0x14, 0x16, 0x48, 0xfc, 0x1, 0xca, 0x1f, 0x40, 0x20, 0x81, 0x90, 0xf8, 0x1, 0xd0, 0x25, 0x8b, 0x8a, 0x25, 0xa0, 0x82, 0x8a, 0x10, 0x12, 0x42, 0x8, 0x29, 0x5d, 0x15, 0xa9, 0x12, 0x8b, 0x4a, 0x20, 0x51, 0x50, 0x1b, 0xcb, 0x79, 0xf8, 0xed, 0x8c, 0xdf, 0xe3, 0x31, 0xe7, 0xbb, 0x99, 0xeb, 0x4c, 0x26, 0x33, 0xb6, 0x13, 0xbb, 0xb4, 0x42, 0xbd, 0xd2, 0xc9, 0x24, 0x77, 0xee, 0x39, 0x73, 0xbf, 0x7b, 0x1e, 0xf7, 0x9c, 0x13, 0xa2, 0x67, 0xe3, 0xd9, 0x9, 0xfc, 0xaf, 0x4e, 0xc0, 0x33, 0x21, 0x1a, 0xac, 0x93, 0x4, 0x96, 0x49, 0xf9, 0x26, 0x14, 0x7f, 0xe6, 0x65, 0x3, 0x93, 0x13, 0x4f, 0x49, 0x23, 0x85, 0x8d, 0xdb, 0xb8, 0x97, 0xb9, 0x41, 0x7e, 0xb, 0xf9, 0xcc, 0xb9, 0x71, 0xbc, 0x67, 0x46, 0x31, 0x21, 0x23, 0x0, 0x1a, 0x4c, 0x7d, 0xa6, 0x9e, 0x85, 0x30, 0x7, 0x72, 0x1c, 0x6e, 0x9b, 0xc6, 0x3c, 0x80, 0x5, 0x98, 0x22, 0x4c, 0x9, 0x93, 0x62, 0xfc, 0xc, 0x99, 0xe0, 0x71, 0x10, 0x4f, 0xa, 0xb4, 0x4, 0xb, 0xa0, 0x2d, 0xa6, 0x3a, 0x53, 0xd5, 0x24, 0x8d, 0x9f, 0x5d, 0xf3, 0x20, 0xa4, 0x5, 0xc, 0xc1, 0x3b, 0x6d, 0x18, 0x40, 0x14, 0x13, 0x68, 0x86, 0x9f, 0xcb, 0xe9, 0xf4, 0x73, 0xd7, 0x22, 0x91, 0xd8, 0x6b, 0x8a, 0xe2, 0xe3, 0xbf, 0x3d, 0x78, 0xe7, 0xe1, 0x31, 0xa1, 0x22, 0x1e, 0xcf, 0xb2, 0xc1, 0x40, 0x60, 0xe1, 0x1f, 0x3, 0x5d, 0xd7, 0xfb, 0x5, 0x4d, 0xab, 0x7f, 0x5f, 0x2c, 0xee, 0x7d, 0xcd, 0x73, 0x39, 0xa6, 0x2, 0x13, 0x80, 0xeb, 0x76, 0x6d, 0xdb, 0x77, 0xd, 0xb0, 0xd0, 0x6a, 0x9c, 0xe9, 0x7c, 0x22, 0x91, 0xba, 0x92, 0x4c, 0xa6, 0xdf, 0xf3, 0x7a, 0x3d, 0x91, 0x23, 0x7c, 0x56, 0x16, 0x37, 0xd0, 0x27, 0xe, 0xf6, 0x70, 0x6f, 0xc2, 0x20, 0x60, 0x6d, 0xb3, 0x37, 0xe, 0x1c, 0x80, 0x61, 0x18, 0x5a, 0xb9, 0x5c, 0xfc, 0xbc, 0x5a, 0x2d, 0x7d, 0xcb, 0x1f, 0x79, 0xc4, 0x54, 0x33, 0xb5, 0x3d, 0x34, 0x71, 0xfb, 0xee, 0x1, 0x76, 0x9e, 0x69, 0x35, 0x9b, 0x5d, 0x7e, 0x5f, 0x55, 0x23, 0x9b, 0x0, 0xea, 0xf7, 0x7b, 0x29, 0x99, 0x4c, 0x52, 0x34, 0x1a, 0xa5, 0xb9, 0xb9, 0x39, 0xf2, 0x7a, 0xb1, 0x61, 0xe7, 0xc1, 0xc7, 0x4d, 0xb5, 0x5a, 0x8d, 0xa, 0x85, 0x2, 0xf5, 0x60, 0x70, 0xc3, 0x21, 0xf, 0x1, 0xdf, 0xc6, 0x67, 0xdd, 0x65, 0x4c, 0x63, 0x13, 0x0, 0xde, 0x68, 0x1c, 0xfc, 0xb0, 0xb3, 0x93, 0xfb, 0x94, 0xe5, 0xfc, 0xcd, 0x54, 0x31, 0x41, 0x8b, 0xd, 0x48, 0xc0, 0xd2, 0x67, 0xa1, 0xd9, 0xb5, 0x73, 0xe7, 0x56, 0x3e, 0x9, 0x87, 0xd5, 0x97, 0x61, 0xb6, 0xe9, 0x74, 0x42, 0x80, 0x5, 0x88, 0x6a, 0xb5, 0x4a, 0xdd, 0x8e, 0x21, 0x74, 0x65, 0x1f, 0x10, 0xa0, 0x70, 0x68, 0xb, 0x6, 0x83, 0xe2, 0x60, 0x40, 0xa5, 0x52, 0x89, 0xca, 0xc5, 0x9a, 0x43, 0x4, 0x91, 0xda, 0x9e, 0x6, 0x9a, 0x3b, 0x2f, 0x40, 0x37, 0x9b, 0xda, 0x4f, 0xf9, 0xfc, 0xf6, 0x87, 0xbc, 0xea, 0x81, 0xa9, 0x69, 0x4, 0xb7, 0x1, 0x2, 0x13, 0x6, 0x8e, 0x3b, 0xc8, 0x94, 0x9d, 0x9f, 0x4f, 0xbf, 0x1d, 0x8f, 0x27, 0xde, 0x1, 0xd8, 0x6c, 0x36, 0x43, 0xaa, 0xaa, 0x52, 0x3e, 0x9f, 0x67, 0xb0, 0xd, 0xea, 0xf7, 0x9d, 0xa0, 0x1e, 0x7d, 0xd8, 0x60, 0xe5, 0x75, 0xbb, 0x3a, 0x1d, 0x1c, 0x34, 0xa9, 0xdd, 0x6e, 0x88, 0x83, 0xa, 0x86, 0x2, 0xd4, 0xd4, 0x9a, 0xb6, 0x43, 0x7a, 0xbc, 0xfe, 0x8f, 0xbd, 0xfb, 0xfd, 0x81, 0x35, 0x0, 0x6d, 0xb5, 0x9a, 0x7f, 0xf2, 0xb3, 0xc1, 0x4, 0x7f, 0x1e, 0x48, 0xbb, 0xc2, 0x13, 0xd1, 0x78, 0x39, 0x99, 0x4c, 0x5d, 0x87, 0x19, 0x27, 0x93, 0x31, 0xa, 0x85, 0x42, 0x94, 0xcb, 0xe5, 0xa8, 0xd5, 0xc2, 0xda, 0xd3, 0x8d, 0x46, 0xa3, 0x2b, 0x78, 0x21, 0x23, 0x91, 0x8c, 0xfe, 0xe7, 0xe1, 0x1c, 0xa0, 0xe7, 0xe7, 0x53, 0xef, 0xf2, 0xae, 0x57, 0x4c, 0x6c, 0x50, 0xae, 0x47, 0x46, 0xf, 0xdc, 0xb3, 0xf1, 0x4c, 0x66, 0xf1, 0x2d, 0xe, 0x50, 0xa1, 0x0, 0x7, 0xe2, 0x54, 0x2a, 0x45, 0x3b, 0x3b, 0x3b, 0x36, 0x3f, 0x3c, 0x1d, 0x68, 0xf8, 0xf0, 0xee, 0xee, 0xae, 0x90, 0xe5, 0x53, 0x46, 0x5b, 0xc7, 0xe9, 0x24, 0x4f, 0xb6, 0xda, 0xeb, 0xf5, 0x85, 0x18, 0xd3, 0x9b, 0xc0, 0x6, 0x8f, 0x3, 0x97, 0xb8, 0x62, 0x98, 0x0, 0x38, 0xa1, 0xaa, 0xd1, 0x4d, 0x4c, 0x46, 0x93, 0x11, 0x76, 0xfc, 0xc6, 0x99, 0x34, 0x6b, 0xdf, 0x4a, 0xb3, 0xd9, 0x63, 0x7f, 0x6a, 0x52, 0x3c, 0x1e, 0x67, 0x9f, 0xc6, 0x75, 0xe9, 0x3c, 0x7a, 0xbd, 0x36, 0xad, 0xaf, 0xaf, 0xd3, 0xc5, 0x8b, 0x17, 0xa8, 0xd3, 0xe9, 0xd0, 0xd6, 0xd6, 0x1d, 0xda, 0xdb, 0x2b, 0xb1, 0x85, 0x4, 0xe8, 0xea, 0xd5, 0xd7, 0x8f, 0x31, 0xdd, 0xba, 0xf5, 0xdd, 0x89, 0xb9, 0xdb, 0xb7, 0x7f, 0x64, 0x57, 0x3a, 0x38, 0x21, 0x1c, 0x81, 0x97, 0xe3, 0xe7, 0x17, 0xfc, 0x62, 0x8f, 0xa9, 0x63, 0x5, 0x1c, 0xe3, 0x7b, 0x36, 0xd, 0xfc, 0xb1, 0x58, 0x8c, 0xca, 0xe5, 0xf2, 0x64, 0xc7, 0x38, 0xc1, 0x2a, 0x4d, 0xd3, 0x84, 0x3f, 0x8f, 0x2, 0xbc, 0xb1, 0xb1, 0x21, 0x80, 0xde, 0xbc, 0xf9, 0x25, 0x7, 0xca, 0x34, 0x5d, 0xbe, 0xfc, 0xaa, 0xf8, 0x1d, 0x80, 0x31, 0xac, 0x80, 0x9c, 0xe6, 0xdc, 0xb6, 0xa1, 0x28, 0xa, 0x72, 0x9, 0x24, 0x4c, 0x2, 0xab, 0xf4, 0x61, 0xd8, 0x37, 0x82, 0x96, 0x50, 0x7b, 0x20, 0xc0, 0x81, 0x86, 0xb5, 0x32, 0xab, 0x1, 0x59, 0x90, 0x39, 0x4a, 0xbb, 0xcb, 0xcb, 0xe7, 0xe8, 0xfe, 0xfd, 0x3f, 0x38, 0xd8, 0x4, 0xf9, 0x46, 0xd0, 0xe8, 0xc1, 0x83, 0x7f, 0x68, 0x75, 0x75, 0x55, 0xb0, 0xec, 0xef, 0x97, 0x4e, 0xb0, 0x3a, 0xcd, 0x39, 0xcb, 0x17, 0x89, 0x12, 0xb2, 0x43, 0xe1, 0xc3, 0x2, 0x20, 0x7e, 0x91, 0x13, 0xf8, 0x83, 0x4f, 0x85, 0xf4, 0x63, 0x77, 0xe8, 0x74, 0xd0, 0x21, 0xb, 0x32, 0xdd, 0x6, 0x2c, 0xa, 0x0, 0xac, 0x26, 0x59, 0x2c, 0x16, 0x84, 0xa6, 0x8b, 0xc5, 0x22, 0x47, 0xfe, 0xe, 0x5d, 0xba, 0xf4, 0xa2, 0x60, 0xbf, 0x77, 0xef, 0x77, 0xd2, 0xf5, 0xce, 0x89, 0x39, 0x27, 0x73, 0x16, 0xc0, 0xe, 0x33, 0xa6, 0x61, 0xa6, 0x23, 0x77, 0x21, 0x73, 0x53, 0x21, 0x14, 0xc9, 0x3, 0xee, 0xd4, 0xe3, 0x89, 0xc3, 0xd9, 0x41, 0x43, 0x16, 0x64, 0xba, 0xd, 0x45, 0x99, 0xa3, 0x85, 0x85, 0x94, 0xb8, 0xbb, 0xe5, 0xc6, 0xa3, 0xd1, 0x98, 0x0, 0x25, 0x7, 0x80, 0xca, 0x77, 0xd2, 0xa4, 0xad, 0x73, 0x6e, 0xb2, 0xcd, 0x14, 0x14, 0xd9, 0x8e, 0x88, 0x9a, 0xd2, 0xa4, 0x71, 0x29, 0x73, 0x12, 0x3e, 0xe0, 0x5d, 0xd, 0xf8, 0x43, 0x5d, 0xa, 0x87, 0xc3, 0x67, 0x47, 0x68, 0xe3, 0x84, 0x2c, 0xc8, 0x74, 0x1b, 0x0, 0x2, 0xd, 0x27, 0x12, 0x51, 0xb1, 0x4, 0xc0, 0xd7, 0xd6, 0x5e, 0x10, 0xda, 0x9d, 0x7e, 0x0, 0x93, 0x28, 0x30, 0x44, 0xe2, 0x1, 0xd, 0x3, 0x39, 0xc, 0xf8, 0x40, 0xd7, 0x8d, 0x82, 0xdf, 0xef, 0xcb, 0xd6, 0xeb, 0x75, 0x91, 0x70, 0xd4, 0x6a, 0xb3, 0xf1, 0xe3, 0x48, 0x24, 0x42, 0x90, 0x39, 0x6a, 0xdc, 0xb9, 0xb3, 0x45, 0x9b, 0x9b, 0xaf, 0xd0, 0x85, 0xb, 0x1a, 0x47, 0xf4, 0x88, 0xf0, 0x61, 0x19, 0xa5, 0xa7, 0x1, 0xcd, 0x96, 0x85, 0x42, 0x2, 0x1f, 0x17, 0x89, 0x87, 0x35, 0xd3, 0xa, 0x70, 0x76, 0xb2, 0xc0, 0xa9, 0xe1, 0xa5, 0x7e, 0x5b, 0xa7, 0xcc, 0x62, 0x86, 0xaf, 0x25, 0x8d, 0x4d, 0xd1, 0xb5, 0xb4, 0x9c, 0x68, 0x1f, 0xe1, 0xb0, 0x5f, 0xdc, 0xc3, 0xb8, 0x8f, 0xd, 0xc3, 0x3d, 0xc3, 0xe2, 0x8a, 0x87, 0xb6, 0xb7, 0xf3, 0xc4, 0x55, 0xf, 0xdd, 0xbd, 0xfb, 0x1b, 0xe7, 0x0, 0xfb, 0x42, 0x7e, 0xab, 0xd5, 0x10, 0xa6, 0xdd, 0xeb, 0xf5, 0x87, 0x56, 0xe2, 0x34, 0xe7, 0x6e, 0x3d, 0xb5, 0xaf, 0x38, 0xcd, 0xfc, 0x85, 0xdf, 0xe3, 0xda, 0xd1, 0x25, 0x60, 0x61, 0xde, 0xfc, 0xa2, 0xc0, 0xa9, 0xe5, 0x35, 0xc3, 0x33, 0x60, 0xaf, 0x33, 0x28, 0x93, 0xc9, 0x88, 0xd, 0x20, 0x65, 0x3c, 0xcb, 0xf0, 0xb3, 0x94, 0xa5, 0xa5, 0x25, 0xaa, 0x54, 0x2a, 0xd4, 0xe4, 0xcc, 0x6b, 0xdc, 0x80, 0xd9, 0xd7, 0xeb, 0x7, 0x34, 0x18, 0x1c, 0x1d, 0x8c, 0xcf, 0xa7, 0x70, 0x4e, 0xd0, 0x3a, 0xe6, 0x12, 0x4e, 0x73, 0x4e, 0xb2, 0xd, 0xa3, 0xdf, 0xca, 0xe5, 0x1e, 0x7e, 0xc0, 0xef, 0x1e, 0x32, 0x21, 0xbd, 0x34, 0xac, 0x80, 0x45, 0x46, 0xcf, 0x41, 0x4d, 0xf, 0x85, 0xc2, 0x2f, 0xb5, 0xdb, 0x5d, 0x2e, 0x4, 0x2, 0xe2, 0xfe, 0xec, 0x74, 0x9a, 0xa7, 0xd6, 0xb4, 0xaa, 0x6, 0x38, 0x17, 0xcf, 0x72, 0x4e, 0xdd, 0xa6, 0x52, 0xa1, 0xea, 0x58, 0x70, 0x8c, 0x3b, 0x80, 0x69, 0xde, 0x23, 0x58, 0x55, 0x2a, 0xc5, 0xcf, 0x38, 0x97, 0xfe, 0x95, 0xe5, 0x20, 0x18, 0xe0, 0xc4, 0x87, 0x26, 0xd, 0xd9, 0xa2, 0x5d, 0xc2, 0xb, 0x76, 0x82, 0xc1, 0xd0, 0xf3, 0x7e, 0xbf, 0x7f, 0x4d, 0xe3, 0xa4, 0x5f, 0x51, 0xbc, 0xb4, 0xb8, 0xb8, 0x28, 0x9e, 0xb8, 0xe, 0xc, 0x97, 0x2, 0x42, 0xa4, 0x6b, 0xac, 0x51, 0x55, 0xd, 0xf2, 0x75, 0x32, 0x2f, 0xac, 0x43, 0x94, 0x89, 0x7b, 0x65, 0xf7, 0x7e, 0xcb, 0x34, 0x88, 0x46, 0xf0, 0xca, 0x6a, 0x69, 0x7f, 0x7f, 0xf7, 0x6, 0x2f, 0x43, 0x43, 0x40, 0x68, 0x17, 0x2c, 0x6e, 0xf5, 0x30, 0x97, 0x88, 0xe7, 0x3f, 0xe2, 0xe8, 0xba, 0x81, 0x6b, 0x4c, 0x51, 0x3c, 0xc2, 0xf, 0xa7, 0xab, 0x87, 0x1f, 0x13, 0x3a, 0x9b, 0xd8, 0x43, 0xb0, 0x8d, 0x9f, 0xf3, 0xf9, 0x47, 0x1f, 0xf3, 0xab, 0xbf, 0x98, 0x1c, 0xeb, 0x61, 0xc9, 0x26, 0x3b, 0x1e, 0xe8, 0x61, 0x9d, 0xe7, 0x6a, 0xe3, 0xa, 0xd3, 0x75, 0x9f, 0xcf, 0xcb, 0x95, 0x94, 0xac, 0x61, 0xad, 0x25, 0xb4, 0xf5, 0x6b, 0xe3, 0x8a, 0x3, 0xc9, 0x6f, 0x97, 0x33, 0xbb, 0x83, 0xe8, 0xf7, 0xfb, 0x1a, 0x9b, 0xf1, 0x8d, 0x4a, 0x65, 0xd8, 0xf1, 0x40, 0x9f, 0xb, 0xa6, 0xec, 0xd8, 0xf1, 0xb0, 0x82, 0x46, 0x31, 0x81, 0x72, 0x91, 0x73, 0x6b, 0x5a, 0xe1, 0x9e, 0xd6, 0x1b, 0x66, 0x4f, 0x6b, 0x1, 0xd9, 0xd9, 0x93, 0xee, 0x67, 0xc9, 0x8d, 0x1e, 0x26, 0x15, 0xa2, 0xa7, 0xb5, 0x6f, 0xf6, 0xb4, 0xbe, 0xe1, 0x89, 0x6d, 0xd3, 0x67, 0xd1, 0xd3, 0xc2, 0x75, 0x7b, 0x2c, 0xe4, 0x8e, 0xeb, 0x5a, 0xce, 0x31, 0x83, 0xca, 0x4, 0x8d, 0xa3, 0xf5, 0x63, 0xef, 0x5a, 0xce, 0x4e, 0x3d, 0xa7, 0x97, 0x4, 0x20, 0xd6, 0xae, 0x25, 0x4c, 0x17, 0x1a, 0x85, 0xbf, 0x22, 0x45, 0x13, 0x89, 0x86, 0x5d, 0xec, 0xa8, 0xd6, 0x3, 0xde, 0xc9, 0x1c, 0x1b, 0x9, 0xa, 0xb2, 0x7f, 0x68, 0x5e, 0x24, 0xe1, 0x26, 0x9d, 0x7e, 0x9b, 0xb3, 0xe3, 0x90, 0x8d, 0x77, 0xd9, 0x97, 0x86, 0xe9, 0x22, 0xb9, 0x90, 0x40, 0x1d, 0x7d, 0x6c, 0xd2, 0x5e, 0x8b, 0x4, 0xf8, 0x34, 0x0, 0xb5, 0x1f, 0x99, 0xf5, 0xbf, 0xe, 0xe3, 0x2, 0xc9, 0xec, 0x8e, 0xfb, 0x99, 0xa4, 0xa7, 0xf4, 0x4, 0xfe, 0x5, 0x72, 0xf1, 0x9c, 0xca, 0xa6, 0xf4, 0x2a, 0x9a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0xfc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x2b, 0x26, 0x2c, 0x40, 0x40, 0x44, 0x4e, 0x4e, 0x52, 0x1a, 0x1a, 0x1d, 0x32, 0x32, 0x37, 0x2c, 0x26, 0x2c, 0x26, 0x25, 0x2a, 0x27, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x2f, 0x26, 0x2d, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x5b, 0x5b, 0x5f, 0x84, 0x84, 0x87, 0x77, 0x77, 0x7a, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x69, 0x69, 0x6c, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x27, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1e, 0x0, 0x0, 0x0, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0xb, 0x1b, 0xbb, 0x0, 0x0, 0x0, 0x54, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x98, 0xe5, 0xfa, 0xfe, 0xff, 0xff, 0x8, 0x17, 0x35, 0x86, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x7, 0x3a, 0xb4, 0xff, 0xff, 0xff, 0xb9, 0xff, 0xff, 0xff, 0xff, 0xb, 0x28, 0x8a, 0xff, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x37, 0xf, 0xff, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xd4, 0x6d, 0x6c, 0xf9, 0x0, 0x0, 0x2, 0x3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x55, 0x85, 0x9a, 0xe2, 0x30, 0x18, 0xbc, 0x7a, 0x8b, 0xbb, 0x7b, 0x2, 0xbb, 0x4d, 0x36, 0xb8, 0x3b, 0xeb, 0xae, 0xef, 0xff, 0x2e, 0x47, 0x48, 0x3f, 0xa0, 0x7a, 0xae, 0x83, 0x56, 0xfe, 0xe9, 0xfc, 0xfe, 0xe9, 0x6f, 0x2, 0xc7, 0xb, 0x82, 0xf8, 0x45, 0x8, 0x2, 0xcf, 0x39, 0x9a, 0xf3, 0xa2, 0x24, 0x2b, 0xaa, 0xe6, 0xfb, 0x2, 0x34, 0x55, 0x91, 0x25, 0x91, 0xb7, 0x3f, 0x5d, 0xf4, 0xab, 0x81, 0x60, 0x28, 0x1c, 0x89, 0xc6, 0x3c, 0x11, 0x8d, 0x84, 0x43, 0xc1, 0x80, 0xea, 0x17, 0x2d, 0x2a, 0xf8, 0x78, 0x22, 0x99, 0x4a, 0x67, 0xb2, 0xb9, 0x7c, 0xe1, 0xb, 0xc8, 0xe7, 0xb2, 0x99, 0x74, 0x2a, 0x99, 0x88, 0xf3, 0x26, 0xfb, 0x62, 0xa9, 0x5c, 0xa9, 0xd6, 0x0, 0x80, 0x10, 0xb2, 0xfb, 0x20, 0x5, 0x80, 0x75, 0xe8, 0x48, 0x52, 0xad, 0x94, 0x4b, 0xc5, 0x23, 0x6, 0xae, 0xa1, 0x9d, 0x9c, 0xd6, 0x80, 0x8e, 0xf0, 0x1e, 0x48, 0xdf, 0xb1, 0xd4, 0x81, 0x8b, 0x8e, 0xd3, 0x13, 0xad, 0xc1, 0x1d, 0xfc, 0x57, 0x82, 0x67, 0x35, 0x48, 0x30, 0x6a, 0xb6, 0x76, 0x97, 0x5b, 0x3a, 0x41, 0x98, 0xb4, 0x77, 0x4a, 0xdc, 0x3c, 0x39, 0xb, 0x2a, 0xfb, 0x38, 0xf0, 0x9d, 0x6e, 0xaf, 0x6, 0x11, 0xea, 0x1f, 0xdf, 0x41, 0x10, 0x6a, 0x7b, 0xc6, 0x62, 0xd0, 0xed, 0xf0, 0x6, 0x81, 0x58, 0xa, 0xd, 0x1, 0xa1, 0xa2, 0x8f, 0xa1, 0x23, 0xd2, 0xf2, 0x62, 0x18, 0x8e, 0x4a, 0x63, 0x26, 0x81, 0x93, 0x2, 0x13, 0xa0, 0xe3, 0xbe, 0xf5, 0xe, 0x82, 0x3d, 0x25, 0x14, 0x26, 0x1, 0x89, 0x11, 0xf0, 0x72, 0x70, 0xba, 0x15, 0x60, 0xbf, 0x3, 0x11, 0xe3, 0xcf, 0x6c, 0xbe, 0x58, 0xa2, 0x42, 0x7f, 0xb1, 0xc5, 0xee, 0x8b, 0x9d, 0x5f, 0xad, 0x37, 0xcc, 0x7, 0x41, 0x9, 0x65, 0x21, 0xbd, 0xd9, 0x8a, 0x3d, 0xe9, 0xf9, 0x7c, 0x46, 0x16, 0xb3, 0x3e, 0x35, 0xa4, 0x5f, 0x6, 0x2e, 0x46, 0x8a, 0xc0, 0x8, 0xd4, 0xcb, 0x2b, 0x88, 0x75, 0x3b, 0x81, 0x8e, 0xd, 0x1, 0xd4, 0x68, 0x8e, 0xfa, 0xe7, 0x94, 0xe0, 0x7c, 0x4f, 0x90, 0xbf, 0x56, 0x45, 0x46, 0x50, 0xba, 0xa9, 0x41, 0xec, 0x10, 0xb0, 0x96, 0x41, 0xd0, 0x3f, 0xdf, 0x7e, 0xe1, 0x79, 0xff, 0xfc, 0xfc, 0x9c, 0x6c, 0xbf, 0xf6, 0x14, 0xb7, 0x25, 0x83, 0x40, 0xd, 0xd7, 0x3c, 0x15, 0x90, 0x9d, 0x2, 0xec, 0xae, 0x40, 0x9, 0xdd, 0x1, 0xef, 0x18, 0xa0, 0x2, 0x59, 0xda, 0x5c, 0xd8, 0xc7, 0x80, 0x97, 0xd7, 0x5f, 0xc8, 0x42, 0x7f, 0x79, 0xbe, 0x9c, 0x17, 0x2c, 0x4, 0xfb, 0x2c, 0xd0, 0x3a, 0xb8, 0xff, 0x42, 0x1d, 0x10, 0x5a, 0x95, 0x33, 0x44, 0xd8, 0x97, 0x81, 0xfb, 0xa4, 0xc4, 0xed, 0x2b, 0xf1, 0x1, 0xfe, 0x40, 0x25, 0xd2, 0x5e, 0x18, 0x7c, 0x7b, 0x2f, 0x3c, 0xd2, 0x5e, 0xf8, 0x72, 0x37, 0x16, 0xbe, 0xdc, 0x8d, 0x6c, 0x1e, 0x3c, 0x3d, 0xd7, 0x40, 0xdb, 0x32, 0xf, 0xbc, 0xec, 0x9f, 0x5f, 0xf6, 0xf3, 0x80, 0x4d, 0x24, 0x2d, 0xf8, 0xfa, 0x6, 0xea, 0x80, 0xd, 0x24, 0x68, 0x0, 0x6c, 0x5f, 0x8e, 0xf6, 0xd5, 0xd7, 0xa0, 0x56, 0x34, 0xcf, 0xb4, 0x86, 0x92, 0xc, 0xa5, 0x33, 0x17, 0xf9, 0xc2, 0x17, 0x91, 0xbf, 0xc8, 0xa4, 0x43, 0x49, 0xa5, 0xc1, 0x5b, 0xa7, 0x72, 0x47, 0xd, 0xac, 0x47, 0xd7, 0xef, 0xb1, 0x2f, 0xe0, 0xfd, 0x7a, 0xb4, 0xe, 0xa8, 0x1d, 0x91, 0xb3, 0x6f, 0x95, 0xb1, 0xb4, 0xf9, 0x28, 0x7d, 0x79, 0x2f, 0x94, 0x3e, 0x36, 0xd2, 0x98, 0xe7, 0x5c, 0x36, 0x93, 0xf8, 0x15, 0xa0, 0x9b, 0xe9, 0xff, 0xc2, 0x67, 0x14, 0xf4, 0xa5, 0xb3, 0x35, 0x5e, 0x63, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char toggle_on_png[] = { @@ -347,7 +347,7 @@ static const unsigned char toggle_on_png[] = { }; static const unsigned char toggle_on_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0xa2, 0x9d, 0x7e, 0x84, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x12, 0x0, 0x0, 0xb, 0x12, 0x1, 0xd2, 0xdd, 0x7e, 0xfc, 0x0, 0x0, 0x6, 0x54, 0x49, 0x44, 0x41, 0x54, 0x68, 0x43, 0xed, 0x59, 0x4b, 0x6f, 0x1b, 0x55, 0x14, 0x3e, 0x71, 0xfc, 0x9a, 0xd8, 0x4e, 0x9c, 0x38, 0x6e, 0x62, 0xe7, 0x21, 0xb5, 0x6e, 0x51, 0xd5, 0x5, 0xa8, 0xac, 0x93, 0x14, 0x89, 0x22, 0x84, 0xba, 0x60, 0x53, 0xb1, 0x29, 0x12, 0x42, 0xa0, 0xfe, 0x1, 0x7e, 0x1, 0x7b, 0xb6, 0x6c, 0xaa, 0x82, 0xa8, 0xc4, 0x96, 0x5f, 0x50, 0x21, 0x55, 0x34, 0x1b, 0x4a, 0x17, 0x65, 0x51, 0x9, 0x85, 0x3c, 0x9b, 0xb4, 0x4d, 0xfd, 0x76, 0xfc, 0x7e, 0xf3, 0x7d, 0x37, 0x33, 0xc6, 0x76, 0xed, 0xcc, 0x38, 0x4e, 0x52, 0x21, 0x7a, 0xa4, 0xa3, 0xc9, 0x4c, 0xee, 0x3d, 0xf7, 0xbc, 0xee, 0xb9, 0xdf, 0x3d, 0x16, 0x79, 0x4b, 0x6f, 0x3d, 0xf0, 0xbf, 0xf6, 0xc0, 0xc8, 0x80, 0xd6, 0x73, 0xbc, 0xc1, 0x9c, 0x3a, 0xe8, 0xfc, 0x1, 0x97, 0xb3, 0x3c, 0xbc, 0xa9, 0x8f, 0xe4, 0xd3, 0x60, 0x4b, 0x93, 0xad, 0x1a, 0x60, 0x83, 0x34, 0xb2, 0xa3, 0x8d, 0x47, 0xf5, 0x6f, 0x56, 0x65, 0x58, 0x52, 0xe8, 0x18, 0x83, 0x68, 0x70, 0x3, 0x5c, 0x7, 0x57, 0xdb, 0x98, 0xdf, 0xc8, 0x47, 0x92, 0x99, 0xf2, 0xfc, 0x3f, 0xd, 0x75, 0x82, 0xbd, 0x60, 0xbf, 0xce, 0xe3, 0x78, 0x6a, 0xba, 0x33, 0xe8, 0x18, 0x33, 0x39, 0x66, 0x7a, 0x1c, 0xf7, 0xff, 0x86, 0xf1, 0x34, 0xbc, 0x8, 0x3e, 0x0, 0xa7, 0x75, 0xce, 0xe1, 0x59, 0xd1, 0x1d, 0x63, 0x64, 0xc8, 0x6b, 0xeb, 0x1c, 0xa5, 0x38, 0xd, 0xb3, 0xeb, 0x86, 0x7, 0xf1, 0x9c, 0xf7, 0xf9, 0x26, 0x96, 0xc1, 0x1f, 0x39, 0x9d, 0xce, 0xb, 0x36, 0xdb, 0xe8, 0xb8, 0xcd, 0x66, 0xd3, 0x46, 0x40, 0xc7, 0xd5, 0xfe, 0x24, 0xe6, 0x35, 0x41, 0x8d, 0x46, 0xa3, 0xd8, 0x68, 0xd4, 0xf, 0x2a, 0x95, 0xca, 0x66, 0x36, 0x9b, 0xb9, 0xf, 0x7e, 0x8, 0xd9, 0x7b, 0xe0, 0x18, 0x98, 0x8e, 0xa8, 0xf5, 0xcb, 0x86, 0x7e, 0xca, 0xd3, 0x78, 0x46, 0x7d, 0x2, 0xbc, 0x38, 0x36, 0xe6, 0x5d, 0x9, 0x4, 0x82, 0xb7, 0x5d, 0x2e, 0xf7, 0x3b, 0x6f, 0xd8, 0x5e, 0x53, 0x9f, 0xc1, 0x1f, 0x52, 0x2e, 0x97, 0xd6, 0x12, 0x89, 0xd8, 0x9d, 0x42, 0x21, 0xf7, 0x1b, 0x26, 0x3c, 0x3, 0x67, 0xf4, 0x6c, 0x78, 0x6d, 0x4b, 0xf4, 0x72, 0x0, 0xbf, 0xd1, 0xf8, 0x49, 0xf0, 0x85, 0xc9, 0xc9, 0xe9, 0xcf, 0xa7, 0xa6, 0xa6, 0xbf, 0x42, 0xb4, 0xf9, 0xed, 0x4c, 0x49, 0xd3, 0xec, 0x32, 0x3b, 0x3b, 0x2b, 0x93, 0x93, 0x93, 0xa2, 0x69, 0x9a, 0x40, 0x87, 0xbe, 0xeb, 0xd7, 0x6a, 0x35, 0x89, 0xc7, 0xe3, 0xb2, 0xb7, 0xb7, 0x27, 0xc5, 0x62, 0x4d, 0x90, 0x15, 0x95, 0x64, 0x32, 0xfe, 0x43, 0x2a, 0x15, 0xff, 0x19, 0x93, 0x36, 0xc1, 0x29, 0xdd, 0x9, 0x1d, 0xdb, 0xa1, 0xdb, 0x1, 0xc6, 0x9e, 0x67, 0xe4, 0x23, 0x53, 0x53, 0xc1, 0xaf, 0x61, 0xfc, 0xd7, 0x67, 0x9e, 0xe6, 0xb6, 0x51, 0x59, 0x98, 0xb, 0xca, 0xcc, 0xcc, 0x8c, 0x24, 0x12, 0x9, 0x65, 0x58, 0x36, 0x87, 0x6d, 0xde, 0xec, 0x51, 0xd3, 0xb0, 0x3, 0x35, 0xb7, 0x4d, 0x3c, 0x1e, 0x8f, 0xf8, 0xfd, 0x7e, 0xe5, 0xac, 0xfd, 0xfd, 0x7d, 0xd9, 0x7d, 0x1e, 0x93, 0x66, 0xbd, 0xd6, 0x84, 0x13, 0xee, 0x26, 0x93, 0xb1, 0xbb, 0xb0, 0x67, 0x43, 0xcf, 0x4, 0x16, 0xcb, 0x96, 0x13, 0x58, 0xe0, 0xda, 0x89, 0x2e, 0x76, 0x83, 0x43, 0x1e, 0x8f, 0xef, 0xe3, 0x60, 0x70, 0xe6, 0x1b, 0x78, 0xbd, 0x7b, 0xcc, 0xe9, 0x66, 0x1, 0x96, 0x8b, 0x9c, 0x9f, 0x93, 0x89, 0x89, 0x9, 0xd9, 0xdc, 0xdc, 0x84, 0x31, 0x9, 0xa9, 0x54, 0xb8, 0x85, 0xfb, 0xd5, 0xb1, 0xa6, 0xd4, 0x6a, 0xd, 0x29, 0x14, 0xca, 0x92, 0x4c, 0x66, 0xf0, 0xcc, 0x4a, 0x28, 0x14, 0x12, 0xaf, 0xc7, 0x2d, 0xa9, 0x4c, 0x7e, 0xc4, 0xed, 0x72, 0xbd, 0x57, 0xa9, 0x94, 0xb7, 0xaa, 0xd5, 0xca, 0x2e, 0x84, 0xe4, 0xc1, 0x1d, 0xc2, 0xba, 0x8d, 0xe3, 0x3b, 0x2b, 0xfd, 0xa5, 0x50, 0x68, 0xfe, 0x5b, 0x87, 0xc3, 0x11, 0x38, 0x5d, 0x6b, 0xbb, 0xa4, 0x23, 0x9a, 0xe1, 0x50, 0x40, 0x45, 0x71, 0x6d, 0x6d, 0x4d, 0x72, 0xb9, 0xf2, 0xc0, 0xcb, 0x97, 0x4a, 0x55, 0x39, 0x38, 0x48, 0x29, 0x27, 0x8c, 0xda, 0x9a, 0x92, 0xcb, 0x97, 0x6c, 0x28, 0xda, 0x91, 0x4c, 0x26, 0xc5, 0x7a, 0xc0, 0x6d, 0x40, 0xa1, 0x2d, 0x6f, 0xb6, 0x6f, 0x2a, 0xa6, 0x3f, 0xcf, 0xf9, 0x89, 0xf1, 0x71, 0xff, 0xa, 0xa, 0xde, 0xf9, 0x81, 0x57, 0x1f, 0x72, 0x82, 0xcb, 0x39, 0xa2, 0x14, 0xdf, 0xd9, 0xd9, 0x51, 0xfb, 0xf8, 0xb8, 0xc4, 0xb9, 0x94, 0x11, 0xe, 0x87, 0x85, 0x32, 0x69, 0xb, 0x6c, 0x5a, 0xa6, 0x6d, 0x60, 0x9e, 0x6c, 0x2d, 0xea, 0xe5, 0x0, 0xbf, 0xd7, 0x3b, 0x7e, 0xdd, 0xea, 0xe2, 0x73, 0x73, 0x61, 0xb9, 0x7a, 0xf5, 0x5d, 0xb9, 0x75, 0xeb, 0x33, 0xb9, 0x79, 0xf3, 0x53, 0xec, 0xdb, 0xc3, 0xa4, 0xd1, 0x34, 0xa7, 0xfa, 0x66, 0x43, 0x14, 0x8c, 0xf7, 0x6b, 0xd7, 0x96, 0x8e, 0x14, 0x1b, 0xc, 0x6, 0x11, 0xbd, 0x3, 0x49, 0xa7, 0x99, 0xa9, 0xc3, 0x11, 0x65, 0x64, 0x32, 0x19, 0xa1, 0x4c, 0x92, 0xd7, 0xeb, 0xa3, 0x4d, 0x2c, 0xec, 0x2c, 0xe6, 0xad, 0xda, 0xd7, 0xcb, 0x1, 0xe3, 0x48, 0x19, 0xcb, 0xd1, 0xbf, 0x78, 0xf1, 0x2, 0x3c, 0xec, 0x92, 0x7, 0xf, 0x56, 0xe5, 0xfe, 0xfd, 0x5f, 0xe5, 0xfa, 0xf5, 0xf, 0x85, 0x4e, 0x31, 0x68, 0x79, 0x99, 0x8e, 0xb7, 0x46, 0x4c, 0xfd, 0x74, 0x9a, 0x38, 0xe6, 0x64, 0x88, 0xb2, 0x28, 0x93, 0xe4, 0x74, 0xba, 0x22, 0x78, 0x10, 0xc0, 0x31, 0x3, 0x7a, 0x3a, 0x80, 0xe3, 0x58, 0x3, 0xdc, 0x4, 0x39, 0x56, 0x54, 0xa0, 0xa1, 0xf3, 0xf3, 0x61, 0x79, 0xfa, 0xf4, 0x2f, 0x79, 0xfe, 0xfc, 0x5, 0x3c, 0x9e, 0x93, 0x8d, 0x8d, 0x2d, 0x44, 0xfd, 0x70, 0x76, 0x34, 0x9a, 0x40, 0x4, 0x2, 0x2a, 0x1b, 0xac, 0x10, 0x8f, 0xba, 0x7c, 0x7e, 0xf8, 0xe8, 0x1b, 0x6b, 0x51, 0x16, 0x65, 0x2a, 0xc3, 0x46, 0xed, 0xac, 0x6d, 0x7c, 0xa1, 0x8d, 0x7d, 0x1d, 0xa0, 0x8e, 0x41, 0x22, 0x3c, 0x2b, 0xa, 0xe3, 0x88, 0x51, 0x46, 0x66, 0xb3, 0xd9, 0xd6, 0xf0, 0x78, 0x3c, 0x26, 0xd3, 0xd3, 0xd3, 0xea, 0x1d, 0xd5, 0x57, 0x9e, 0x3c, 0xf9, 0x53, 0x96, 0x96, 0xac, 0x65, 0x1, 0x8a, 0xae, 0x14, 0x8a, 0xa6, 0xf0, 0xdd, 0x8a, 0x6a, 0x6a, 0xc, 0x65, 0x51, 0x26, 0x49, 0xc7, 0x31, 0xaf, 0xc1, 0xf6, 0x6e, 0x64, 0xa1, 0xb0, 0x35, 0xd0, 0x14, 0xb1, 0xb5, 0x29, 0xd9, 0xed, 0x2e, 0x39, 0x77, 0x2e, 0x20, 0x3e, 0x9f, 0xaf, 0x35, 0xd6, 0xe7, 0x1b, 0x57, 0x86, 0x1b, 0xb4, 0xbe, 0xbe, 0xcd, 0xf4, 0x93, 0xcb, 0x97, 0x2f, 0x9b, 0xca, 0xab, 0x56, 0xab, 0x32, 0xa6, 0xf5, 0x7, 0x3b, 0xa6, 0x2, 0xba, 0x6, 0x50, 0x16, 0x65, 0x92, 0x8, 0x8c, 0xf8, 0x0, 0x77, 0x9c, 0xa7, 0xdd, 0xab, 0x11, 0x24, 0x14, 0xeb, 0xf5, 0x9a, 0xa5, 0x8d, 0xc8, 0xc8, 0x33, 0x3, 0xfc, 0xfe, 0x43, 0x7, 0xd0, 0x11, 0x91, 0xc8, 0x79, 0x5, 0x5c, 0xda, 0xe9, 0xf1, 0xe3, 0xdf, 0xe5, 0xca, 0x15, 0x73, 0x7, 0x14, 0x8b, 0x45, 0x5, 0x68, 0x4e, 0x8a, 0x28, 0x8b, 0x32, 0x49, 0xba, 0x4d, 0x7c, 0xe9, 0x0, 0x42, 0xed, 0x47, 0x2, 0x3d, 0x43, 0x77, 0x65, 0x71, 0xa9, 0xd8, 0x70, 0x38, 0x9c, 0xe7, 0xac, 0x28, 0xb2, 0xba, 0xfa, 0x50, 0x6e, 0xdc, 0xf8, 0x4, 0x11, 0xce, 0x1, 0xbc, 0x78, 0x55, 0xd, 0x78, 0xf5, 0x2a, 0xd1, 0xb1, 0xef, 0xf9, 0x4e, 0x47, 0x99, 0x51, 0x2a, 0x95, 0x52, 0x68, 0x2e, 0x16, 0xb3, 0xe4, 0x7f, 0x33, 0x71, 0x4a, 0x16, 0x65, 0x92, 0x90, 0x95, 0x44, 0x82, 0xbc, 0x2d, 0x1e, 0x9, 0x84, 0xd4, 0x25, 0x8, 0xd0, 0xd7, 0x87, 0x63, 0x63, 0xc5, 0x74, 0x5, 0x4a, 0xab, 0xd5, 0x65, 0x77, 0xf7, 0x5, 0x40, 0xcb, 0x81, 0x3c, 0x7a, 0xf4, 0x87, 0xbc, 0x7c, 0x19, 0x55, 0xd3, 0x8, 0x63, 0xa3, 0xd1, 0x7d, 0x14, 0xb5, 0xc3, 0x8, 0x6c, 0x6f, 0x6f, 0x22, 0x1a, 0x85, 0xd6, 0x7b, 0x2f, 0xd9, 0xe5, 0x72, 0x51, 0x16, 0x16, 0x16, 0x30, 0x2e, 0x27, 0x4, 0x34, 0xc3, 0x90, 0xdf, 0xef, 0x51, 0x38, 0x60, 0x6b, 0x6b, 0xb, 0xd1, 0x6f, 0xc2, 0x11, 0x89, 0x7b, 0xb8, 0x24, 0x3d, 0x82, 0xcc, 0xa4, 0xee, 0x4, 0x25, 0xbe, 0x17, 0xcc, 0xb5, 0x61, 0x60, 0x11, 0xe, 0x58, 0xb6, 0xdb, 0xed, 0x87, 0x67, 0x88, 0x9, 0x21, 0x63, 0x70, 0x7e, 0x67, 0xa5, 0xd9, 0xfc, 0xf7, 0x6a, 0xc1, 0xed, 0x61, 0x18, 0xcf, 0xe9, 0xfc, 0x5f, 0xfb, 0x7b, 0x2f, 0x91, 0x75, 0xec, 0xd0, 0x11, 0x6c, 0x53, 0x2a, 0x4e, 0x34, 0x47, 0x88, 0x7b, 0x1c, 0xe2, 0x25, 0x2a, 0x12, 0x89, 0x20, 0x13, 0x5f, 0x49, 0x3a, 0x53, 0xe0, 0xed, 0x70, 0x2b, 0x1a, 0x7d, 0xf9, 0x3d, 0x64, 0xed, 0x80, 0x79, 0xcc, 0xb4, 0x4, 0xf7, 0x72, 0x0, 0xb7, 0xc2, 0x8, 0x6e, 0x57, 0x39, 0xdc, 0x7, 0x3e, 0x40, 0x36, 0x9c, 0x5c, 0x55, 0xb2, 0x60, 0x4d, 0x36, 0x5f, 0x56, 0x38, 0x9e, 0x88, 0xb0, 0x54, 0xca, 0x43, 0xf9, 0xc1, 0x32, 0x81, 0x91, 0xa7, 0xf1, 0xb9, 0x5c, 0x4e, 0x9e, 0xed, 0x45, 0xa5, 0x51, 0xaf, 0xd5, 0x62, 0xb1, 0xfd, 0xef, 0x70, 0x17, 0x60, 0xf4, 0x59, 0x9c, 0x58, 0xc, 0xfb, 0x5e, 0x86, 0xa8, 0xa2, 0x6a, 0x2f, 0x61, 0x42, 0x86, 0xc6, 0x6b, 0xda, 0xd8, 0xfb, 0x67, 0x7a, 0x1b, 0xc4, 0x7d, 0x3e, 0x5, 0x3c, 0xe1, 0x74, 0xd8, 0x64, 0x71, 0x71, 0x11, 0x20, 0xcb, 0x81, 0x14, 0xae, 0x48, 0xa5, 0x6a, 0xe8, 0xdc, 0xde, 0x96, 0xc4, 0xdf, 0x88, 0x8f, 0xa6, 0x8d, 0xaa, 0x42, 0x1c, 0xe, 0xcf, 0x2, 0x84, 0xcd, 0xa1, 0x86, 0xc4, 0x64, 0xfb, 0xd9, 0xbe, 0xba, 0xd, 0x22, 0xf5, 0x7f, 0x44, 0x36, 0xfd, 0x2, 0x9b, 0xd8, 0x20, 0xe9, 0x88, 0x3e, 0x8d, 0x35, 0xeb, 0x7, 0x44, 0xd0, 0x8, 0xf9, 0xd2, 0xef, 0xf, 0x7c, 0x81, 0x73, 0xb4, 0x3, 0x43, 0x5b, 0x8, 0xe6, 0xd0, 0x43, 0x86, 0xec, 0x7, 0xd4, 0xd2, 0xe9, 0xc4, 0x3d, 0x34, 0x46, 0x7e, 0x82, 0x22, 0xeb, 0x60, 0x4b, 0xfd, 0x0, 0x43, 0x69, 0xa3, 0x23, 0x44, 0xf4, 0xb4, 0xe8, 0xf1, 0x78, 0x57, 0xd0, 0x1b, 0xb8, 0xed, 0x76, 0x6b, 0x97, 0x86, 0xb6, 0xea, 0xc, 0x4, 0x94, 0x4a, 0xc5, 0xbf, 0xd1, 0x3, 0xb8, 0x93, 0xcf, 0xb7, 0x3a, 0x42, 0x3c, 0x56, 0xc, 0x1c, 0xd0, 0xa1, 0x81, 0x59, 0x4f, 0x90, 0x30, 0x8a, 0xcd, 0x50, 0x42, 0xbb, 0x5, 0xf4, 0x3, 0x97, 0xf4, 0x9e, 0xe0, 0x45, 0x42, 0xcb, 0x37, 0xd1, 0x25, 0xea, 0xe5, 0x3f, 0x82, 0x1c, 0x9e, 0xf3, 0x28, 0xc6, 0xeb, 0x7a, 0x4f, 0x70, 0x15, 0xe3, 0x78, 0xff, 0xe7, 0x9e, 0x67, 0x4f, 0x90, 0x85, 0xa4, 0x67, 0x45, 0x35, 0x6b, 0x68, 0x1a, 0x1d, 0x22, 0x17, 0x4, 0x10, 0xa1, 0x30, 0x23, 0x78, 0x32, 0x74, 0x77, 0x85, 0xcf, 0x20, 0xae, 0x7d, 0x97, 0xa0, 0x61, 0xed, 0x5d, 0x61, 0xa6, 0x3a, 0x23, 0xce, 0xfd, 0x4e, 0x48, 0xda, 0x1, 0x7c, 0xba, 0xa5, 0x98, 0x39, 0x80, 0xe3, 0x8d, 0xaa, 0xc3, 0x13, 0x83, 0x75, 0x80, 0x37, 0x1b, 0x66, 0x86, 0x71, 0xa9, 0xb0, 0x22, 0xe3, 0x34, 0x1d, 0x64, 0xfc, 0x10, 0x62, 0xfc, 0x2e, 0xc0, 0x54, 0x27, 0xd8, 0x31, 0xc, 0xef, 0xdb, 0x12, 0x37, 0x8c, 0x1b, 0x44, 0xb9, 0xae, 0x12, 0x3c, 0xc8, 0xd4, 0x53, 0x1f, 0xdb, 0xfe, 0xab, 0xd0, 0x91, 0x46, 0x9f, 0xba, 0x26, 0x6f, 0x17, 0xf8, 0xf, 0x79, 0xe0, 0x1f, 0xd, 0x80, 0x80, 0xb4, 0xad, 0xe9, 0x2a, 0x4d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x53, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x2e, 0x2e, 0x2e, 0x46, 0x46, 0x46, 0x57, 0x57, 0x57, 0x60, 0x60, 0x60, 0x62, 0x62, 0x62, 0x5e, 0x5e, 0x5e, 0x4a, 0x4a, 0x4a, 0x12, 0x12, 0x15, 0x25, 0x27, 0x2d, 0x42, 0x42, 0x42, 0x59, 0x59, 0x59, 0x32, 0x32, 0x32, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x39, 0x39, 0x39, 0x49, 0x49, 0x49, 0x5a, 0x5a, 0x5a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0x48, 0x48, 0x48, 0x54, 0x54, 0x54, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x25, 0x26, 0x2b, 0x3f, 0x3f, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x2c, 0x2c, 0x2c, 0x58, 0x58, 0x58, 0x1a, 0x1a, 0x1e, 0x40, 0x40, 0x44, 0x56, 0x56, 0x58, 0x80, 0x80, 0x80, 0x79, 0x79, 0x79, 0x3c, 0x3c, 0x3d, 0x2e, 0x2e, 0x30, 0x27, 0x27, 0x29, 0x64, 0x64, 0x66, 0x41, 0x41, 0x41, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5d, 0x5d, 0x5f, 0x34, 0x34, 0x36, 0x52, 0x52, 0x52, 0x3a, 0x3a, 0x3a, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x32, 0x32, 0x37, 0x42, 0x42, 0x44, 0x6a, 0x6a, 0x6d, 0x5b, 0x5b, 0x5b, 0x2f, 0x2f, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x49, 0x4a, 0x0, 0x0, 0x0, 0x50, 0x50, 0x51, 0x70, 0x70, 0x74, 0xe, 0xe, 0x10, 0xb, 0xb, 0xd, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x0, 0x0, 0x0, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbd, 0xb, 0x85, 0x35, 0x0, 0x0, 0x0, 0x71, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0xff, 0x8, 0x17, 0x35, 0x73, 0xd9, 0xff, 0x7, 0x3a, 0x96, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb, 0x28, 0x76, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x77, 0xde, 0xff, 0xff, 0x45, 0x5, 0x82, 0xff, 0xff, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x37, 0xf, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x4c, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4e, 0x4f, 0xff, 0x50, 0xff, 0xff, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x49, 0x96, 0x6e, 0xf, 0x0, 0x0, 0x1, 0xfa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x18, 0x5e, 0x0, 0xd0, 0x5c, 0x39, 0x28, 0x49, 0x12, 0xc0, 0x60, 0xb8, 0xda, 0xdd, 0xcb, 0x31, 0x33, 0xb6, 0x6d, 0xdb, 0x5e, 0xdb, 0xd6, 0xfb, 0x17, 0x4e, 0x7d, 0x37, 0xe6, 0xf9, 0x2b, 0x23, 0x7f, 0x9c, 0x20, 0x28, 0x86, 0xe1, 0xb, 0xc1, 0x30, 0x14, 0x99, 0x6a, 0x8e, 0xe2, 0x4, 0x49, 0xd1, 0xcc, 0xda, 0x2, 0x18, 0x9a, 0x22, 0x9, 0x1c, 0x9d, 0xf4, 0x8e, 0xaf, 0xd3, 0x1b, 0x9b, 0x5b, 0xdb, 0x1c, 0x2e, 0x6f, 0x2e, 0x5c, 0xce, 0xf6, 0xd6, 0xe6, 0x6, 0xbd, 0x8e, 0x8f, 0x45, 0x81, 0xf2, 0x5, 0x42, 0x91, 0x58, 0x22, 0x95, 0xc9, 0x61, 0x1, 0x72, 0x99, 0x54, 0x22, 0x16, 0x9, 0x5, 0x7c, 0x74, 0xc4, 0x5e, 0xa1, 0x54, 0xa9, 0x35, 0x5a, 0x58, 0x12, 0xad, 0x46, 0xad, 0x52, 0x2a, 0x86, 0x14, 0x10, 0x1d, 0xa3, 0x37, 0x18, 0x61, 0x1e, 0x26, 0xb3, 0xc5, 0x6a, 0x63, 0xb1, 0x3b, 0x4c, 0x60, 0x34, 0xe8, 0x19, 0x1d, 0x32, 0xc8, 0x9f, 0xda, 0x74, 0xce, 0x8d, 0xdd, 0xe5, 0xf6, 0x98, 0xbd, 0x3e, 0xff, 0x57, 0x2, 0xa6, 0x60, 0x28, 0xec, 0x76, 0xc9, 0x9d, 0x9b, 0x54, 0xbf, 0xe, 0x68, 0x24, 0x1a, 0x8b, 0xcf, 0xb5, 0x4f, 0x24, 0x53, 0x30, 0x44, 0x3a, 0x99, 0x70, 0xc5, 0x33, 0xd1, 0xc8, 0x8f, 0x24, 0x70, 0xe5, 0x56, 0x16, 0xe6, 0x90, 0xcb, 0x27, 0x4d, 0x63, 0x9, 0x25, 0xf3, 0xb9, 0x6c, 0x41, 0x59, 0x64, 0x43, 0x40, 0x88, 0x8d, 0x12, 0xcc, 0xa3, 0x5c, 0x49, 0xc3, 0x18, 0x69, 0x4f, 0x19, 0x4a, 0x1b, 0x4, 0x2b, 0x80, 0x92, 0x9b, 0x55, 0xe8, 0x53, 0xab, 0x37, 0x9a, 0x2d, 0x68, 0x37, 0x3a, 0xd0, 0xee, 0x2, 0x4b, 0xcf, 0x1, 0x13, 0x38, 0x7a, 0xb0, 0xb3, 0xbb, 0xc7, 0xe6, 0x80, 0x51, 0x5b, 0x52, 0xe8, 0xd3, 0xdd, 0xaf, 0x1d, 0x34, 0x6a, 0xed, 0x46, 0x77, 0x20, 0x70, 0x78, 0x4, 0x13, 0x1c, 0x1d, 0xc2, 0x71, 0x81, 0xc2, 0x58, 0x1, 0xfa, 0x44, 0x36, 0x8, 0xa0, 0x71, 0xa, 0xb0, 0x7f, 0xd6, 0x3e, 0x6f, 0xb6, 0xfb, 0x2, 0x17, 0x97, 0x30, 0xc1, 0xe5, 0x5, 0x18, 0xaf, 0x68, 0x9c, 0x15, 0x50, 0x5e, 0xf, 0x7a, 0xd8, 0x3e, 0x7, 0x80, 0x9b, 0x7a, 0xbb, 0x7b, 0x73, 0xde, 0x17, 0xb0, 0xfa, 0x60, 0x2, 0x9f, 0x15, 0xe0, 0x56, 0xf9, 0x5d, 0x80, 0xde, 0x1e, 0xc, 0xd1, 0xe9, 0xd7, 0x8, 0xea, 0x77, 0xed, 0x2e, 0xdc, 0xd7, 0x97, 0x8e, 0x80, 0xda, 0x3a, 0x86, 0x3e, 0xe7, 0x67, 0x70, 0xda, 0x6c, 0xb5, 0xbb, 0xd0, 0x6a, 0x2c, 0x5b, 0x3, 0x94, 0xdc, 0xad, 0x42, 0x9f, 0x76, 0xf3, 0xbc, 0x59, 0x87, 0xaf, 0xe1, 0x9f, 0x2f, 0xd5, 0x5, 0x76, 0xe, 0x1e, 0x60, 0xc0, 0xe9, 0x59, 0x7, 0xa0, 0xd6, 0x2, 0xe8, 0xb4, 0xe6, 0xcf, 0xc1, 0x83, 0x90, 0x40, 0x7e, 0x79, 0x12, 0xfb, 0xbb, 0x90, 0x59, 0x7d, 0x17, 0x1e, 0xd9, 0x5d, 0xf8, 0xd5, 0x6d, 0xec, 0xdf, 0x83, 0xa7, 0xe7, 0xf8, 0x2a, 0xf7, 0x20, 0xfe, 0xfc, 0xc2, 0xde, 0x83, 0xfe, 0x45, 0x62, 0x36, 0x5f, 0xdf, 0x60, 0x69, 0xde, 0x5e, 0x37, 0x19, 0xc5, 0xe8, 0x4d, 0xd3, 0x51, 0xc2, 0x2d, 0xb1, 0xe4, 0xd8, 0x8, 0xb, 0x31, 0x1e, 0x4b, 0xc4, 0x5b, 0x42, 0x4a, 0x87, 0x8e, 0x5f, 0xe5, 0x8, 0xbd, 0xb1, 0x5b, 0xb8, 0x7a, 0xe7, 0x2d, 0xe0, 0xfd, 0xaa, 0xb0, 0xbb, 0x41, 0x47, 0x70, 0x64, 0xf2, 0xab, 0x14, 0x89, 0xbd, 0xf, 0xe5, 0xe2, 0xbf, 0xa0, 0xfc, 0xd8, 0x23, 0x8a, 0x28, 0x32, 0xe3, 0x33, 0xe1, 0x4b, 0xc0, 0x7e, 0xa6, 0xff, 0x87, 0xcf, 0xb, 0x94, 0xb9, 0x37, 0x3c, 0xc6, 0xd8, 0xcd, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tooltip_bg_png[] = { diff --git a/scene/resources/default_theme/toggle_off_disabled.png b/scene/resources/default_theme/toggle_off_disabled.png Binary files differindex d65a9d8e64..250cd29b66 100644 --- a/scene/resources/default_theme/toggle_off_disabled.png +++ b/scene/resources/default_theme/toggle_off_disabled.png diff --git a/scene/resources/default_theme/toggle_on_disabled.png b/scene/resources/default_theme/toggle_on_disabled.png Binary files differindex ca4dbe211f..b1dacbaf32 100644 --- a/scene/resources/default_theme/toggle_on_disabled.png +++ b/scene/resources/default_theme/toggle_on_disabled.png diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 8ee9879055..58fd883b0d 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -494,7 +494,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap b int byte = i * bitmap.pitch + (j >> 3); int bit = 1 << (7 - (j % 8)); wr[ofs + 0] = 255; //grayscale as 1 - wr[ofs + 1] = bitmap.buffer[byte] & bit ? 255 : 0; + wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0; } break; case FT_PIXEL_MODE_GRAY: wr[ofs + 0] = 255; //grayscale as 1 diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 627397f0ab..a29e25174d 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -133,6 +133,7 @@ PoolVector<int> BitmapFont::_get_chars() const { while ((key = char_map.next(key))) { const Character *c = char_map.getptr(*key); + ERR_FAIL_COND_V(!c, PoolVector<int>()); chars.push_back(*key); chars.push_back(c->texture_idx); chars.push_back(c->rect.position.x); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 4c4f9b5aba..d27180e9eb 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -139,7 +139,7 @@ public: static void set_default(const Ref<Theme> &p_default); static Ref<Theme> get_project_default(); - static void set_project_default(const Ref<Theme> &p_default); + static void set_project_default(const Ref<Theme> &p_project_default); static void set_default_icon(const Ref<Texture> &p_icon); static void set_default_style(const Ref<StyleBox> &p_style); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index bd5ce91e77..eed255fd6e 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -148,15 +148,20 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { } } } else if (what == "shape") - tile_set_shape(id, 0, p_value); + for (int i = 0; i < tile_get_shape_count(id); i++) + tile_set_shape(id, i, p_value); else if (what == "shape_offset") - tile_set_shape_offset(id, 0, p_value); + for (int i = 0; i < tile_get_shape_count(id); i++) + tile_set_shape_offset(id, i, p_value); else if (what == "shape_transform") - tile_set_shape_transform(id, 0, p_value); + for (int i = 0; i < tile_get_shape_count(id); i++) + tile_set_shape_transform(id, i, p_value); else if (what == "shape_one_way") - tile_set_shape_one_way(id, 0, p_value); + for (int i = 0; i < tile_get_shape_count(id); i++) + tile_set_shape_one_way(id, i, p_value); else if (what == "shape_one_way_margin") - tile_set_shape_one_way_margin(id, 0, p_value); + for (int i = 0; i < tile_get_shape_count(id); i++) + tile_set_shape_one_way_margin(id, i, p_value); else if (what == "shapes") _tile_set_shapes(id, p_value); else if (what == "occluder") diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 8475a34818..843e33f11e 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -2260,6 +2260,7 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad static Vector<String> pre_symbols; if (pre_symbols.empty()) { pre_symbols.push_back("\t"); + pre_symbols.push_back(","); pre_symbols.push_back("{"); pre_symbols.push_back("["); pre_symbols.push_back("("); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index a1a29ec950..9195d80cfc 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2399,34 +2399,38 @@ VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() { set_input_port_default_value(2, 0.0); } -////////////// Scalar Interp +////////////// Scalar Mix String VisualShaderNodeScalarInterp::get_caption() const { - return "Mix"; + return "ScalarMix"; } int VisualShaderNodeScalarInterp::get_input_port_count() const { return 3; } + VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_input_port_type(int p_port) const { return PORT_TYPE_SCALAR; } + String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const { if (p_port == 0) { return "a"; } else if (p_port == 1) { return "b"; } else { - return "c"; + return "weight"; } } int VisualShaderNodeScalarInterp::get_output_port_count() const { return 1; } + VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_output_port_type(int p_port) const { return PORT_TYPE_SCALAR; } + String VisualShaderNodeScalarInterp::get_output_port_name(int p_port) const { return "mix"; } @@ -2437,38 +2441,42 @@ String VisualShaderNodeScalarInterp::generate_code(Shader::Mode p_mode, VisualSh VisualShaderNodeScalarInterp::VisualShaderNodeScalarInterp() { set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, 0.0); + set_input_port_default_value(1, 1.0); + set_input_port_default_value(2, 0.5); } -////////////// Vector Interp +////////////// Vector Mix String VisualShaderNodeVectorInterp::get_caption() const { - return "Mix"; + return "VectorMix"; } int VisualShaderNodeVectorInterp::get_input_port_count() const { return 3; } + VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_input_port_type(int p_port) const { return PORT_TYPE_VECTOR; } + String VisualShaderNodeVectorInterp::get_input_port_name(int p_port) const { if (p_port == 0) { return "a"; } else if (p_port == 1) { return "b"; } else { - return "c"; + return "weight"; } } int VisualShaderNodeVectorInterp::get_output_port_count() const { return 1; } + VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_output_port_type(int p_port) const { return PORT_TYPE_VECTOR; } + String VisualShaderNodeVectorInterp::get_output_port_name(int p_port) const { return "mix"; } @@ -2478,9 +2486,57 @@ String VisualShaderNodeVectorInterp::generate_code(Shader::Mode p_mode, VisualSh } VisualShaderNodeVectorInterp::VisualShaderNodeVectorInterp() { - set_input_port_default_value(0, Vector3()); - set_input_port_default_value(1, Vector3()); - set_input_port_default_value(2, Vector3()); + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); + set_input_port_default_value(2, Vector3(0.5, 0.5, 0.5)); +} + +////////////// Vector Mix (by scalar) + +String VisualShaderNodeVectorScalarMix::get_caption() const { + return "VectorScalarMix"; +} + +int VisualShaderNodeVectorScalarMix::get_input_port_count() const { + return 3; +} + +VisualShaderNodeVectorScalarMix::PortType VisualShaderNodeVectorScalarMix::get_input_port_type(int p_port) const { + if (p_port == 2) + return PORT_TYPE_SCALAR; + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorScalarMix::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "a"; + } else if (p_port == 1) { + return "b"; + } else { + return "weight"; + } +} + +int VisualShaderNodeVectorScalarMix::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVectorScalarMix::PortType VisualShaderNodeVectorScalarMix::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeVectorScalarMix::get_output_port_name(int p_port) const { + return "mix"; +} + +String VisualShaderNodeVectorScalarMix::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + return "\t" + p_output_vars[0] + " = mix( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n"; +} + +VisualShaderNodeVectorScalarMix::VisualShaderNodeVectorScalarMix() { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); + set_input_port_default_value(2, 0.5); } ////////////// Vector Compose diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 4585e7fdcc..f7efa396dc 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -1171,6 +1171,27 @@ public: }; /////////////////////////////////////// + +class VisualShaderNodeVectorScalarMix : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorScalarMix, VisualShaderNode); + +public: + virtual String get_caption() const; + + virtual int get_input_port_count() const; + virtual PortType get_input_port_type(int p_port) const; + virtual String get_input_port_name(int p_port) const; + + virtual int get_output_port_count() const; + virtual PortType get_output_port_type(int p_port) const; + virtual String get_output_port_name(int p_port) const; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + + VisualShaderNodeVectorScalarMix(); +}; + +/////////////////////////////////////// /// COMPOSE /////////////////////////////////////// diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 17f5e158a7..c651c177b5 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -134,31 +134,31 @@ AudioStreamMicrophone::AudioStreamMicrophone() { void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_frames) { - AudioDriver::get_singleton()->lock(); + AudioServer::get_singleton()->lock(); - Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer(); - unsigned int input_size = AudioDriver::get_singleton()->get_input_size(); - int mix_rate = AudioDriver::get_singleton()->get_mix_rate(); - unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1); + PoolVector<int32_t> capture_buffer = AudioServer::get_singleton()->get_capture_buffer(); + unsigned int capture_size = AudioServer::get_singleton()->get_capture_size(); + int mix_rate = AudioServer::get_singleton()->get_mix_rate(); + unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, capture_buffer.size() >> 1); #ifdef DEBUG_ENABLED - unsigned int input_position = AudioDriver::get_singleton()->get_input_position(); + unsigned int capture_position = AudioServer::get_singleton()->get_capture_position(); #endif - if (playback_delay > input_size) { + if (playback_delay > capture_size) { for (int i = 0; i < p_frames; i++) { p_buffer[i] = AudioFrame(0.0f, 0.0f); } - input_ofs = 0; + capture_ofs = 0; } else { for (int i = 0; i < p_frames; i++) { - if (input_size > input_ofs && (int)input_ofs < buf.size()) { - float l = (buf[input_ofs++] >> 16) / 32768.f; - if ((int)input_ofs >= buf.size()) { - input_ofs = 0; + if (capture_size > capture_ofs && (int)capture_ofs < capture_buffer.size()) { + float l = (capture_buffer[capture_ofs++] >> 16) / 32768.f; + if ((int)capture_ofs >= capture_buffer.size()) { + capture_ofs = 0; } - float r = (buf[input_ofs++] >> 16) / 32768.f; - if ((int)input_ofs >= buf.size()) { - input_ofs = 0; + float r = (capture_buffer[capture_ofs++] >> 16) / 32768.f; + if ((int)capture_ofs >= capture_buffer.size()) { + capture_ofs = 0; } p_buffer[i] = AudioFrame(l, r); @@ -169,12 +169,12 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr } #ifdef DEBUG_ENABLED - if (input_ofs > input_position && (int)(input_ofs - input_position) < (p_frames * 2)) { - print_verbose(String(get_class_name()) + " buffer underrun: input_position=" + itos(input_position) + " input_ofs=" + itos(input_ofs) + " input_size=" + itos(input_size)); + if (capture_ofs > capture_position && (int)(capture_ofs - capture_position) < (p_frames * 2)) { + print_verbose(String(get_class_name()) + " buffer underrun: capture_position=" + itos(capture_position) + " capture_ofs=" + itos(capture_ofs) + " capture_size=" + itos(capture_size)); } #endif - AudioDriver::get_singleton()->unlock(); + AudioServer::get_singleton()->unlock(); } void AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { @@ -196,9 +196,9 @@ void AudioStreamPlaybackMicrophone::start(float p_from_pos) { return; } - input_ofs = 0; + capture_ofs = 0; - if (AudioDriver::get_singleton()->capture_start() == OK) { + if (AudioServer::get_singleton()->capture_start() == OK) { active = true; _begin_resample(); } @@ -206,7 +206,7 @@ void AudioStreamPlaybackMicrophone::start(float p_from_pos) { void AudioStreamPlaybackMicrophone::stop() { if (active) { - AudioDriver::get_singleton()->capture_stop(); + AudioServer::get_singleton()->capture_stop(); active = false; } } diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index ef9f8ea92a..4548f8f036 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -123,7 +123,7 @@ class AudioStreamPlaybackMicrophone : public AudioStreamPlaybackResampled { friend class AudioStreamMicrophone; bool active; - unsigned int input_ofs; + unsigned int capture_ofs; Ref<AudioStreamMicrophone> microphone; diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index a6473d69c0..2cf6a67bef 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -85,26 +85,26 @@ double AudioDriver::get_time_to_next_mix() const { return mix_buffer - total; } -void AudioDriver::input_buffer_init(int driver_buffer_frames) { +void AudioDriver::capture_buffer_init(int driver_buffer_frames) { - const int input_buffer_channels = 2; - input_buffer.resize(driver_buffer_frames * input_buffer_channels * 4); - input_position = 0; - input_size = 0; + const int capture_buffer_channels = 2; + capture_buffer.resize(driver_buffer_frames * capture_buffer_channels * 4); + capture_position = 0; + capture_size = 0; } -void AudioDriver::input_buffer_write(int32_t sample) { +void AudioDriver::capture_buffer_write(int32_t sample) { - if ((int)input_position < input_buffer.size()) { - input_buffer.write[input_position++] = sample; - if ((int)input_position >= input_buffer.size()) { - input_position = 0; + if ((int)capture_position < capture_buffer.size()) { + capture_buffer.write()[capture_position++] = sample; + if ((int)capture_position >= capture_buffer.size()) { + capture_position = 0; } - if ((int)input_size < input_buffer.size()) { - input_size++; + if ((int)capture_size < capture_buffer.size()) { + capture_size++; } } else { - WARN_PRINTS("input_buffer_write: Invalid input_position=" + itos(input_position) + " input_buffer.size()=" + itos(input_buffer.size())); + WARN_PRINTS("capture_buffer_write: Invalid capture_position=" + itos(capture_position) + " capture_buffer.size()=" + itos(capture_buffer.size())); } } @@ -154,8 +154,8 @@ AudioDriver::AudioDriver() { _last_mix_time = 0; _last_mix_frames = 0; - input_position = 0; - input_size = 0; + capture_position = 0; + capture_size = 0; #ifdef DEBUG_ENABLED prof_time = 0; @@ -338,6 +338,8 @@ void AudioServer::_mix_step() { E->get().callback(E->get().userdata); } + emit_signal("audio_mix_callback"); + for (int i = buses.size() - 1; i >= 0; i--) { //go bus by bus Bus *bus = buses[i]; @@ -1057,6 +1059,8 @@ void AudioServer::update() { E->get().callback(E->get().userdata); } + + emit_signal("audio_update_callback"); } void AudioServer::load_default_bus_layout() { @@ -1302,6 +1306,14 @@ void AudioServer::set_device(String device) { AudioDriver::get_singleton()->set_device(device); } +Error AudioServer::capture_start() { + return AudioDriver::get_singleton()->capture_start(); +} + +Error AudioServer::capture_stop() { + return AudioDriver::get_singleton()->capture_stop(); +} + Array AudioServer::capture_get_device_list() { return AudioDriver::get_singleton()->capture_get_device_list(); @@ -1317,6 +1329,18 @@ void AudioServer::capture_set_device(const String &p_name) { AudioDriver::get_singleton()->capture_set_device(p_name); } +PoolVector<int32_t> AudioServer::get_capture_buffer() { + return AudioDriver::get_singleton()->get_capture_buffer(); +} + +unsigned int AudioServer::get_capture_position() { + return AudioDriver::get_singleton()->get_capture_position(); +} + +unsigned int AudioServer::get_capture_size() { + return AudioDriver::get_singleton()->get_capture_size(); +} + void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bus_count", "amount"), &AudioServer::set_bus_count); @@ -1377,18 +1401,28 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_time_since_last_mix"), &AudioServer::get_time_since_last_mix); ClassDB::bind_method(D_METHOD("get_output_latency"), &AudioServer::get_output_latency); + ClassDB::bind_method(D_METHOD("capture_start"), &AudioServer::capture_start); + ClassDB::bind_method(D_METHOD("capture_stop"), &AudioServer::capture_stop); + ClassDB::bind_method(D_METHOD("capture_get_device_list"), &AudioServer::capture_get_device_list); ClassDB::bind_method(D_METHOD("capture_get_device"), &AudioServer::capture_get_device); ClassDB::bind_method(D_METHOD("capture_set_device", "name"), &AudioServer::capture_set_device); + ClassDB::bind_method(D_METHOD("get_capture_buffer"), &AudioServer::get_capture_buffer); + ClassDB::bind_method(D_METHOD("get_capture_position"), &AudioServer::get_capture_position); + ClassDB::bind_method(D_METHOD("get_capture_size"), &AudioServer::get_capture_size); + ClassDB::bind_method(D_METHOD("set_bus_layout", "bus_layout"), &AudioServer::set_bus_layout); ClassDB::bind_method(D_METHOD("generate_bus_layout"), &AudioServer::generate_bus_layout); ADD_PROPERTY(PropertyInfo(Variant::INT, "bus_count"), "set_bus_count", "get_bus_count"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "device"), "set_device", "get_device"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "capture_device"), "capture_set_device", "capture_get_device"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_rate_scale"), "set_global_rate_scale", "get_global_rate_scale"); ADD_SIGNAL(MethodInfo("bus_layout_changed")); + ADD_SIGNAL(MethodInfo("audio_mix_callback")); + ADD_SIGNAL(MethodInfo("audio_update_callback")); BIND_ENUM_CONSTANT(SPEAKER_MODE_STEREO); BIND_ENUM_CONSTANT(SPEAKER_SURROUND_31); diff --git a/servers/audio_server.h b/servers/audio_server.h index b0fff9d4b7..72bb6faf42 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -53,14 +53,14 @@ class AudioDriver { #endif protected: - Vector<int32_t> input_buffer; - unsigned int input_position; - unsigned int input_size; + PoolVector<int32_t> capture_buffer; + unsigned int capture_position; + unsigned int capture_size; void audio_server_process(int p_frames, int32_t *p_buffer, bool p_update_mix_time = true); void update_mix_time(int p_frames); - void input_buffer_init(int driver_buffer_frames); - void input_buffer_write(int32_t sample); + void capture_buffer_init(int driver_buffer_frames); + void capture_buffer_write(int32_t sample); #ifdef DEBUG_ENABLED _FORCE_INLINE_ void start_counting_ticks() { prof_ticks = OS::get_singleton()->get_ticks_usec(); } @@ -111,9 +111,9 @@ public: SpeakerMode get_speaker_mode_by_total_channels(int p_channels) const; int get_total_channels_by_speaker_mode(SpeakerMode) const; - Vector<int32_t> get_input_buffer() { return input_buffer; } - unsigned int get_input_position() { return input_position; } - unsigned int get_input_size() { return input_size; } + PoolVector<int32_t> get_capture_buffer() { return capture_buffer; } + unsigned int get_capture_position() { return capture_position; } + unsigned int get_capture_size() { return capture_size; } #ifdef DEBUG_ENABLED uint64_t get_profiling_time() const { return prof_time; } @@ -384,10 +384,17 @@ public: String get_device(); void set_device(String device); + Error capture_start(); + Error capture_stop(); + Array capture_get_device_list(); String capture_get_device(); void capture_set_device(const String &p_name); + PoolVector<int32_t> get_capture_buffer(); + unsigned int get_capture_position(); + unsigned int get_capture_size(); + AudioServer(); virtual ~AudioServer(); }; diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp index f3a4cbed24..410b6e59a0 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -348,11 +348,9 @@ bool PhysicsDirectSpaceStateSW::collide_shape(RID p_shape, const Transform &p_sh cbk.max = p_result_max; cbk.amount = 0; cbk.ptr = r_results; - CollisionSolverSW::CallbackResult cbkres = NULL; + CollisionSolverSW::CallbackResult cbkres = PhysicsServerSW::_shape_col_cbk; - PhysicsServerSW::CollCbkData *cbkptr = NULL; - cbkptr = &cbk; - cbkres = PhysicsServerSW::_shape_col_cbk; + PhysicsServerSW::CollCbkData *cbkptr = &cbk; for (int i = 0; i < amount; i++) { diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index 5dff655ea1..b9ebd30021 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -608,7 +608,7 @@ void Body2DSW::call_queries() { set_force_integration_callback(0, StringName()); } else { Variant::CallError ce; - if (fi_callback->callback_udata.get_type()) { + if (fi_callback->callback_udata.get_type() != Variant::NIL) { obj->call(fi_callback->method, vp, 2, ce); diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 7c89c43f36..2778775446 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -330,11 +330,9 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D & cbk.amount = 0; cbk.passed = 0; cbk.ptr = r_results; - CollisionSolver2DSW::CallbackResult cbkres = NULL; + CollisionSolver2DSW::CallbackResult cbkres = Physics2DServerSW::_shape_col_cbk; - Physics2DServerSW::CollCbkData *cbkptr = NULL; - cbkptr = &cbk; - cbkres = Physics2DServerSW::_shape_col_cbk; + Physics2DServerSW::CollCbkData *cbkptr = &cbk; for (int i = 0; i < amount; i++) { diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 25973aa295..5c28705192 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -860,7 +860,7 @@ void ShaderLanguage::clear() { } } -bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, int *r_array_size) { +bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size) { if (p_builtin_types.has(p_identifier)) { @@ -882,6 +882,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String if (r_data_type) { *r_data_type = p_block->variables[p_identifier].type; } + if (r_is_const) { + *r_is_const = p_block->variables[p_identifier].is_const; + } if (r_array_size) { *r_array_size = p_block->variables[p_identifier].array_size; } @@ -2735,7 +2738,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI return false; } - if (shader->constants.has(var->name)) { + if (shader->constants.has(var->name) || var->is_const) { if (r_message) *r_message = RTR("Constants cannot be modified."); return false; @@ -2745,6 +2748,15 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI return true; } } else if (p_node->type == Node::TYPE_ARRAY) { + + ArrayNode *arr = static_cast<ArrayNode *>(p_node); + + if (arr->is_const) { + if (r_message) + *r_message = RTR("Constants cannot be modified."); + return false; + } + return true; } @@ -2931,9 +2943,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons DataType data_type; IdentifierType ident_type; + bool is_const = false; int array_size = 0; - if (!_find_identifier(p_block, p_builtin_types, identifier, &data_type, &ident_type, &array_size)) { + if (!_find_identifier(p_block, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size)) { _set_error("Unknown identifier in expression: " + String(identifier)); return NULL; } @@ -2996,6 +3009,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons arrname->datatype_cache = data_type; arrname->index_expression = index_expression; arrname->call_expression = call_expression; + arrname->is_const = is_const; expr = arrname; } else { @@ -3003,6 +3017,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons VariableNode *varname = alloc_node<VariableNode>(); varname->name = identifier; varname->datatype_cache = data_type; + varname->is_const = is_const; expr = varname; } } @@ -3770,7 +3785,15 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui return OK; - } else if (is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type)) { + } else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type)) { + + bool is_const = false; + + if (tk.type == TK_CONST) { + is_const = true; + tk = _get_token(); + } + DataPrecision precision = PRECISION_DEFAULT; if (is_token_precision(tk.type)) { precision = get_token_precision(tk.type); @@ -3810,6 +3833,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui var.precision = precision; var.line = tk_line; var.array_size = 0; + var.is_const = is_const; tk = _get_token(); @@ -3819,6 +3843,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>(); node->datatype = type; node->precision = precision; + node->is_const = is_const; vardecl = (Node *)node; ArrayDeclarationNode::Declaration decl; @@ -4004,6 +4029,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>(); node->datatype = type; node->precision = precision; + node->is_const = is_const; vardecl = (Node *)node; VariableDeclarationNode::Declaration decl; diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 8253bce468..36c691c3ae 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -330,15 +330,18 @@ public: DataType datatype_cache; StringName name; virtual DataType get_datatype() const { return datatype_cache; } + bool is_const; VariableNode() : Node(TYPE_VARIABLE), - datatype_cache(TYPE_VOID) {} + datatype_cache(TYPE_VOID), + is_const(false) {} }; struct VariableDeclarationNode : public Node { DataPrecision precision; DataType datatype; + bool is_const; struct Declaration { StringName name; @@ -351,7 +354,8 @@ public: VariableDeclarationNode() : Node(TYPE_VARIABLE_DECLARATION), precision(PRECISION_DEFAULT), - datatype(TYPE_VOID) {} + datatype(TYPE_VOID), + is_const(false) {} }; struct ArrayNode : public Node { @@ -359,6 +363,7 @@ public: StringName name; Node *index_expression; Node *call_expression; + bool is_const; virtual DataType get_datatype() const { return datatype_cache; } @@ -366,12 +371,14 @@ public: Node(TYPE_ARRAY), datatype_cache(TYPE_VOID), index_expression(NULL), - call_expression(NULL) {} + call_expression(NULL), + is_const(false) {} }; struct ArrayDeclarationNode : public Node { DataPrecision precision; DataType datatype; + bool is_const; struct Declaration { StringName name; @@ -385,7 +392,8 @@ public: ArrayDeclarationNode() : Node(TYPE_ARRAY_DECLARATION), precision(PRECISION_DEFAULT), - datatype(TYPE_VOID) {} + datatype(TYPE_VOID), + is_const(false) {} }; struct ConstantNode : public Node { @@ -417,6 +425,7 @@ public: DataPrecision precision; int line; //for completion int array_size; + bool is_const; }; Map<StringName, Variable> variables; @@ -683,7 +692,7 @@ private: IDENTIFIER_CONSTANT, }; - bool _find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = NULL, IdentifierType *r_type = NULL, int *r_array_size = NULL); + bool _find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = NULL, IdentifierType *r_type = NULL, bool *r_is_const = NULL, int *r_array_size = NULL); bool _is_operator_assign(Operator p_op) const; bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = NULL); bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = NULL); diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 86c5227f30..0863d5c2e3 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -85,6 +85,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E if (!p_viewport->hide_canvas && !p_viewport->disable_environment && VSG::scene->scenario_owner.owns(p_viewport->scenario)) { VisualServerScene::Scenario *scenario = VSG::scene->scenario_owner.get(p_viewport->scenario); + ERR_FAIL_COND(!scenario); if (VSG::scene_render->is_environment(scenario->environment)) { scenario_draw_canvas_bg = VSG::scene_render->environment_get_background(scenario->environment) == VS::ENV_BG_CANVAS; |