summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/BakedLightmap.xml15
-rw-r--r--doc/classes/ColorPicker.xml10
-rw-r--r--doc/classes/ColorPickerButton.xml6
-rw-r--r--doc/classes/ColorRect.xml8
-rw-r--r--doc/classes/Control.xml63
-rw-r--r--doc/classes/DirectionalLight.xml18
-rw-r--r--doc/classes/InputEventKey.xml1
-rw-r--r--doc/classes/InputMap.xml5
-rw-r--r--doc/classes/ItemList.xml18
-rw-r--r--doc/classes/KinematicBody2D.xml3
-rw-r--r--doc/classes/Light.xml15
-rw-r--r--doc/classes/OmniLight.xml8
-rw-r--r--doc/classes/ProgressBar.xml1
-rw-r--r--doc/classes/Range.xml16
-rw-r--r--doc/classes/TileSet.xml54
-rw-r--r--doc/classes/Viewport.xml34
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp947
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.h46
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp11
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h4
-rw-r--r--drivers/gles2/shader_gles2.cpp14
-rw-r--r--drivers/gles2/shader_gles2.h1
-rw-r--r--drivers/gles2/shaders/canvas.glsl33
-rw-r--r--editor/editor_help.cpp8
-rw-r--r--editor/editor_properties.cpp16
-rw-r--r--editor/editor_properties.h1
-rw-r--r--editor/editor_properties_array_dict.cpp12
-rw-r--r--editor/editor_properties_array_dict.h4
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--editor/editor_themes.cpp12
-rw-r--r--editor/find_in_files.cpp257
-rw-r--r--editor/find_in_files.h24
-rw-r--r--editor/import/resource_importer_texture.cpp15
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp6
-rw-r--r--editor/plugins/curve_editor_plugin.cpp4
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp15
-rw-r--r--editor/plugins/spatial_editor_plugin.h1
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp2
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp7
-rw-r--r--editor/project_export.cpp9
-rw-r--r--modules/bullet/godot_result_callbacks.cpp4
-rw-r--r--modules/gdscript/gdscript_editor.cpp2
-rw-r--r--modules/mono/SCsub25
-rw-r--r--modules/mono/editor/bindings_generator.cpp9
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp2
-rwxr-xr-xmodules/mono/glue/cs_files/VERSION.txt1
-rw-r--r--platform/android/detect.py2
-rw-r--r--platform/windows/detect.py6
-rw-r--r--platform/windows/os_windows.cpp7
-rw-r--r--platform/x11/os_x11.cpp17
-rw-r--r--scene/animation/skeleton_ik.cpp4
-rw-r--r--scene/animation/skeleton_ik.h4
-rw-r--r--scene/gui/item_list.cpp3
-rw-r--r--scene/gui/popup_menu.cpp19
-rw-r--r--scene/register_scene_types.cpp6
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/physics_material.h2
-rw-r--r--servers/visual/shader_language.cpp4
58 files changed, 1144 insertions, 701 deletions
diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/BakedLightmap.xml
index 77895249e5..966b6dd7c4 100644
--- a/doc/classes/BakedLightmap.xml
+++ b/doc/classes/BakedLightmap.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="BakedLightmap" inherits="VisualInstance" category="Core" version="3.1">
<brief_description>
+ Prerendered indirect light map for a scene.
</brief_description>
<description>
+ Baked lightmaps are an alternative workflow for adding indirect (or baked) lighting to a scene. Unlike the [GIProbe] approach, baked lightmaps work fine on low-end PCs and mobile devices as they consume almost no resources in run-time.
</description>
<tutorials>
<link>http://docs.godotengine.org/en/3.0/tutorials/3d/baked_lightmaps.html</link>
@@ -29,36 +31,49 @@
</methods>
<members>
<member name="bake_cell_size" type="float" setter="set_bake_cell_size" getter="get_bake_cell_size">
+ Grid subdivision size for lightmapper calculation. Default value of [code]0.25[/code] will work for most cases. Increase for better lighting on small details or if your scene is very large.
</member>
<member name="bake_energy" type="float" setter="set_energy" getter="get_energy">
</member>
<member name="bake_extents" type="Vector3" setter="set_extents" getter="get_extents">
+ Size of affected area.
</member>
<member name="bake_hdr" type="bool" setter="set_hdr" getter="is_hdr">
+ If [code]true[/code] lightmap can capture light values greater than [code]1.0[/code]. Turning this off will result in a smaller lightmap. Default value:[code]false[/code].
</member>
<member name="bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="BakedLightmap.BakeMode">
+ Lightmapping mode. See [enum BakeMode].
</member>
<member name="bake_propagation" type="float" setter="set_propagation" getter="get_propagation">
</member>
<member name="bake_quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="BakedLightmap.BakeQuality">
+ Three quality modes are available. Higher quality requires more rendering time. See [enum BakeQuality].
</member>
<member name="capture_cell_size" type="float" setter="set_capture_cell_size" getter="get_capture_cell_size">
+ Grid size used for real-time capture information on dynamic objects. Cannot be larger than [member bake_cell_size].
</member>
<member name="image_path" type="String" setter="set_image_path" getter="get_image_path">
+ Location where lightmaps will be saved.
</member>
<member name="light_data" type="BakedLightmapData" setter="set_light_data" getter="get_light_data">
+ The calculated light data.
</member>
</members>
<constants>
<constant name="BAKE_QUALITY_LOW" value="0" enum="BakeQuality">
+ Lowest bake quality mode. Fastest to calculate.
</constant>
<constant name="BAKE_QUALITY_MEDIUM" value="1" enum="BakeQuality">
+ Default bake quality mode.
</constant>
<constant name="BAKE_QUALITY_HIGH" value="2" enum="BakeQuality">
+ Highest bake quality mode. Takes longer to calculate.
</constant>
<constant name="BAKE_MODE_CONE_TRACE" value="0" enum="BakeMode">
+ Less precise but faster bake mode.
</constant>
<constant name="BAKE_MODE_RAY_TRACE" value="1" enum="BakeMode">
+ More precise bake mode but can take considerably longer to bake.
</constant>
<constant name="BAKE_ERROR_OK" value="0" enum="BakeError">
</constant>
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index 232357f822..4d52eacba8 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -4,7 +4,7 @@
Color picker control.
</brief_description>
<description>
- This is a simple color picker [Control]. It's useful for selecting a color from an RGB/RGBA colorspace.
+ [Control] node displaying a color picker widget. It's useful for selecting a color from an RGB/RGBA colorspace.
</description>
<tutorials>
</tutorials>
@@ -17,7 +17,7 @@
<argument index="0" name="color" type="Color">
</argument>
<description>
- Adds the current selected to color to a list of colors (presets), the presets will be displayed in the color picker and the user will be able to select them, notice that the presets list is only for this color picker.
+ Adds the given color to a list of color presets. The presets are displayed in the color picker and the user will be able to select them. Note: the presets list is only for [i]this[/i] color picker.
</description>
</method>
</methods>
@@ -26,13 +26,13 @@
The currently selected color.
</member>
<member name="deferred_mode" type="bool" setter="set_deferred_mode" getter="is_deferred_mode">
- If [code]true[/code], the color will apply only after user releases mouse button, otherwise it will apply immediatly even in mouse motion event (which can cause performance issues).
+ If [code]true[/code] the color will apply only after the user releases the mouse button, otherwise it will apply immediatly even in mouse motion event (which can cause performance issues).
</member>
<member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha">
- If [code]true[/code], shows an alpha channel slider (transparency).
+ If [code]true[/code] shows an alpha channel slider (transparency).
</member>
<member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode">
- If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR).
+ If [code]true[/code] allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR).
</member>
</members>
<signals>
diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml
index d049e936a8..6ac2911c11 100644
--- a/doc/classes/ColorPickerButton.xml
+++ b/doc/classes/ColorPickerButton.xml
@@ -4,7 +4,7 @@
Button that pops out a [ColorPicker].
</brief_description>
<description>
- Encapsulates a [ColorPicker] making it accesible by pressing a button, pressing the button will toggle the [ColorPicker] visibility
+ Encapsulates a [ColorPicker] making it accesible by pressing a button. Pressing the button will toggle the [ColorPicker] visibility.
</description>
<tutorials>
</tutorials>
@@ -15,14 +15,14 @@
<return type="ColorPicker">
</return>
<description>
- Returns the [code]ColorPicker[/code] that this [code]ColorPickerButton[/code] toggles.
+ Returns the [ColorPicker] that this node toggles.
</description>
</method>
<method name="get_popup">
<return type="PopupPanel">
</return>
<description>
- Returns the control's [PopupPanel] which allows you to connect to Popup Signals. This allows you to handle events when the ColorPicker is shown or hidden.
+ Returns the control's [PopupPanel] which allows you to connect to popup signals. This allows you to handle events when the ColorPicker is shown or hidden.
</description>
</method>
</methods>
diff --git a/doc/classes/ColorRect.xml b/doc/classes/ColorRect.xml
index 69a70cfa39..e1bffb719e 100644
--- a/doc/classes/ColorRect.xml
+++ b/doc/classes/ColorRect.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ColorRect" inherits="Control" category="Core" version="3.1">
<brief_description>
- Colored rect for canvas.
+ Colored rectangle.
</brief_description>
<description>
- An object that is represented on the canvas as a rect with color. [Color] is used to set or get color info for the rect.
+ Displays a colored rectangle.
</description>
<tutorials>
</tutorials>
@@ -14,9 +14,9 @@
</methods>
<members>
<member name="color" type="Color" setter="set_frame_color" getter="get_frame_color">
- The color to fill the [code]ColorRect[/code].
+ The fill color.
[codeblock]
- $ColorRect.color = Color(1, 0, 0, 1) # Set ColorRect node's color to red
+ $ColorRect.color = Color(1, 0, 0, 1) # Set ColorRect's color to red.
[/codeblock]
</member>
</members>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index d11b369e68..2efb529f31 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Control" inherits="CanvasItem" category="Core" version="3.1">
<brief_description>
- All User Interface nodes inherit from Control. Features anchors and margins to adapt its position and size to its parent.
+ All User Interface nodes inherit from Control. A control's anchors and margins adapt its position and size relative to its parent.
</brief_description>
<description>
Base class for all User Interface or [i]UI[/i] related nodes. [code]Control[/code] features a bounding rectangle that defines its extents, an anchor position relative to its parent and margins that represent an offset to the anchor. The margins update automatically when the node, any of its parents, or the screen size change.
@@ -23,7 +23,7 @@
<return type="Vector2">
</return>
<description>
- Returns the minimum size this Control can shrink to. The node can never be smaller than this minimum size.
+ Returns the minimum size for this control. See [member rect_min_size].
</description>
</method>
<method name="_gui_input" qualifiers="virtual">
@@ -129,7 +129,7 @@
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
@@ -148,10 +148,10 @@
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')
-
+
func drop_data(position, data):
color = data['color']
[/codeblock]
@@ -173,6 +173,7 @@
<return type="Vector2">
</return>
<description>
+ Returns [member margin_left] and [member margin_top]. See also [member rect_position].
</description>
</method>
<method name="get_color" qualifiers="const">
@@ -207,7 +208,7 @@
<argument index="0" name="position" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
- Returns the mouse cursor shape the control displays on mouse hover, one of the [code]CURSOR_*[/code] constants.
+ Returns the mouse cursor shape the control displays on mouse hover. See [enum CursorShape].
</description>
</method>
<method name="get_drag_data" qualifiers="virtual">
@@ -220,7 +221,7 @@
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))
@@ -232,14 +233,14 @@
<return type="Vector2">
</return>
<description>
- Returns MARGIN_LEFT and MARGIN_TOP at the same time. This is a helper (see [method set_margin]).
+ Returns [member margin_right] and [member margin_bottom].
</description>
</method>
<method name="get_focus_owner" qualifiers="const">
<return type="Control">
</return>
<description>
- Return which control is owning the keyboard focus, or null if no one.
+ Returns the control that has the keyboard focus or [code]null[/code] if none.
</description>
</method>
<method name="get_font" qualifiers="const">
@@ -256,7 +257,7 @@
<return type="Rect2">
</return>
<description>
- Return position and size of the Control, relative to the top-left corner of the [i]window[/i] Control. This is a helper (see [method get_global_position], [method get_size]).
+ Returns the position and size of the control relative to the top-left corner of the screen. See [member rect_position] and [member rect_size].
</description>
</method>
<method name="get_icon" qualifiers="const">
@@ -273,33 +274,35 @@
<return type="Vector2">
</return>
<description>
- Return the minimum size this Control can shrink to. A control will never be displayed or resized smaller than its minimum size.
+ Returns the minimum size for this control. See [member rect_min_size].
</description>
</method>
<method name="get_parent_area_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
+ Returns the width/height occupied in the parent control.
</description>
</method>
<method name="get_parent_control" qualifiers="const">
<return type="Control">
</return>
<description>
+ Returns the parent control node.
</description>
</method>
<method name="get_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
- Return position and size of the Control, relative to the top-left corner of the parent Control. This is a helper (see [method get_position], [method get_size]).
+ Returns the position and size of the control relative to the top-left corner of the parent Control. See [member rect_position] and [member rect_size].
</description>
</method>
<method name="get_rotation" qualifiers="const">
<return type="float">
</return>
<description>
- Return the rotation (in radians)
+ Returns the rotation (in radians).
</description>
</method>
<method name="get_stylebox" qualifiers="const">
@@ -318,7 +321,7 @@
<argument index="0" name="at_position" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
- Return 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.
</description>
</method>
<method name="grab_click_focus">
@@ -374,7 +377,7 @@
<return type="bool">
</return>
<description>
- Return whether the Control is the current focused control (see [method set_focus_mode]).
+ Returns [code]true[/code] if this is the current focused control. See [member focus_mode].
</description>
</method>
<method name="has_font" qualifiers="const">
@@ -457,7 +460,7 @@
<return type="void">
</return>
<description>
- Give up the focus, no other control will be able to receive keyboard input.
+ Give up the focus. No other control will be able to receive keyboard input.
</description>
</method>
<method name="set_anchor">
@@ -516,7 +519,7 @@
<argument index="0" name="position" type="Vector2">
</argument>
<description>
- Sets MARGIN_LEFT and MARGIN_TOP at the same time. This is a helper (see [method set_margin]).
+ Sets [member margin_left] and [member margin_top] at the same time.
</description>
</method>
<method name="set_drag_forwarding">
@@ -534,15 +537,15 @@
extends Control
func _ready():
set_drag_forwarding(target_control)
-
+
# TargetControl.gd
extends Control
func can_drop_data_fw(position, data, from_control):
return true
-
+
func drop_data_fw(position, data, from_control):
my_handle_data(data)
-
+
func get_drag_data_fw(position, from_control):
set_drag_preview(my_preview)
return my_data()
@@ -564,7 +567,7 @@
<argument index="0" name="position" type="Vector2">
</argument>
<description>
- Sets MARGIN_RIGHT and MARGIN_BOTTOM at the same time. This is a helper (see [method set_margin]).
+ Sets [member margin_right] and [member margin_bottom] at the same time.
</description>
</method>
<method name="set_margins_preset">
@@ -585,7 +588,7 @@
<argument index="0" name="radians" type="float">
</argument>
<description>
- Set the rotation (in radians).
+ Sets the rotation (in radians).
</description>
</method>
<method name="show_modal">
@@ -594,7 +597,7 @@
<argument index="0" name="exclusive" type="bool" default="false">
</argument>
<description>
- Display 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.
+ 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.
</description>
</method>
<method name="warp_mouse">
@@ -753,22 +756,22 @@
</signals>
<constants>
<constant name="FOCUS_NONE" value="0" enum="FocusMode">
- The node cannot grab focus. Use with [member set_focus_mode].
+ The node cannot grab focus. Use with [member focus_mode].
</constant>
<constant name="FOCUS_CLICK" value="1" enum="FocusMode">
- The node can only grab focus on mouse clicks. Use with [member set_focus_mode].
+ The node can only grab focus on mouse clicks. Use with [member focus_mode].
</constant>
<constant name="FOCUS_ALL" value="2" enum="FocusMode">
- The node can grab focus on mouse click or using the arrows and the Tab keys on the keyboard. Use with [member set_focus_mode].
+ The node can grab focus on mouse click or using the arrows and the Tab keys on the keyboard. Use with [member focus_mode].
</constant>
<constant name="NOTIFICATION_RESIZED" value="40">
Sent when the node changes size. Use [member rect_size] to get the new size.
</constant>
<constant name="NOTIFICATION_MOUSE_ENTER" value="41">
- Sent when the mouse pointer enters the node's [code]Rect[/code] area.
+ Sent when the mouse pointer enters the node.
</constant>
<constant name="NOTIFICATION_MOUSE_EXIT" value="42">
- Sent when the mouse pointer exits the node's [code]Rect[/code] area.
+ Sent when the mouse pointer exits the node.
</constant>
<constant name="NOTIFICATION_FOCUS_ENTER" value="43">
Sent when the node grabs focus.
@@ -777,7 +780,7 @@
Sent when the node loses focus.
</constant>
<constant name="NOTIFICATION_THEME_CHANGED" value="45">
- Sent when the node's [member theme] changes, right before Godot redraws the [code]Control[/code]. Happens when you call one of the [code]add_*_override[/code]
+ Sent when the node's [member theme] changes, right before Godot redraws the control. Happens when you call one of the [code]add_*_override[/code]
</constant>
<constant name="NOTIFICATION_MODAL_CLOSE" value="46">
Sent when an open modal dialog closes. See [member show_modal].
@@ -903,7 +906,7 @@
Sets the node's size flags to both fill and expand. See the 2 constants above for more information.
</constant>
<constant name="SIZE_SHRINK_CENTER" value="4" enum="SizeFlags">
- Tells the parent [Container] to center the node in itself. It centers the [code]Control[/code] based on its bounding box, so it doesn't work with the fill or expand size flags. Use with [member size_flags_horizontal] and [member size_flags_vertical].
+ Tells the parent [Container] to center the node in itself. It centers the control based on its bounding box, so it doesn't work with the fill or expand size flags. Use with [member size_flags_horizontal] and [member size_flags_vertical].
</constant>
<constant name="SIZE_SHRINK_END" value="8" enum="SizeFlags">
Tells the parent [Container] to align the node with its end, either the bottom or the right edge. It doesn't work with the fill or expand size flags. Use with [member size_flags_horizontal] and [member size_flags_vertical].
diff --git a/doc/classes/DirectionalLight.xml b/doc/classes/DirectionalLight.xml
index ef75182811..2dc522083d 100644
--- a/doc/classes/DirectionalLight.xml
+++ b/doc/classes/DirectionalLight.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="DirectionalLight" inherits="Light" category="Core" version="3.1">
<brief_description>
- Directional Light, such as the Sun or the Moon.
+ Directional light from a distance, as from the Sun.
</brief_description>
<description>
- A DirectionalLight is a type of [Light] node that emits light constantly in one direction (the negative z axis of the node). It is used lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldspace location of the DirectionalLight transform (origin) is ignored, only the basis is used do determine light direction.
+ A directional light is a type of [Light] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldspace location of the DirectionalLight transform (origin) is ignored. Only the basis is used do determine light direction.
</description>
<tutorials>
<link>http://docs.godotengine.org/en/3.0/tutorials/3d/lights_and_shadows.html</link>
@@ -15,34 +15,48 @@
</methods>
<members>
<member name="directional_shadow_bias_split_scale" type="float" setter="set_param" getter="get_param">
+ Amount of extra bias for shadow splits that are far away. If self shadowing occurs only on the splits far away, this value can fix them.
</member>
<member name="directional_shadow_blend_splits" type="bool" setter="set_blend_splits" getter="is_blend_splits_enabled">
+ If [code]true[/code] shadow detail is sacrificed in exchange for smoother transitions between splits. Default value:[code]false[/code].
</member>
<member name="directional_shadow_depth_range" type="int" setter="set_shadow_depth_range" getter="get_shadow_depth_range" enum="DirectionalLight.ShadowDepthRange">
+ Optimizes shadow rendering for detail versus movement. See [enum ShadowDepthRange].
</member>
<member name="directional_shadow_max_distance" type="float" setter="set_param" getter="get_param">
+ The maximum distance for shadow splits.
</member>
<member name="directional_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="DirectionalLight.ShadowMode">
+ The light's shadow rendering algorithm. See [enum ShadowMode].
</member>
<member name="directional_shadow_normal_bias" type="float" setter="set_param" getter="get_param">
+ Can be used to fix special cases of self shadowing when objects are perpendicular to the light.
</member>
<member name="directional_shadow_split_1" type="float" setter="set_param" getter="get_param">
+ The distance from camera to shadow split 1. Relative to [member directional_shadow_max_distance]. Only used in [enum directional_shadow_mode] SHADOW_PARALLEL_*_SPLITS.
</member>
<member name="directional_shadow_split_2" type="float" setter="set_param" getter="get_param">
+ The distance from shadow split 1 to split 2. Relative to [member directional_shadow_max_distance]. Only used in [enum directional_shadow_mode] SHADOW_PARALLEL_*_SPLITS.
</member>
<member name="directional_shadow_split_3" type="float" setter="set_param" getter="get_param">
+ The distance from shadow split 2 to split 3. Relative to [member directional_shadow_max_distance]. Only used in [enum directional_shadow_mode] SHADOW_PARALLEL_4_SPLITS.
</member>
</members>
<constants>
<constant name="SHADOW_ORTHOGONAL" value="0" enum="ShadowMode">
+ Renders the entire scene's shadow map from an orthogonal point of view. May result in blockier shadows on close objects.
</constant>
<constant name="SHADOW_PARALLEL_2_SPLITS" value="1" enum="ShadowMode">
+ Splits the view frustum in 2 areas, each with its own shadow map.
</constant>
<constant name="SHADOW_PARALLEL_4_SPLITS" value="2" enum="ShadowMode">
+ Splits the view frustum in 4 areas, each with its own shadow map.
</constant>
<constant name="SHADOW_DEPTH_RANGE_STABLE" value="0" enum="ShadowDepthRange">
+ Keeps the shadow stable when the camera moves, at the cost of lower effective shadow resolution. Default value.
</constant>
<constant name="SHADOW_DEPTH_RANGE_OPTIMIZED" value="1" enum="ShadowDepthRange">
+ Tries to achieve maximum shadow resolution. May result in saw effect on shadow edges.
</constant>
</constants>
</class>
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index 7503e53188..a013ee6266 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -16,6 +16,7 @@
<return type="int">
</return>
<description>
+ Returns the scancode combined with modifier keys such as [code]Shift[/code] or [code]Alt[/code]. See also [InputEventWithModifiers].
</description>
</method>
</methods>
diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml
index 2f5fb49dba..cbcff1dd75 100644
--- a/doc/classes/InputMap.xml
+++ b/doc/classes/InputMap.xml
@@ -40,6 +40,7 @@
<argument index="0" name="action" type="String">
</argument>
<description>
+ Removes all events from an action.
</description>
</method>
<method name="action_has_event">
@@ -50,7 +51,7 @@
<argument index="1" name="event" type="InputEvent">
</argument>
<description>
- Returns [true] if an action has an [InputEvent] associated with it.
+ Returns [code]true[/code] if the action has the given [InputEvent] associated with it.
</description>
</method>
<method name="action_set_deadzone">
@@ -71,7 +72,7 @@
<argument index="1" name="deadzone" type="float" default="0.5">
</argument>
<description>
- Adds an (empty) action to the [code]InputMap[/code], with a configurable [code]deadzone[/code].
+ Adds an empty action to the [code]InputMap[/code] with a configurable [code]deadzone[/code].
An [InputEvent] can then be added to this action with [method action_add_event].
</description>
</method>
diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml
index 48ca0ddc01..4723cf8ee4 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -77,6 +77,14 @@
<description>
</description>
</method>
+ <method name="get_item_custom_fg_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="get_item_icon" qualifiers="const">
<return type="Texture">
</return>
@@ -227,6 +235,16 @@
<description>
</description>
</method>
+ <method name="set_item_custom_fg_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="custom_fg_color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_item_disabled">
<return type="void">
</return>
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index fdc974630f..cdb1b0aa68 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -115,6 +115,8 @@
<argument index="6" name="floor_max_angle" type="float" default="0.785398">
</argument>
<description>
+ Moves the body while keeping it attached to slopes. Similar to [me
+ As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting[code]snap[/code] to[code](0, 0)[/code] or by using [method move_and_slide] instead.
</description>
</method>
<method name="test_move">
@@ -136,6 +138,7 @@
If the body is at least this close to another body, this body will consider them to be colliding.
</member>
<member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled">
+ If [code]true[/code] the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms.
</member>
</members>
<constants>
diff --git a/doc/classes/Light.xml b/doc/classes/Light.xml
index e9b36c2f9d..04191136a8 100644
--- a/doc/classes/Light.xml
+++ b/doc/classes/Light.xml
@@ -15,28 +15,40 @@
</methods>
<members>
<member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only">
+ If [code]true[/code] the light only appears in the editor and will not be visible at runtime. Default value:[code]false[/code].
</member>
<member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light.BakeMode">
+ The light's bake mode. See [enum BakeMode].
</member>
<member name="light_color" type="Color" setter="set_color" getter="get_color">
+ The light's color.
</member>
<member name="light_cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask">
+ The light will affect objects in the selected layers.
</member>
<member name="light_energy" type="float" setter="set_param" getter="get_param">
+ The light's strength multiplier.
</member>
<member name="light_indirect_energy" type="float" setter="set_param" getter="get_param">
+ Secondary multiplier used with indirect light (light bounces). This works in baked light or GIProbe.
</member>
<member name="light_negative" type="bool" setter="set_negative" getter="is_negative">
+ If [code]true[/code] the light's effect is reversed, darkening areas and casting bright shadows. Default value: [code]false[/code].
</member>
<member name="light_specular" type="float" setter="set_param" getter="get_param">
+ The intensity of the specular blob in objects affected by the light. At [code]0[/code] the light becomes a pure diffuse light.
</member>
<member name="shadow_bias" type="float" setter="set_param" getter="get_param">
+ Used to adjust shadow appearance. Too small a value results in self shadowing, while too large a value causes shadows to separate from casters. Adjust as needed.
</member>
<member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color">
+ The color of shadows cast by this light.
</member>
<member name="shadow_contact" type="float" setter="set_param" getter="get_param">
+ Attempts to reduce [member shadow_bias] gap.
</member>
<member name="shadow_enabled" type="bool" setter="set_shadow" getter="has_shadow">
+ If [code]true[/code] the light will cast shadows. Default value: [code]false[/code].
</member>
<member name="shadow_reverse_cull_face" type="bool" setter="set_shadow_reverse_cull_face" getter="get_shadow_reverse_cull_face">
</member>
@@ -75,10 +87,13 @@
<constant name="PARAM_MAX" value="15" enum="Param">
</constant>
<constant name="BAKE_DISABLED" value="0" enum="BakeMode">
+ Light is ignored when baking. Note: hiding a light does [i]not[/i] affect baking.
</constant>
<constant name="BAKE_INDIRECT" value="1" enum="BakeMode">
+ Only indirect lighting will be baked. Default value.
</constant>
<constant name="BAKE_ALL" value="2" enum="BakeMode">
+ Both direct and indirect light will be baked. Note: you should hide the light if you don't want it to appear twice (dynamic and baked).
</constant>
</constants>
</class>
diff --git a/doc/classes/OmniLight.xml b/doc/classes/OmniLight.xml
index ff2e77ffbe..5ed058bb06 100644
--- a/doc/classes/OmniLight.xml
+++ b/doc/classes/OmniLight.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="OmniLight" inherits="Light" category="Core" version="3.1">
<brief_description>
- OmniDirectional Light, such as a light bulb or a candle.
+ Omnidirectional light, such as a light bulb or a candle.
</brief_description>
<description>
- An OmniDirectional light is a type of [Light] node that emits lights in all directions. The light is attenuated through the distance and this attenuation can be configured by changing the energy, radius and attenuation parameters of [Light].
+ An Omnidirectional light is a type of [Light] that emits light in all directions. The light is attenuated by distance and this attenuation can be configured by changing its energy, radius, and attenuation parameters.
</description>
<tutorials>
<link>http://docs.godotengine.org/en/3.0/tutorials/3d/lights_and_shadows.html</link>
@@ -15,12 +15,16 @@
</methods>
<members>
<member name="omni_attenuation" type="float" setter="set_param" getter="get_param">
+ The light's attenuation (drop-off) curve. A number of presets are available in the Inspector.
</member>
<member name="omni_range" type="float" setter="set_param" getter="get_param">
+ Maximum distance the light affects.
</member>
<member name="omni_shadow_detail" type="int" setter="set_shadow_detail" getter="get_shadow_detail" enum="OmniLight.ShadowDetail">
+ See [enum ShadowDetail].
</member>
<member name="omni_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="OmniLight.ShadowMode">
+ See [enum ShadowMode].
</member>
</members>
<constants>
diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml
index 919ecd7c86..0f03b7b80a 100644
--- a/doc/classes/ProgressBar.xml
+++ b/doc/classes/ProgressBar.xml
@@ -14,6 +14,7 @@
</methods>
<members>
<member name="percent_visible" type="bool" setter="set_percent_visible" getter="is_percent_visible">
+ If [code]true[/code] the fill percentage is displayed on the bar. Default value: [code]true[/code].
</member>
</members>
<constants>
diff --git a/doc/classes/Range.xml b/doc/classes/Range.xml
index fa7e20eff6..46a6132b94 100644
--- a/doc/classes/Range.xml
+++ b/doc/classes/Range.xml
@@ -17,30 +17,32 @@
<argument index="0" name="with" type="Node">
</argument>
<description>
- Binds two Ranges together along with any Ranges previously grouped with either of them. When any of Range's member variables change, it will share the new value with all other Ranges in its group.
+ Binds two ranges together along with any ranges previously grouped with either of them. When any of range's member variables change, it will share the new value with all other ranges in its group.
</description>
</method>
<method name="unshare">
<return type="void">
</return>
<description>
- Stop Range from sharing its member variables with any other Range.
+ Stop range from sharing its member variables with any other.
</description>
</method>
</methods>
<members>
<member name="allow_greater" type="bool" setter="set_allow_greater" getter="is_greater_allowed">
+ If [code]true[/code] [member value] may be greater than [member max_value]. Default value: [code]false[/code].
</member>
<member name="allow_lesser" type="bool" setter="set_allow_lesser" getter="is_lesser_allowed">
+ If [code]true[/code] [member value] may be less than [member min_value]. Default value: [code]false[/code].
</member>
<member name="exp_edit" type="bool" setter="set_exp_ratio" getter="is_ratio_exp">
If [code]true[/code] and [code]min_value[/code] is greater than 0, [code]value[/code] will be represented exponentially rather than linearly.
</member>
<member name="max_value" type="float" setter="set_max" getter="get_max">
- Maximum value. Range is clamped if [code]value[/code] is greater than [code]max_value[/code]. Default value: 100.
+ Maximum value. Range is clamped if [code]value[/code] is greater than [code]max_value[/code]. Default value: [code]100[/code].
</member>
<member name="min_value" type="float" setter="set_min" getter="get_min">
- Minimum value. Range is clamped if [code]value[/code] is less than [code]min_value[/code]. Default value: 0.
+ Minimum value. Range is clamped if [code]value[/code] is less than [code]min_value[/code]. Default value: [code]0[/code].
</member>
<member name="page" type="float" setter="set_page" getter="get_page">
Page size. Used mainly for [ScrollBar]. ScrollBar's length is its size multiplied by [code]page[/code] over the difference between [code]min_value[/code] and [code]max_value[/code].
@@ -49,7 +51,7 @@
The value mapped between 0 and 1.
</member>
<member name="rounded" type="bool" setter="set_use_rounded_values" getter="is_using_rounded_values">
- If [code]true[/code], [code]value[/code] will always be rounded to the nearest integer.
+ If [code]true[/code] [code]value[/code] will always be rounded to the nearest integer. Default value: [code]false[/code].
</member>
<member name="step" type="float" setter="set_step" getter="get_step">
If greater than 0, [code]value[/code] will always be rounded to a multiple of [code]step[/code]. If [code]rounded[/code] is also [code]true[/code], [code]value[/code] will first be rounded to a multiple of [code]step[/code] then rounded to the nearest integer.
@@ -61,14 +63,14 @@
<signals>
<signal name="changed">
<description>
- This signal is emitted when min, max, range or step change.
+ Emitted when [member min_value], [member max_value], [member page], or [member step] change.
</description>
</signal>
<signal name="value_changed">
<argument index="0" name="value" type="float">
</argument>
<description>
- This signal is emitted when value changes.
+ Emitted when [member value] changes.
</description>
</signal>
</signals>
diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml
index 7121bc8b9c..dadc7c5ffa 100644
--- a/doc/classes/TileSet.xml
+++ b/doc/classes/TileSet.xml
@@ -58,7 +58,7 @@
<return type="void">
</return>
<description>
- Clear all tiles.
+ Clears all tiles.
</description>
</method>
<method name="create_tile">
@@ -67,7 +67,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Create a new tile which will be referenced by the given ID.
+ Creates a new tile which will be referenced by the given ID.
</description>
</method>
<method name="find_tile_by_name" qualifiers="const">
@@ -76,21 +76,21 @@
<argument index="0" name="name" type="String">
</argument>
<description>
- Find the first tile matching the given name.
+ Returns the first tile matching the given name.
</description>
</method>
<method name="get_last_unused_tile_id" qualifiers="const">
<return type="int">
</return>
<description>
- Return the ID following the last currently used ID, useful when creating a new tile.
+ Returns the ID following the last currently used ID, useful when creating a new tile.
</description>
</method>
<method name="get_tiles_ids" qualifiers="const">
<return type="Array">
</return>
<description>
- Return an array of all currently used tile IDs.
+ Returns an array of all currently used tile IDs.
</description>
</method>
<method name="remove_tile">
@@ -99,7 +99,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Remove the tile referenced by the given ID.
+ Removes the tile referenced by the given ID.
</description>
</method>
<method name="tile_add_shape">
@@ -124,7 +124,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the light occluder of the tile.
+ Returns the light occluder of the tile.
</description>
</method>
<method name="tile_get_material" qualifiers="const">
@@ -133,7 +133,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the material of the tile.
+ Returns the material of the tile.
</description>
</method>
<method name="tile_get_modulate" qualifiers="const">
@@ -150,7 +150,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the name of the tile.
+ Returns the name of the tile.
</description>
</method>
<method name="tile_get_navigation_polygon" qualifiers="const">
@@ -159,7 +159,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the navigation polygon of the tile.
+ Returns the navigation polygon of the tile.
</description>
</method>
<method name="tile_get_navigation_polygon_offset" qualifiers="const">
@@ -168,7 +168,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the offset of the tile's navigation polygon.
+ Returns the offset of the tile's navigation polygon.
</description>
</method>
<method name="tile_get_normal_map" qualifiers="const">
@@ -185,7 +185,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the offset of the tile's light occluder.
+ Returns the offset of the tile's light occluder.
</description>
</method>
<method name="tile_get_region" qualifiers="const">
@@ -194,7 +194,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the tile sub-region in the texture.
+ Returns the tile sub-region in the texture.
</description>
</method>
<method name="tile_get_shape" qualifiers="const">
@@ -241,7 +241,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the array of shapes of the tile.
+ Returns the array of shapes of the tile.
</description>
</method>
<method name="tile_get_texture" qualifiers="const">
@@ -250,7 +250,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the texture of the tile.
+ Returns the texture of the tile.
</description>
</method>
<method name="tile_get_texture_offset" qualifiers="const">
@@ -259,7 +259,7 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the texture offset of the tile.
+ Returns the texture offset of the tile.
</description>
</method>
<method name="tile_get_tile_mode" qualifiers="const">
@@ -286,7 +286,7 @@
<argument index="1" name="light_occluder" type="OccluderPolygon2D">
</argument>
<description>
- Set a light occluder for the tile.
+ Sets a light occluder for the tile.
</description>
</method>
<method name="tile_set_material">
@@ -297,7 +297,7 @@
<argument index="1" name="material" type="ShaderMaterial">
</argument>
<description>
- Set the material of the tile.
+ Sets the tile's material.
</description>
</method>
<method name="tile_set_modulate">
@@ -308,6 +308,7 @@
<argument index="1" name="color" type="Color">
</argument>
<description>
+ Sets the tile's modulation color.
</description>
</method>
<method name="tile_set_name">
@@ -318,7 +319,7 @@
<argument index="1" name="name" type="String">
</argument>
<description>
- Set the name of the tile, for descriptive purposes.
+ Sets the tile's name.
</description>
</method>
<method name="tile_set_navigation_polygon">
@@ -329,7 +330,7 @@
<argument index="1" name="navigation_polygon" type="NavigationPolygon">
</argument>
<description>
- Set a navigation polygon for the tile.
+ Sets the tile's navigation polygon.
</description>
</method>
<method name="tile_set_navigation_polygon_offset">
@@ -340,7 +341,7 @@
<argument index="1" name="navigation_polygon_offset" type="Vector2">
</argument>
<description>
- Set an offset for the tile's navigation polygon.
+ Sets an offset for the tile's navigation polygon.
</description>
</method>
<method name="tile_set_normal_map">
@@ -351,6 +352,7 @@
<argument index="1" name="normal_map" type="Texture">
</argument>
<description>
+ Sets the tile's normal map texture.
</description>
</method>
<method name="tile_set_occluder_offset">
@@ -372,7 +374,7 @@
<argument index="1" name="region" type="Rect2">
</argument>
<description>
- Set the tile sub-region in the texture. This is common in texture atlases.
+ Set the tile's sub-region in the texture. This is common in texture atlases.
</description>
</method>
<method name="tile_set_shape">
@@ -419,7 +421,7 @@
<argument index="1" name="shapes" type="Array">
</argument>
<description>
- Set an array of shapes for the tile, enabling physics to collide with it.
+ Sets an array of shapes for the tile, enabling collision.
</description>
</method>
<method name="tile_set_texture">
@@ -430,7 +432,7 @@
<argument index="1" name="texture" type="Texture">
</argument>
<description>
- Set the texture of the tile.
+ Sets the tile's texture.
</description>
</method>
<method name="tile_set_texture_offset">
@@ -441,7 +443,7 @@
<argument index="1" name="texture_offset" type="Vector2">
</argument>
<description>
- Set the texture offset of the tile.
+ Sets the tile's texture offset.
</description>
</method>
<method name="tile_set_tile_mode">
@@ -452,6 +454,7 @@
<argument index="1" name="tilemode" type="int" enum="TileSet.TileMode">
</argument>
<description>
+ Sets the tile's [enum TileMode].
</description>
</method>
<method name="tile_set_z_index">
@@ -462,6 +465,7 @@
<argument index="1" name="z_index" type="int">
</argument>
<description>
+ Sets the tile's drawing index.
</description>
</method>
</methods>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index af0712d357..05649193a6 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -22,35 +22,35 @@
<return type="World">
</return>
<description>
- Return the 3D world of the viewport, or if no such present, the one of the parent viewport.
+ Returns the 3D world of the viewport, or if none the world of the parent viewport.
</description>
</method>
<method name="find_world_2d" qualifiers="const">
<return type="World2D">
</return>
<description>
- Return the 2D world of the viewport.
+ Returns the 2D world of the viewport.
</description>
</method>
<method name="get_camera" qualifiers="const">
<return type="Camera">
</return>
<description>
- Return the active 3D camera.
+ Returns the active 3D camera.
</description>
</method>
<method name="get_final_transform" qualifiers="const">
<return type="Transform2D">
</return>
<description>
- Get the total transform of the viewport.
+ Returns the total transform of the viewport.
</description>
</method>
<method name="get_mouse_position" qualifiers="const">
<return type="Vector2">
</return>
<description>
- Get the mouse position, relative to the viewport.
+ Returns the mouse position relative to the viewport.
</description>
</method>
<method name="get_render_info">
@@ -59,35 +59,35 @@
<argument index="0" name="info" type="int" enum="Viewport.RenderInfo">
</argument>
<description>
- Get the specific information about the viewport from rendering pipeline.
+ Returns information about the viewport from the rendering pipeline.
</description>
</method>
<method name="get_size_override" qualifiers="const">
<return type="Vector2">
</return>
<description>
- Get the size override set with [method set_size_override].
+ Returns the size override set with [method set_size_override].
</description>
</method>
<method name="get_texture" qualifiers="const">
<return type="ViewportTexture">
</return>
<description>
- Get the viewport's texture, for use with various objects that you want to texture with the viewport.
+ Returns the viewport's texture.
</description>
</method>
<method name="get_viewport_rid" qualifiers="const">
<return type="RID">
</return>
<description>
- Get the viewport RID from the [VisualServer].
+ Returns the viewport's RID from the [VisualServer].
</description>
</method>
<method name="get_visible_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
- Return the final, visible rect in global screen coordinates.
+ Returns the visible rectangle in global screen coordinates.
</description>
</method>
<method name="gui_get_drag_data" qualifiers="const">
@@ -101,7 +101,7 @@
<return type="bool">
</return>
<description>
- Returns whether there are shown modals on-screen.
+ Returns [code]true[/code] if there are visible modals on-screen.
</description>
</method>
<method name="input">
@@ -116,14 +116,14 @@
<return type="bool">
</return>
<description>
- Get the enabled status of the size override set with [method set_size_override].
+ Returns [code]true[/code] if the size override is enabled. See [method set_size_override].
</description>
</method>
<method name="is_size_override_stretch_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
- Get the enabled status of the size stretch override set with [method set_size_override_stretch].
+ Returns [code]true[/code] if the size stretch override is enabled. See [method set_size_override_stretch].
</description>
</method>
<method name="set_attach_to_screen_rect">
@@ -144,7 +144,7 @@
<argument index="2" name="margin" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
- Set the size override of the viewport. If the enable parameter is true, it would use the override, otherwise it would use the default size. If the size parameter is equal to [code](-1, -1)[/code], it won't update the size.
+ Sets the size override of the viewport. If the [code]enable[/code] parameter is [code]true[/code] the override is used, otherwise it uses the default size. If the size parameter is [code](-1, -1)[/code], it won't update the size.
</description>
</method>
<method name="set_size_override_stretch">
@@ -153,7 +153,7 @@
<argument index="0" name="enabled" type="bool">
</argument>
<description>
- Set whether the size override affects stretch as well.
+ If [code]true[/code] the size override affects stretch as well.
</description>
</method>
<method name="unhandled_input">
@@ -168,7 +168,7 @@
<return type="void">
</return>
<description>
- Force update of the 2D and 3D worlds.
+ Forces update of the 2D and 3D worlds.
</description>
</method>
<method name="warp_mouse">
@@ -177,7 +177,7 @@
<argument index="0" name="to_position" type="Vector2">
</argument>
<description>
- Warp the mouse to a position, relative to the viewport.
+ Warps the mouse to a position relative to the viewport.
</description>
</method>
</methods>
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index d6fbf04353..f7b49c627d 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -64,9 +64,13 @@ void RasterizerCanvasGLES2::_set_uniforms() {
state.canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size);
}
+
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, state.uniforms.texpixel_size);
}
void RasterizerCanvasGLES2::canvas_begin() {
+ data.primitive = GL_TRIANGLES;
+ data.texture = GL_NONE;
state.canvas_shader.bind();
if (storage->frame.current_rt) {
@@ -95,6 +99,7 @@ void RasterizerCanvasGLES2::canvas_begin() {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
+ data.texture = storage->resources.white_tex;
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
glDisableVertexAttribArray(VS::ARRAY_COLOR);
@@ -125,7 +130,7 @@ void RasterizerCanvasGLES2::canvas_begin() {
state.uniforms.extra_matrix = Transform2D();
_set_uniforms();
- _bind_quad_buffer();
+ state.prev_uniforms = state.uniforms;
}
void RasterizerCanvasGLES2::canvas_end() {
@@ -143,6 +148,7 @@ void RasterizerCanvasGLES2::canvas_end() {
RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map) {
RasterizerStorageGLES2::Texture *tex_return = NULL;
+ GLuint newtexid;
if (p_texture.is_valid()) {
@@ -152,8 +158,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
state.current_tex = RID();
state.current_tex_ptr = NULL;
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
+ newtexid = storage->resources.white_tex;
} else {
@@ -167,8 +172,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
texture->render_target->used_in_frame = true;
}
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, texture->tex_id);
+ newtexid = texture->tex_id;
state.current_tex = p_texture;
state.current_tex_ptr = texture;
@@ -179,8 +183,15 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
state.current_tex = RID();
state.current_tex_ptr = NULL;
+ newtexid = storage->resources.white_tex;
+ }
+
+ if (data.texture != newtexid) {
+ _flush();
+
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
+ glBindTexture(GL_TEXTURE_2D, newtexid);
+ data.texture = newtexid;
}
return tex_return;
@@ -190,217 +201,154 @@ void RasterizerCanvasGLES2::_set_texture_rect_mode(bool p_enable, bool p_ninepat
}
void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) {
+ _begin(GL_TRIANGLES);
+ _prepare(p_vertex_count, p_index_count);
- glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
+ Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset;
- uint32_t buffer_ofs = 0;
-
- glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL);
- buffer_ofs += sizeof(Vector2) * p_vertex_count;
+ bool single;
+ Color color;
if (p_singlecolor) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- Color m = *p_colors;
- glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
+ single = true;
+ color = *p_colors;
} else if (!p_colors) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
- } else {
- glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
- glEnableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)0) + buffer_ofs);
- buffer_ofs += sizeof(Color) * p_vertex_count;
- }
-
- if (p_uvs) {
- glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs);
- buffer_ofs += sizeof(Vector2) * p_vertex_count;
+ single = true;
+ color = Color(1, 1, 1, 1);
} else {
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ single = false;
}
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
- glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices);
-
- glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-}
+ const bool use_single_color = single;
+ const Color single_color = color;
-void RasterizerCanvasGLES2::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) {
+ for (int i = 0; i < p_vertex_count; ++i) {
+ v->v = p_vertices[i];
- glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
+ if (use_single_color)
+ v->c = single_color;
+ else
+ v->c = p_colors[i];
- uint32_t buffer_ofs = 0;
+ if (p_uvs)
+ v->uv = p_uvs[i];
+ else
+ v->uv = Vector2();
- glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), (uint8_t *)0);
- buffer_ofs += sizeof(Vector2) * p_vertex_count;
-
- if (p_singlecolor) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- Color m = *p_colors;
- glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
- } else if (!p_colors) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
- } else {
- glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
- glEnableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)0) + buffer_ofs);
- buffer_ofs += sizeof(Color) * p_vertex_count;
+ ++v;
}
- if (p_uvs) {
- glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs);
- } else {
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
- }
+ memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, p_indices, p_index_count * sizeof(int));
- glDrawArrays(p_primitive, 0, p_vertex_count);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
+ _commit(p_vertex_count, p_index_count);
}
-void RasterizerCanvasGLES2::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs) {
-
- static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN };
-
- int color_offset = 0;
- int uv_offset = 0;
- int stride = 2;
-
- if (p_colors) {
- color_offset = stride;
- stride += 4;
- }
+void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) {
- if (p_uvs) {
- uv_offset = stride;
- stride += 2;
- }
+ int command_count = p_item->commands.size();
+ Item::Command **commands = p_item->commands.ptrw();
- float buffer_data[(2 + 2 + 4) * 4];
+ for (int i = 0; i < command_count; i++) {
- for (int i = 0; i < p_points; i++) {
- buffer_data[stride * i + 0] = p_vertices[i].x;
- buffer_data[stride * i + 1] = p_vertices[i].y;
- }
+ Item::Command *command = commands[i];
- if (p_colors) {
- for (int i = 0; i < p_points; i++) {
- buffer_data[stride * i + color_offset + 0] = p_colors[i].r;
- buffer_data[stride * i + color_offset + 1] = p_colors[i].g;
- buffer_data[stride * i + color_offset + 2] = p_colors[i].b;
- buffer_data[stride * i + color_offset + 3] = p_colors[i].a;
+ if (command->type != Item::Command::TYPE_RECT && state.tiled) {
+ _flush();
+ _untile();
}
- }
- if (p_uvs) {
- for (int i = 0; i < p_points; i++) {
- buffer_data[stride * i + uv_offset + 0] = p_uvs[i].x;
- buffer_data[stride * i + uv_offset + 1] = p_uvs[i].y;
- }
- }
+ switch (command->type) {
- glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
- glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4 * sizeof(float), buffer_data);
+ case Item::Command::TYPE_LINE: {
+ const Item::CommandLine *line = static_cast<Item::CommandLine *>(command);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), NULL);
+ if (line->width <= 1) {
+ const int p_vertex_count = 2;
+ const int p_index_count = 2;
- if (p_colors) {
- glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), (uint8_t *)0 + color_offset * sizeof(float));
- glEnableVertexAttribArray(VS::ARRAY_COLOR);
- }
+ _begin(GL_LINES);
+ _prepare(p_vertex_count, p_index_count);
- if (p_uvs) {
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), (uint8_t *)0 + uv_offset * sizeof(float));
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
- }
+ _bind_shader(p_material);
+ _bind_canvas_texture(RID(), RID());
- glDrawArrays(prim[p_points], 0, p_points);
+ Vertex vertices[p_vertex_count];
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-}
+ vertices[0].v = Vector2(line->from.x, line->from.y);
+ vertices[0].c = line->color;
+ vertices[0].uv = Vector2();
-void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) {
+ vertices[1].v = Vector2(line->to.x, line->to.y);
+ vertices[1].c = line->color;
+ vertices[1].uv = Vector2();
- int command_count = p_item->commands.size();
- Item::Command **commands = p_item->commands.ptrw();
+ memcpy(data.mem_vertex_buffer + data.mem_vertex_buffer_offset, vertices, sizeof(vertices));
- for (int i = 0; i < command_count; i++) {
+ const int indices[p_index_count] = { 0, 1 };
- Item::Command *command = commands[i];
+ memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices));
- switch (command->type) {
+ _commit(p_vertex_count, p_index_count);
+ } else {
+ const int p_vertex_count = 4;
+ const int p_index_count = 6;
- case Item::Command::TYPE_LINE: {
+ _begin(GL_TRIANGLES);
+ _prepare(p_vertex_count, p_index_count);
- Item::CommandLine *line = static_cast<Item::CommandLine *>(command);
+ _bind_shader(p_material);
+ _bind_canvas_texture(RID(), RID());
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
+ Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset;
- _bind_canvas_texture(RID(), RID());
+ Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5;
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4fv(VS::ARRAY_COLOR, line->color.components);
+ v[0].v = line->from - t;
+ v[0].c = line->color;
+ v[0].uv = Vector2();
- state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
+ v[1].v = line->from + t;
+ v[1].c = line->color;
+ v[1].uv = Vector2();
- if (line->width <= 1) {
- Vector2 verts[2] = {
- Vector2(line->from.x, line->from.y),
- Vector2(line->to.x, line->to.y)
- };
+ v[2].v = line->to + t;
+ v[2].c = line->color;
+ v[2].uv = Vector2();
- _draw_gui_primitive(2, verts, NULL, NULL);
- } else {
- Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5;
+ v[3].v = line->to - t;
+ v[3].c = line->color;
+ v[3].uv = Vector2();
- Vector2 verts[4] = {
- line->from - t,
- line->from + t,
- line->to + t,
- line->to - t
+ const int indices[p_index_count] = {
+ 0, 1, 2,
+ 2, 3, 0
};
- _draw_gui_primitive(4, verts, NULL, NULL);
+ memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices));
+
+ _commit(p_vertex_count, p_index_count);
}
+
} break;
case Item::Command::TYPE_RECT: {
+ const int p_vertex_count = 4;
+ const int p_index_count = 6;
- Item::CommandRect *r = static_cast<Item::CommandRect *>(command);
+ _begin(GL_TRIANGLES);
+ _prepare(p_vertex_count, p_index_count);
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4fv(VS::ARRAY_COLOR, r->modulate.components);
+ Item::CommandRect *r = static_cast<Item::CommandRect *>(command);
- _bind_quad_buffer();
+ _bind_shader(p_material);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
+ Rect2 src_rect;
+ Rect2 dst_rect;
RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map);
if (!tex) {
- Rect2 dst_rect = Rect2(r->rect.position, r->rect.size);
+ dst_rect = Rect2(r->rect.position, r->rect.size);
if (dst_rect.size.width < 0) {
dst_rect.position.x += dst_rect.size.width;
@@ -411,24 +359,28 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
dst_rect.size.height *= -1;
}
- state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
- state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(0, 0, 1, 1));
+ src_rect = Rect2(0, 0, 1, 1);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
} else {
- bool untile = false;
+ const bool tiled = r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT);
- if (r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) {
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- untile = true;
+ if (tiled != state.tiled) {
+ _flush();
+
+ if (tiled) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ state.tiled = true;
+ } else {
+ _untile();
+ }
}
Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height);
- Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
- Rect2 dst_rect = Rect2(r->rect.position, r->rect.size);
+ src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
+ dst_rect = Rect2(r->rect.position, r->rect.size);
if (dst_rect.size.width < 0) {
dst_rect.position.x += dst_rect.size.width;
@@ -441,48 +393,61 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
if (r->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
+ src_rect.position.x -= src_rect.size.width;
}
-
if (r->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
+ src_rect.position.y -= src_rect.size.height;
}
-
if (r->flags & CANVAS_RECT_TRANSPOSE) {
dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
}
- state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ state.uniforms.texpixel_size = texpixel_size;
+ }
- state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
- state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y));
+ Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset;
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ // 0,0
+ v[0].v = dst_rect.position;
+ v[0].c = r->modulate;
+ v[0].uv = src_rect.position;
- if (untile) {
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
- }
+ // 0,1
+ v[1].v = Vector2(dst_rect.position.x, dst_rect.position.y + dst_rect.size.y);
+ v[1].c = r->modulate;
+ v[1].uv = Vector2(src_rect.position.x, src_rect.position.y + src_rect.size.y);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ // 1,1
+ v[2].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y + dst_rect.size.y);
+ v[2].c = r->modulate;
+ v[2].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y + src_rect.size.y);
+ // 1,0
+ v[3].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y);
+ v[3].c = r->modulate;
+ v[3].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y);
+
+ const int indices[p_index_count] = {
+ 0, 1, 2,
+ 2, 3, 0
+ };
+
+ memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(int) * p_index_count);
+
+ _commit(p_vertex_count, p_index_count);
} break;
case Item::Command::TYPE_NINEPATCH: {
+ const int p_vertex_count = 16;
+ const int p_index_count = 54;
- Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(command);
+ _begin(GL_TRIANGLES);
+ _prepare(p_vertex_count, p_index_count);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true);
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
-
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4fv(VS::ARRAY_COLOR, np->color.components);
+ Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(command);
+ _bind_shader(p_material);
RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(np->texture, np->normal_map);
if (!tex) {
@@ -492,8 +457,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height);
- // state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
- state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ state.uniforms.texpixel_size = texpixel_size;
Rect2 source = np->source;
if (source.size.x == 0 && source.size.y == 0) {
@@ -505,255 +469,334 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
// this buffer contains [ POS POS UV UV ] *
- float buffer[16 * 2 + 16 * 2];
+ Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset;
- {
+ v[0].v = np->rect.position;
+ v[0].c = np->color;
+ v[0].uv = source.position * texpixel_size;
- // first row
+ v[1].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], 0);
+ v[1].c = np->color;
+ v[1].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], 0)) * texpixel_size;
- buffer[(0 * 4 * 4) + 0] = np->rect.position.x;
- buffer[(0 * 4 * 4) + 1] = np->rect.position.y;
+ v[2].v = np->rect.position + Vector2(np->rect.size.x - np->margin[MARGIN_RIGHT], 0);
+ v[2].c = np->color;
+ v[2].uv = (source.position + Vector2(source.size.x - np->margin[MARGIN_RIGHT], 0)) * texpixel_size;
- buffer[(0 * 4 * 4) + 2] = source.position.x * texpixel_size.x;
- buffer[(0 * 4 * 4) + 3] = source.position.y * texpixel_size.y;
+ v[3].v = np->rect.position + Vector2(np->rect.size.x, 0);
+ v[3].c = np->color;
+ v[3].uv = (source.position + Vector2(source.size.x, 0)) * texpixel_size;
- buffer[(0 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT];
- buffer[(0 * 4 * 4) + 5] = np->rect.position.y;
+ v[4].v = np->rect.position + Vector2(0, np->margin[MARGIN_TOP]);
+ v[4].c = np->color;
+ v[4].uv = (source.position + Vector2(0, np->margin[MARGIN_TOP])) * texpixel_size;
- buffer[(0 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
- buffer[(0 * 4 * 4) + 7] = source.position.y * texpixel_size.y;
+ v[5].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->margin[MARGIN_TOP]);
+ v[5].c = np->color;
+ v[5].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], np->margin[MARGIN_TOP])) * texpixel_size;
- buffer[(0 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT];
- buffer[(0 * 4 * 4) + 9] = np->rect.position.y;
+ v[6].v = np->rect.position + Vector2(np->rect.size.x - np->margin[MARGIN_RIGHT], np->margin[MARGIN_TOP]);
+ v[6].c = np->color;
+ v[6].uv = (source.position + Vector2(source.size.x - np->margin[MARGIN_RIGHT], np->margin[MARGIN_TOP])) * texpixel_size;
- buffer[(0 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
- buffer[(0 * 4 * 4) + 11] = source.position.y * texpixel_size.y;
+ v[7].v = np->rect.position + Vector2(np->rect.size.x, np->margin[MARGIN_TOP]);
+ v[7].c = np->color;
+ v[7].uv = (source.position + Vector2(source.size.x, np->margin[MARGIN_TOP])) * texpixel_size;
- buffer[(0 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x;
- buffer[(0 * 4 * 4) + 13] = np->rect.position.y;
+ v[8].v = np->rect.position + Vector2(0, np->rect.size.y - np->margin[MARGIN_BOTTOM]);
+ v[8].c = np->color;
+ v[8].uv = (source.position + Vector2(0, source.size.y - np->margin[MARGIN_BOTTOM])) * texpixel_size;
- buffer[(0 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x;
- buffer[(0 * 4 * 4) + 15] = source.position.y * texpixel_size.y;
+ v[9].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->rect.size.y - np->margin[MARGIN_BOTTOM]);
+ v[9].c = np->color;
+ v[9].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], source.size.y - np->margin[MARGIN_BOTTOM])) * texpixel_size;
- // second row
+ v[10].v = np->rect.position + np->rect.size - Vector2(np->margin[MARGIN_RIGHT], np->margin[MARGIN_BOTTOM]);
+ v[10].c = np->color;
+ v[10].uv = (source.position + source.size - Vector2(np->margin[MARGIN_RIGHT], np->margin[MARGIN_BOTTOM])) * texpixel_size;
- buffer[(1 * 4 * 4) + 0] = np->rect.position.x;
- buffer[(1 * 4 * 4) + 1] = np->rect.position.y + np->margin[MARGIN_TOP];
+ v[11].v = np->rect.position + np->rect.size - Vector2(0, np->margin[MARGIN_BOTTOM]);
+ v[11].c = np->color;
+ v[11].uv = (source.position + source.size - Vector2(0, np->margin[MARGIN_BOTTOM])) * texpixel_size;
- buffer[(1 * 4 * 4) + 2] = source.position.x * texpixel_size.x;
- buffer[(1 * 4 * 4) + 3] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
+ v[12].v = np->rect.position + Vector2(0, np->rect.size.y);
+ v[12].c = np->color;
+ v[12].uv = (source.position + Vector2(0, source.size.y)) * texpixel_size;
- buffer[(1 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT];
- buffer[(1 * 4 * 4) + 5] = np->rect.position.y + np->margin[MARGIN_TOP];
+ v[13].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->rect.size.y);
+ v[13].c = np->color;
+ v[13].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], source.size.y)) * texpixel_size;
- buffer[(1 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
- buffer[(1 * 4 * 4) + 7] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
+ v[14].v = np->rect.position + np->rect.size - Vector2(np->margin[MARGIN_RIGHT], 0);
+ v[14].c = np->color;
+ v[14].uv = (source.position + source.size - Vector2(np->margin[MARGIN_RIGHT], 0)) * texpixel_size;
- buffer[(1 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT];
- buffer[(1 * 4 * 4) + 9] = np->rect.position.y + np->margin[MARGIN_TOP];
+ v[15].v = np->rect.position + np->rect.size;
+ v[15].c = np->color;
+ v[15].uv = (source.position + source.size) * texpixel_size;
- buffer[(1 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
- buffer[(1 * 4 * 4) + 11] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
+ memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, data.ninepatch_elements, sizeof(data.ninepatch_elements));
- buffer[(1 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x;
- buffer[(1 * 4 * 4) + 13] = np->rect.position.y + np->margin[MARGIN_TOP];
+ _commit(p_vertex_count, p_index_count - (np->draw_center ? 0 : 6));
+ } break;
- buffer[(1 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x;
- buffer[(1 * 4 * 4) + 15] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
+ case Item::Command::TYPE_CIRCLE: {
+ Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(command);
- // thrid row
+ _bind_shader(p_material);
- buffer[(2 * 4 * 4) + 0] = np->rect.position.x;
- buffer[(2 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM];
+ const int num_points = 32;
- buffer[(2 * 4 * 4) + 2] = source.position.x * texpixel_size.x;
- buffer[(2 * 4 * 4) + 3] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
+ Vector2 points[num_points + 1];
+ points[num_points] = circle->pos;
- buffer[(2 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT];
- buffer[(2 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM];
+ int indices[num_points * 3];
- buffer[(2 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
- buffer[(2 * 4 * 4) + 7] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
+ for (int i = 0; i < num_points; i++) {
+ points[i] = circle->pos + Vector2(Math::sin(i * Math_PI * 2.0 / num_points), Math::cos(i * Math_PI * 2.0 / num_points)) * circle->radius;
+ indices[i * 3 + 0] = i;
+ indices[i * 3 + 1] = (i + 1) % num_points;
+ indices[i * 3 + 2] = num_points;
+ }
- buffer[(2 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT];
- buffer[(2 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM];
+ _bind_canvas_texture(RID(), RID());
- buffer[(2 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
- buffer[(2 * 4 * 4) + 11] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
+ _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true);
+ } break;
- buffer[(2 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x;
- buffer[(2 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM];
+ case Item::Command::TYPE_POLYGON: {
+ Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(command);
- buffer[(2 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x;
- buffer[(2 * 4 * 4) + 15] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
+ const int *indices = polygon->indices.ptr();
+ if (!indices) // self-intersecting polygon
+ break;
- // fourth row
+ _bind_shader(p_material);
+ RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map);
- buffer[(3 * 4 * 4) + 0] = np->rect.position.x;
- buffer[(3 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y;
+ if (texture) {
+ Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
+ state.uniforms.texpixel_size = texpixel_size;
+ }
- buffer[(3 * 4 * 4) + 2] = source.position.x * texpixel_size.x;
- buffer[(3 * 4 * 4) + 3] = (source.position.y + source.size.y) * texpixel_size.y;
+ _draw_polygon(indices, polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1);
+ } break;
- buffer[(3 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT];
- buffer[(3 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y;
+ case Item::Command::TYPE_POLYLINE: {
+ Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(command);
- buffer[(3 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
- buffer[(3 * 4 * 4) + 7] = (source.position.y + source.size.y) * texpixel_size.y;
+ if (pline->triangles.size()) {
+ const int p_vertex_count = pline->triangles.size();
+ const int p_triangle_count = p_vertex_count - 2;
+ const int p_index_count = p_triangle_count * 3;
- buffer[(3 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT];
- buffer[(3 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y;
+ _begin(GL_TRIANGLES);
+ _prepare(p_vertex_count, p_index_count);
- buffer[(3 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
- buffer[(3 * 4 * 4) + 11] = (source.position.y + source.size.y) * texpixel_size.y;
+ _bind_shader(p_material);
+ _bind_canvas_texture(RID(), RID());
- buffer[(3 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x;
- buffer[(3 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y;
+ const Vector2 *t = pline->triangles.ptr();
+ Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset;
- buffer[(3 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x;
- buffer[(3 * 4 * 4) + 15] = (source.position.y + source.size.y) * texpixel_size.y;
+ const bool p_singlecolor = pline->triangle_colors.size() == 1;
+ const Color *p_colors = pline->triangle_colors.ptr();
- // print_line(String::num((source.position.y + source.size.y) * texpixel_size.y));
- }
+ bool single;
+ Color color;
- glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices);
- glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * (16 + 16) * 2, buffer);
+ if (pline->triangle_colors.size() == 1) {
+ single = true;
+ color = *p_colors;
+ } else if (!p_colors) {
+ single = true;
+ color = Color(1, 1, 1, 1);
+ } else {
+ single = false;
+ }
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements);
+ const bool use_single_color = single;
+ const Color single_color = color;
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ for (int i = 0; i < p_vertex_count; ++i) {
+ if (use_single_color)
+ v->c = single_color;
+ else
+ v->c = p_colors[i];
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (uint8_t *)0 + (sizeof(float) * 2));
+ v->uv = Vector2();
+ v->v = t[i];
- glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_BYTE, NULL);
+ ++v;
+ }
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ for (int i = 0; i < p_triangle_count; ++i) {
+ const int indices[3] = {
+ i, i + 1, i + 2
+ };
- } break;
+ memcpy(data.mem_index_buffer + data.mem_index_buffer_offset + i * 3, indices, sizeof(indices));
+ }
- case Item::Command::TYPE_CIRCLE: {
+ _commit(p_vertex_count, p_index_count);
+ } else {
+ _begin(GL_LINES);
- Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(command);
+ _bind_shader(p_material);
+ _bind_canvas_texture(RID(), RID());
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
+ const Color *p_colors = pline->line_colors.ptr();
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
+ bool single;
+ Color color;
- static const int num_points = 32;
+ if (pline->line_colors.size() == 1) {
+ single = true;
+ color = *p_colors;
+ } else if (!p_colors) {
+ single = true;
+ color = Color(1, 1, 1, 1);
+ } else {
+ single = false;
+ }
- Vector2 points[num_points + 1];
- points[num_points] = circle->pos;
+ const bool use_single_color = single;
+ const Color single_color = color;
- int indices[num_points * 3];
+ const Vector2 *p_lines = pline->lines.ptr();
- for (int i = 0; i < num_points; i++) {
- points[i] = circle->pos + Vector2(Math::sin(i * Math_PI * 2.0 / num_points), Math::cos(i * Math_PI * 2.0 / num_points)) * circle->radius;
- indices[i * 3 + 0] = i;
- indices[i * 3 + 1] = (i + 1) % num_points;
- indices[i * 3 + 2] = num_points;
- }
+ if (pline->multiline) {
+ const int p_lines_count = pline->lines.size() / 2;
- _bind_canvas_texture(RID(), RID());
+ for (int i = 0; i < p_lines_count; ++i) {
+ const int p_vertex_count = 2;
+ const int p_index_count = 2;
- _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true);
- } break;
+ _prepare(p_vertex_count, p_index_count);
- case Item::Command::TYPE_POLYGON: {
+ Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset;
- Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(command);
+ for (int j = 0; j < 2; ++j) {
+ if (use_single_color)
+ v->c = single_color;
+ else
+ v->c = p_colors[i];
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true);
+ v->uv = Vector2();
+ v->v = p_lines[i * 2 + j];
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
+ ++v;
+ }
- RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map);
+ const int indices[p_index_count] = { 0, 1 };
- if (texture) {
- Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
- state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
- }
+ memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices));
- _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1);
- } break;
+ _commit(p_vertex_count, p_index_count);
+ }
+ } else {
+ const int p_vertex_count = pline->lines.size();
+ const int p_lines_count = p_vertex_count - 1;
+ const int p_index_count = p_lines_count * 2;
- case Item::Command::TYPE_POLYLINE: {
- Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(command);
+ _prepare(p_vertex_count, p_index_count);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
+ _bind_shader(p_material);
+ _bind_canvas_texture(RID(), RID());
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
+ Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset;
- _bind_canvas_texture(RID(), RID());
+ for (int i = 0; i < p_vertex_count; ++i) {
+ if (use_single_color)
+ v->c = single_color;
+ else
+ v->c = p_colors[i];
- if (pline->triangles.size()) {
- _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1);
- } else {
- if (pline->multiline) {
- int todo = pline->lines.size() / 2;
- int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4);
- int offset = 0;
-
- while (todo) {
- int to_draw = MIN(max_per_call, todo);
- _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1);
- todo -= to_draw;
- offset += to_draw * 2;
+ v->uv = Vector2();
+ v->v = p_lines[i];
+
+ ++v;
}
- } else {
- _draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1);
+
+ for (int i = 0; i < p_lines_count; ++i) {
+ const int indices[2] = { i, i + 1 };
+
+ memcpy(data.mem_index_buffer + data.mem_index_buffer_offset + i * 2, indices, sizeof(indices));
+ }
+
+ _commit(p_vertex_count, p_index_count);
}
}
} break;
case Item::Command::TYPE_PRIMITIVE: {
-
Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(command);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true);
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
+ const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN };
ERR_CONTINUE(primitive->points.size() < 1);
+ _bind_shader(p_material);
RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map);
if (texture) {
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
- state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ state.uniforms.texpixel_size = texpixel_size;
}
+ const int p_vertex_count = primitive->points.size();
+ const int p_index_count = p_vertex_count;
+
+ _begin(prim[p_vertex_count]);
+ _prepare(p_vertex_count, p_index_count);
+
+ Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset;
+ int *index = data.mem_index_buffer + data.mem_index_buffer_offset;
+
+ Color c;
+ bool p_single_color;
+
+ const Color *p_colors = primitive->colors.ptr();
+ const Vector2 *p_uvs = primitive->uvs.ptr();
+ const Vector2 *p_points = primitive->points.ptr();
+
if (primitive->colors.size() == 1 && primitive->points.size() > 1) {
- Color c = primitive->colors[0];
- glVertexAttrib4f(VS::ARRAY_COLOR, c.r, c.g, c.b, c.a);
+ p_single_color = true;
+ c = primitive->colors[0];
} else if (primitive->colors.empty()) {
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ p_single_color = true;
+ c = Color(1, 1, 1, 1);
+ } else {
+ p_single_color = false;
+ }
+
+ const bool use_single_color = p_single_color;
+ const Color single_color = c;
+
+ for (int i = 0; i < p_vertex_count; ++i) {
+ if (use_single_color)
+ v->c = single_color;
+ else
+ v->c = p_colors[i];
+
+ if (p_uvs)
+ v->uv = p_uvs[i];
+ else
+ v->uv = Vector2();
+
+ v->v = p_points[i];
+
+ index[i] = i;
+
+ ++v;
}
- _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr());
+ _commit(p_vertex_count, p_index_count);
} break;
case Item::Command::TYPE_TRANSFORM: {
Item::CommandTransform *transform = static_cast<Item::CommandTransform *>(command);
state.uniforms.extra_matrix = transform->xform;
- state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX, state.uniforms.extra_matrix);
} break;
case Item::Command::TYPE_PARTICLES: {
@@ -816,6 +859,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
+ data.texture = storage->resources.white_tex;
int last_blend_mode = -1;
@@ -825,8 +869,9 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
Item *ci = p_item_list;
- if (current_clip != ci->final_clip_owner) {
+ Item *material_owner = ci->material_owner ? ci->material_owner : ci;
+ if (current_clip != ci->final_clip_owner) {
current_clip = ci->final_clip_owner;
if (current_clip) {
@@ -850,8 +895,6 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
}
}
- Item *material_owner = ci->material_owner ? ci->material_owner : ci;
-
RID material = material_owner->material;
RasterizerStorageGLES2::Material *material_ptr = storage->material_owner.getornull(material);
@@ -981,9 +1024,11 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
state.uniforms.extra_matrix = Transform2D();
_set_uniforms();
-
_canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr);
+ // TODO: figure out when to _flush to get better batching results
+ _flush();
+
rebind_shader = true; // hacked in for now.
if (reclip) {
@@ -997,6 +1042,8 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
p_item_list = p_item_list->next;
}
+ _flush();
+
if (current_clip) {
glDisable(GL_SCISSOR_TEST);
}
@@ -1035,17 +1082,40 @@ void RasterizerCanvasGLES2::reset_canvas() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
-void RasterizerCanvasGLES2::_bind_quad_buffer() {
- glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, NULL);
-}
-void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) {
+void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &dst_rect, const Rect2 &src_rect) {
+
+ const int p_index_count = 6;
+ const int p_vertex_count = 4;
+
+ Vertex v[p_vertex_count];
+ Color c(1, 1, 1, 1);
+
+ // 0,0
+ v[0].v = dst_rect.position;
+ v[0].c = c;
+ v[0].uv = src_rect.position;
+
+ // 0,1
+ v[1].v = Vector2(dst_rect.position.x, dst_rect.position.y + dst_rect.size.y);
+ v[1].c = c;
+ v[1].uv = Vector2(src_rect.position.x, src_rect.position.y + src_rect.size.y);
+
+ // 1,1
+ v[2].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y + dst_rect.size.y);
+ v[2].c = c;
+ v[2].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y + src_rect.size.y);
- state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y));
- state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y));
+ // 1,0
+ v[3].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y);
+ v[3].c = c;
+ v[3].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ const int indices[p_index_count] = {
+ 0, 1, 2,
+ 2, 3, 0
+ };
+
+ _draw(GL_TRIANGLES, p_vertex_count, v, p_index_count, indices);
}
void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) {
@@ -1053,60 +1123,36 @@ void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_im
void RasterizerCanvasGLES2::initialize() {
- // quad buffer
- {
- glGenBuffers(1, &data.canvas_quad_vertices);
- glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices);
-
- const float qv[8] = {
- 0, 0,
- 0, 1,
- 1, 1,
- 1, 0
- };
-
- glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, qv, GL_STATIC_DRAW);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- }
-
// polygon buffer
{
uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
poly_size *= 1024;
poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float));
- glGenBuffers(1, &data.polygon_buffer);
- glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
+ glGenBuffers(1, &data.vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, data.vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW);
- data.polygon_buffer_size = poly_size;
+ data.vertex_buffer_size = poly_size;
glBindBuffer(GL_ARRAY_BUFFER, 0);
uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_size_kb", 128);
index_size *= 1024; // kb
- glGenBuffers(1, &data.polygon_index_buffer);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
+ glGenBuffers(1, &data.index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW);
+
+ data.index_buffer_size = index_size;
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
// ninepatch buffers
{
// array buffer
- glGenBuffers(1, &data.ninepatch_vertices);
- glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices);
-
- glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, NULL, GL_DYNAMIC_DRAW);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- // element buffer
- glGenBuffers(1, &data.ninepatch_elements);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements);
#define _EIDX(y, x) (y * 4 + x)
- uint8_t elems[3 * 2 * 9] = {
+ const int elems[3 * 2 * 9] = {
// first row
@@ -1150,14 +1196,24 @@ void RasterizerCanvasGLES2::initialize() {
;
#undef _EIDX
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW);
+ memcpy(data.ninepatch_elements, elems, sizeof(elems));
+ }
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ {
+ const uint32_t size = data.vertex_buffer_size / sizeof(Vertex);
+ data.mem_vertex_buffer = (Vertex *)memalloc(sizeof(Vertex) * size);
+ data.mem_vertex_buffer_offset = 0;
+ data.mem_vertex_buffer_size = size;
}
- state.canvas_shader.init();
+ {
+ const uint32_t size = data.index_buffer_size / sizeof(int);
+ data.mem_index_buffer = (int *)memalloc(sizeof(int) * size);
+ data.mem_index_buffer_offset = 0;
+ data.mem_index_buffer_size = size;
+ }
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
+ state.canvas_shader.init();
state.canvas_shader.bind();
}
@@ -1167,3 +1223,92 @@ void RasterizerCanvasGLES2::finalize() {
RasterizerCanvasGLES2::RasterizerCanvasGLES2() {
}
+
+void RasterizerCanvasGLES2::_begin(const GLuint p_primitive) {
+ if (data.primitive != p_primitive) {
+ _flush();
+ data.primitive = p_primitive;
+ }
+}
+
+void RasterizerCanvasGLES2::_prepare(const int p_vertex_count, const int p_index_count) {
+ if (data.mem_vertex_buffer_size - data.mem_vertex_buffer_offset < p_vertex_count ||
+ data.mem_index_buffer_size - data.mem_index_buffer_offset < p_index_count) {
+ _flush();
+ }
+}
+
+void RasterizerCanvasGLES2::_draw(const GLuint p_primitive, const int p_vertex_count, const Vertex *p_vertices, const int p_index_count, const int *p_indices) {
+ glBindBuffer(GL_ARRAY_BUFFER, data.vertex_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * p_vertex_count, p_vertices);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.index_buffer);
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices);
+
+ glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+ glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), NULL);
+
+ glEnableVertexAttribArray(VS::ARRAY_COLOR);
+ glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), ((uint8_t *)0) + sizeof(Vector2));
+
+ glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), ((uint8_t *)0) + sizeof(Vector2) + sizeof(Color));
+
+ glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_INT, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+void RasterizerCanvasGLES2::_flush() {
+ if (data.mem_vertex_buffer_offset) {
+ _draw(data.primitive, data.mem_vertex_buffer_offset, data.mem_vertex_buffer, data.mem_index_buffer_offset, data.mem_index_buffer);
+ }
+
+ data.mem_vertex_buffer_offset = 0;
+ data.mem_index_buffer_offset = 0;
+}
+
+void RasterizerCanvasGLES2::_commit(const int p_vertex_count, const int p_index_count) {
+ ERR_FAIL_COND(!p_vertex_count);
+ ERR_FAIL_COND(!p_index_count);
+
+ if (state.uniforms.extra_matrix != state.prev_uniforms.extra_matrix ||
+ state.uniforms.final_modulate != state.prev_uniforms.final_modulate ||
+ state.uniforms.modelview_matrix != state.prev_uniforms.modelview_matrix ||
+ state.uniforms.projection_matrix != state.prev_uniforms.projection_matrix ||
+ state.uniforms.texpixel_size != state.prev_uniforms.texpixel_size ||
+ state.uniforms.time != state.prev_uniforms.time) {
+
+ _set_uniforms();
+ state.prev_uniforms = state.uniforms;
+ _flush();
+ }
+
+ const int new_index_offset = data.mem_index_buffer_offset + p_index_count;
+
+ for (int i = data.mem_index_buffer_offset; i < new_index_offset; ++i)
+ data.mem_index_buffer[i] += data.mem_vertex_buffer_offset;
+
+ data.mem_vertex_buffer_offset += p_vertex_count;
+ data.mem_index_buffer_offset = new_index_offset;
+}
+
+void RasterizerCanvasGLES2::_untile() {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ state.tiled = false;
+}
+
+void RasterizerCanvasGLES2::_bind_shader(RasterizerStorageGLES2::Material *p_material) {
+ if (!state.canvas_shader.is_dirty()) {
+ return;
+ }
+
+ _flush();
+
+ if (state.canvas_shader.bind()) {
+ state.canvas_shader.use_material((void *)p_material);
+ }
+}
diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h
index cda3ec79e7..d5a122e533 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.h
+++ b/drivers/gles2/rasterizer_canvas_gles2.h
@@ -50,23 +50,44 @@ public:
Color final_modulate;
float time;
+
+ Size2 texpixel_size;
+ };
+
+ struct Vertex {
+ Vector2 v;
+ Color c;
+ Vector2 uv;
};
struct Data {
- GLuint canvas_quad_vertices;
- GLuint polygon_buffer;
- GLuint polygon_index_buffer;
+ GLuint vertex_buffer;
+ GLuint index_buffer;
+
+ uint32_t vertex_buffer_size;
+ uint32_t index_buffer_size;
+
+ int ninepatch_elements[3 * 2 * 9];
- uint32_t polygon_buffer_size;
+ int *mem_index_buffer;
+ uint32_t mem_index_buffer_offset;
+ uint32_t mem_index_buffer_size;
- GLuint ninepatch_vertices;
- GLuint ninepatch_elements;
+ Vertex *mem_vertex_buffer;
+ uint32_t mem_vertex_buffer_offset;
+ uint32_t mem_vertex_buffer_size;
+ GLuint primitive;
+ GLuint texture;
} data;
struct State {
Uniforms uniforms;
+ Uniforms prev_uniforms;
+
+ bool tiled;
+
bool canvas_texscreen_used;
CanvasShaderGLES2 canvas_shader;
// CanvasShadowShaderGLES3 canvas_shadow_shader;
@@ -99,9 +120,16 @@ public:
_FORCE_INLINE_ void _set_texture_rect_mode(bool p_enable, bool p_ninepatch = false);
- _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs);
_FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
- _FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
+
+ _FORCE_INLINE_ void _begin(const GLuint p_primitive);
+ _FORCE_INLINE_ void _prepare(const int p_vertex_count, const int p_index_count);
+ _FORCE_INLINE_ void _commit(const int p_vertex_count, const int p_index_count);
+
+ _FORCE_INLINE_ void _flush();
+ _FORCE_INLINE_ void _draw(const GLuint p_primitive, const int p_vertex_count, const Vertex *p_vertices, const int p_index_count, const int *p_indices);
+
+ _FORCE_INLINE_ void _untile();
_FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material);
_FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect);
@@ -114,8 +142,8 @@ public:
virtual void reset_canvas();
RasterizerStorageGLES2::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map);
+ _FORCE_INLINE_ void _bind_shader(RasterizerStorageGLES2::Material *p_material);
- void _bind_quad_buffer();
void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
void initialize();
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 73d93f7b46..165ffc0412 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -345,9 +345,6 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
- canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
- canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
-
canvas->state.canvas_shader.set_custom_shader(0);
canvas->state.canvas_shader.bind();
@@ -359,7 +356,7 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
// TODO normals
- canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1));
+ canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 1, 1, -1));
glBindTexture(GL_TEXTURE_2D, 0);
canvas->canvas_end();
@@ -392,12 +389,6 @@ void RasterizerGLES2::end_frame(bool p_swap_buffers) {
OS::get_singleton()->swap_buffers();
else
glFinish();
-
- if (p_swap_buffers) {
- glColorMask(true, true, true, true);
- glClearColor(0, 0, 0, 1);
- glClear(GL_COLOR_BUFFER_BIT);
- }
}
void RasterizerGLES2::finalize() {
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index c1fbf73254..38c0ccaac2 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -252,7 +252,7 @@ public:
int mipmaps;
bool active;
- GLenum tex_id;
+ GLuint tex_id;
uint16_t stored_cube_sides;
@@ -429,6 +429,8 @@ public:
bool uses_screen_texture;
bool uses_screen_uv;
bool uses_time;
+ bool uses_modelview_matrix;
+ bool uses_vertex;
} canvas_item;
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index e9b58cb272..89c1b6490d 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -122,13 +122,11 @@ GLint ShaderGLES2::get_uniform_location(int p_index) const {
}
bool ShaderGLES2::bind() {
-
- if (active != this || !version || new_conditional_version.key != conditional_version.key) {
- conditional_version = new_conditional_version;
- version = get_current_version();
- } else {
+ if (!is_dirty())
return false;
- }
+
+ conditional_version = new_conditional_version;
+ version = get_current_version();
ERR_FAIL_COND_V(!version, false);
@@ -1109,3 +1107,7 @@ ShaderGLES2::ShaderGLES2() {
ShaderGLES2::~ShaderGLES2() {
finish();
}
+
+bool ShaderGLES2::is_dirty() const {
+ return active != this || !version || new_conditional_version.key != conditional_version.key;
+}
diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h
index cb515c199c..99513abfe9 100644
--- a/drivers/gles2/shader_gles2.h
+++ b/drivers/gles2/shader_gles2.h
@@ -208,6 +208,7 @@ public:
GLint get_uniform_location(int p_index) const;
static _FORCE_INLINE_ ShaderGLES2 *get_active() { return active; }
+ bool is_dirty() const;
bool bind();
void unbind();
void bind_uniforms();
diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl
index 29d81bb2c4..a63c7675d8 100644
--- a/drivers/gles2/shaders/canvas.glsl
+++ b/drivers/gles2/shaders/canvas.glsl
@@ -20,13 +20,6 @@ varying vec4 color_interp;
uniform highp vec2 color_texpixel_size;
-#ifdef USE_TEXTURE_RECT
-
-uniform vec4 dst_rect;
-uniform vec4 src_rect;
-
-#endif
-
uniform highp float time;
VERTEX_SHADER_GLOBALS
@@ -44,35 +37,9 @@ void main() {
vec4 color = color_attrib;
-#ifdef USE_TEXTURE_RECT
-
- if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z
- uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.yx;
- } else {
- uv_interp = src_rect.xy + abs(src_rect.zw) * vertex;
- }
-
- vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0);
-
- // This is what is done in the GLES 3 bindings and should
- // take care of flipped rects.
- //
- // But it doesn't.
- // I don't know why, will need to investigate further.
-
- outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0)));
-
- // outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex;
-#else
vec4 outvec = vec4(vertex.xy, 0.0, 1.0);
-#ifdef USE_UV_ATTRIBUTE
uv_interp = uv_attrib;
-#else
- uv_interp = vertex.xy;
-#endif
-
-#endif
{
vec2 src_vtx=outvec.xy;
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 60826aa81b..65c41ef579 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1781,7 +1781,7 @@ void EditorHelp::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ class_desc->add_color_override("selection_color", EditorSettings::get_singleton()->get("text_editor/theme/selection_color"));
_update_doc();
} break;
@@ -1863,7 +1863,7 @@ EditorHelp::EditorHelp() {
class_desc = memnew(RichTextLabel);
add_child(class_desc);
class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
- class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ class_desc->add_color_override("selection_color", EditorSettings::get_singleton()->get("text_editor/theme/selection_color"));
class_desc->connect("meta_clicked", this, "_class_desc_select");
class_desc->connect("gui_input", this, "_class_desc_input");
@@ -1929,7 +1929,7 @@ void EditorHelpBit::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- rich_text->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ rich_text->add_color_override("selection_color", EditorSettings::get_singleton()->get("text_editor/theme/selection_color"));
} break;
default: break;
@@ -1948,7 +1948,7 @@ EditorHelpBit::EditorHelpBit() {
add_child(rich_text);
//rich_text->set_anchors_and_margins_preset(Control::PRESET_WIDE);
rich_text->connect("meta_clicked", this, "_meta_clicked");
- rich_text->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ rich_text->add_color_override("selection_color", EditorSettings::get_singleton()->get("text_editor/theme/selection_color"));
rich_text->set_override_selected_font_color(false);
set_custom_minimum_size(Size2(0, 70 * EDSCALE));
}
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 0cbd5f0bff..1c1d72e7d1 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -61,7 +61,7 @@ void EditorPropertyText::_text_changed(const String &p_string) {
if (updating)
return;
- emit_signal("property_changed", get_edited_property(), p_string);
+ emit_signal("property_changed", get_edited_property(), p_string, true);
}
void EditorPropertyText::update_property() {
@@ -92,12 +92,11 @@ EditorPropertyText::EditorPropertyText() {
void EditorPropertyMultilineText::_big_text_changed() {
text->set_text(big_text->get_text());
- emit_signal("property_changed", get_edited_property(), big_text->get_text());
+ emit_signal("property_changed", get_edited_property(), big_text->get_text(), true);
}
void EditorPropertyMultilineText::_text_changed() {
-
- emit_signal("property_changed", get_edited_property(), text->get_text());
+ emit_signal("property_changed", get_edited_property(), text->get_text(), true);
}
void EditorPropertyMultilineText::_open_big_text() {
@@ -1735,12 +1734,18 @@ EditorPropertyTransform::EditorPropertyTransform() {
void EditorPropertyColor::_color_changed(const Color &p_color) {
- emit_signal("property_changed", get_edited_property(), p_color);
+ emit_signal("property_changed", get_edited_property(), p_color, true);
+}
+
+void EditorPropertyColor::_popup_closed() {
+
+ emit_signal("property_changed", get_edited_property(), picker->get_pick_color(), false);
}
void EditorPropertyColor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_color_changed"), &EditorPropertyColor::_color_changed);
+ ClassDB::bind_method(D_METHOD("_popup_closed"), &EditorPropertyColor::_popup_closed);
}
void EditorPropertyColor::update_property() {
@@ -1758,6 +1763,7 @@ EditorPropertyColor::EditorPropertyColor() {
add_child(picker);
picker->set_flat(true);
picker->connect("color_changed", this, "_color_changed");
+ picker->connect("popup_closed", this, "_popup_closed");
}
////////////// NODE PATH //////////////////////
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index d5fac9c1a0..ea107d76b0 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -476,6 +476,7 @@ class EditorPropertyColor : public EditorProperty {
GDCLASS(EditorPropertyColor, EditorProperty)
ColorPickerButton *picker;
void _color_changed(const Color &p_color);
+ void _popup_closed();
protected:
static void _bind_methods();
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 8203c85c6a..23dbb026dd 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -125,13 +125,13 @@ EditorPropertyDictionaryObject::EditorPropertyDictionaryObject() {
///////////////////// ARRAY ///////////////////////////
-void EditorPropertyArray::_property_changed(const String &p_prop, Variant p_value) {
+void EditorPropertyArray::_property_changed(const String &p_prop, Variant p_value, bool changing) {
if (p_prop.begins_with("indices")) {
int idx = p_prop.get_slice("/", 1).to_int();
Variant array = object->get_array();
array.set(idx, p_value);
- emit_signal("property_changed", get_edited_property(), array);
+ emit_signal("property_changed", get_edited_property(), array, true);
if (array.get_type() == Variant::ARRAY) {
array = array.call("duplicate"); //dupe, so undo/redo works better
@@ -544,7 +544,7 @@ void EditorPropertyArray::_bind_methods() {
ClassDB::bind_method("_edit_pressed", &EditorPropertyArray::_edit_pressed);
ClassDB::bind_method("_page_changed", &EditorPropertyArray::_page_changed);
ClassDB::bind_method("_length_changed", &EditorPropertyArray::_length_changed);
- ClassDB::bind_method("_property_changed", &EditorPropertyArray::_property_changed);
+ ClassDB::bind_method("_property_changed", &EditorPropertyArray::_property_changed, DEFVAL(false));
ClassDB::bind_method("_change_type", &EditorPropertyArray::_change_type);
ClassDB::bind_method("_change_type_menu", &EditorPropertyArray::_change_type_menu);
}
@@ -579,7 +579,7 @@ EditorPropertyArray::EditorPropertyArray() {
///////////////////// DICTIONARY ///////////////////////////
-void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p_value) {
+void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p_value, bool changing) {
if (p_prop == "new_item_key") {
@@ -593,7 +593,7 @@ void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p
Variant key = dict.get_key_at_index(idx);
dict[key] = p_value;
- emit_signal("property_changed", get_edited_property(), dict);
+ emit_signal("property_changed", get_edited_property(), dict, true);
dict = dict.duplicate(); //dupe, so undo/redo works better
object->set_dict(dict);
@@ -1006,7 +1006,7 @@ void EditorPropertyDictionary::_page_changed(double p_page) {
void EditorPropertyDictionary::_bind_methods() {
ClassDB::bind_method("_edit_pressed", &EditorPropertyDictionary::_edit_pressed);
ClassDB::bind_method("_page_changed", &EditorPropertyDictionary::_page_changed);
- ClassDB::bind_method("_property_changed", &EditorPropertyDictionary::_property_changed);
+ ClassDB::bind_method("_property_changed", &EditorPropertyDictionary::_property_changed, DEFVAL(false));
ClassDB::bind_method("_change_type", &EditorPropertyDictionary::_change_type);
ClassDB::bind_method("_change_type_menu", &EditorPropertyDictionary::_change_type_menu);
ClassDB::bind_method("_add_key_value", &EditorPropertyDictionary::_add_key_value);
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index 75c67d280d..a8ddb02e9d 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -67,7 +67,7 @@ class EditorPropertyArray : public EditorProperty {
void _page_changed(double p_page);
void _length_changed(double p_page);
void _edit_pressed();
- void _property_changed(const String &p_prop, Variant p_value);
+ void _property_changed(const String &p_prop, Variant p_value, bool changing = false);
void _change_type(Object *p_button, int p_index);
void _change_type_menu(int p_index);
@@ -99,7 +99,7 @@ class EditorPropertyDictionary : public EditorProperty {
void _page_changed(double p_page);
void _edit_pressed();
- void _property_changed(const String &p_prop, Variant p_value);
+ void _property_changed(const String &p_prop, Variant p_value, bool changing = false);
void _change_type(Object *p_button, int p_index);
void _change_type_menu(int p_index);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index d24816ee02..85186440ab 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -357,6 +357,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Adaptive,Default,Custom");
_initial_set("text_editor/theme/line_spacing", 4);
+ _initial_set("text_editor/theme/selection_color", Color::html("40808080"));
_load_default_text_editor_theme();
@@ -473,6 +474,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["editors/3d/freelook/freelook_modifier_speed_factor"] = PropertyInfo(Variant::REAL, "editors/3d/freelook/freelook_modifier_speed_factor", PROPERTY_HINT_RANGE, "0.0, 10.0, 0.1");
_initial_set("editors/3d/freelook/freelook_speed_zoom_link", false);
+ _initial_set("editors/2d/grid_color", Color(1.0, 1.0, 1.0, 0.07));
_initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8));
_initial_set("editors/2d/bone_width", 5);
_initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9));
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 3995eb3dd6..50d71f1c98 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -173,7 +173,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
const Color error_color = p_theme->get_color("error_color", "Editor");
const Color success_color = p_theme->get_color("success_color", "Editor");
const Color warning_color = p_theme->get_color("warning_color", "Editor");
- dark_icon_color_dictionary[Color::html("#ff5d5d")] = error_color;
+ dark_icon_color_dictionary[Color::html("#ff0000")] = error_color;
dark_icon_color_dictionary[Color::html("#45ff8b")] = success_color;
dark_icon_color_dictionary[Color::html("#dbab09")] = warning_color;
@@ -381,12 +381,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("error_color", "Editor", error_color);
theme->set_color("property_color", "Editor", property_color);
- // 2d grid color
- const Color grid_minor_color = mono_color * Color(1.0, 1.0, 1.0, 0.07);
- const Color grid_major_color = Color(font_color_disabled.r, font_color_disabled.g, font_color_disabled.b, 0.15);
- theme->set_color("grid_major_color", "Editor", grid_major_color);
- theme->set_color("grid_minor_color", "Editor", grid_minor_color);
-
const int thumb_size = EDITOR_DEF("filesystem/file_dialog/thumbnail_size", 64);
theme->set_constant("scale", "Editor", EDSCALE);
theme->set_constant("thumb_size", "Editor", thumb_size);
@@ -971,8 +965,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// GraphEdit
theme->set_stylebox("bg", "GraphEdit", style_tree_bg);
- theme->set_color("grid_major", "GraphEdit", grid_major_color);
- theme->set_color("grid_minor", "GraphEdit", grid_minor_color);
+ theme->set_color("grid_major", "GraphEdit", Color(1.0, 1.0, 1.0, 0.15));
+ theme->set_color("grid_minor", "GraphEdit", Color(1.0, 1.0, 1.0, 0.07));
theme->set_color("activity", "GraphEdit", accent_color);
theme->set_icon("minus", "GraphEdit", theme->get_icon("ZoomLess", "EditorIcons"));
theme->set_icon("more", "GraphEdit", theme->get_icon("ZoomMore", "EditorIcons"));
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 2be1f1644e..ef7409fd43 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -37,10 +37,10 @@
#include "scene/gui/check_box.h"
#include "scene/gui/file_dialog.h"
#include "scene/gui/grid_container.h"
-#include "scene/gui/item_list.h"
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/progress_bar.h"
+#include "scene/gui/tree.h"
#define ROOT_PREFIX "res://"
@@ -58,6 +58,34 @@ static bool is_text_char(CharType c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
+static bool find_next(const String &line, String pattern, int from, bool match_case, bool whole_words, int &out_begin, int &out_end) {
+
+ int end = from;
+
+ while (true) {
+ int begin = match_case ? line.find(pattern, end) : line.findn(pattern, end);
+
+ if (begin == -1)
+ return false;
+
+ end = begin + pattern.length();
+ out_begin = begin;
+ out_end = end;
+
+ if (whole_words) {
+ if (begin > 0 && is_text_char(line[begin - 1])) {
+ continue;
+ }
+ if (end < line.size() && is_text_char(line[end])) {
+ continue;
+ }
+ }
+
+ return true;
+ }
+}
+
+//--------------------------------------------------------------------------------
FindInFiles::FindInFiles() {
_root_prefix = ROOT_PREFIX;
_extension_filter.insert("gd");
@@ -246,24 +274,7 @@ void FindInFiles::_scan_file(String fpath) {
String line = f->get_line();
- // Find all occurrences in the current line
- while (true) {
- begin = _match_case ? line.find(_pattern, end) : line.findn(_pattern, end);
-
- if (begin == -1)
- break;
-
- end = begin + _pattern.length();
-
- if (_whole_words) {
- if (begin > 0 && is_text_char(line[begin - 1])) {
- continue;
- }
- if (end < line.size() && is_text_char(line[end])) {
- continue;
- }
- }
-
+ while (find_next(line, _pattern, end, _match_case, _whole_words, begin, end)) {
emit_signal(SIGNAL_RESULT_FOUND, fpath, line_number, begin, end, line);
}
}
@@ -567,14 +578,18 @@ FindInFilesPanel::FindInFilesPanel() {
vbc->add_child(hbc);
}
- // In the future, this should be replaced by a more specific list container,
- // which can highlight text regions and change opacity for enabled/disabled states
- _results_display = memnew(ItemList);
+ _results_display = memnew(Tree);
_results_display->add_font_override("font", get_font("source", "EditorFonts"));
_results_display->set_v_size_flags(SIZE_EXPAND_FILL);
_results_display->connect("item_selected", this, "_on_result_selected");
+ _results_display->connect("item_edited", this, "_on_item_edited");
+ _results_display->set_hide_root(true);
+ _results_display->set_select_mode(Tree::SELECT_ROW);
+ _results_display->create_item(); // Root
vbc->add_child(_results_display);
+ _with_replace = false;
+
{
_replace_container = memnew(HBoxContainer);
@@ -600,12 +615,33 @@ FindInFilesPanel::FindInFilesPanel() {
void FindInFilesPanel::set_with_replace(bool with_replace) {
+ _with_replace = with_replace;
_replace_container->set_visible(with_replace);
+
+ if (with_replace) {
+ // Results show checkboxes on their left so they can be opted out
+ _results_display->set_columns(2);
+ _results_display->set_column_expand(0, false);
+ _results_display->set_column_min_width(0, 48 * EDSCALE);
+
+ } else {
+ // Results are single-cell items
+ _results_display->set_column_expand(0, true);
+ _results_display->set_columns(1);
+ }
+}
+
+void FindInFilesPanel::clear() {
+ _file_items.clear();
+ _result_items.clear();
+ _results_display->clear();
+ _results_display->create_item(); // Root
}
void FindInFilesPanel::start_search() {
- _results_display->clear();
+ clear();
+
_status_label->set_text(TTR("Searching..."));
_search_text_label->set_text(_finder->get_search_text());
@@ -636,9 +672,90 @@ void FindInFilesPanel::_notification(int p_what) {
void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin, int end, String text) {
- int i = _results_display->get_item_count();
- _results_display->add_item(fpath + ": " + String::num(line_number) + ": " + text.replace("\t", " "));
- _results_display->set_item_metadata(i, varray(fpath, line_number, begin, end));
+ TreeItem *file_item;
+ Map<String, TreeItem *>::Element *E = _file_items.find(fpath);
+
+ if (E == NULL) {
+ file_item = _results_display->create_item();
+ file_item->set_text(0, fpath);
+ file_item->set_metadata(0, fpath);
+
+ // The width of this column is restrained to checkboxes, but that doesn't make sense for the parent items,
+ // so we override their width so they can expand to full width
+ file_item->set_expand_right(0, true);
+
+ _file_items[fpath] = file_item;
+
+ } else {
+ file_item = E->value();
+ }
+
+ int text_index = _with_replace ? 1 : 0;
+
+ TreeItem *item = _results_display->create_item(file_item);
+
+ // Do this first because it resets properties of the cell...
+ item->set_cell_mode(text_index, TreeItem::CELL_MODE_CUSTOM);
+
+ String item_text = String::num_int64(line_number) + ": " + text.replace("\t", " ");
+
+ item->set_text(text_index, item_text);
+ item->set_custom_draw(text_index, this, "_draw_result_text");
+
+ Ref<Font> font = _results_display->get_font("font");
+
+ float raw_text_width = font->get_string_size(text).x;
+ float item_text_width = font->get_string_size(item_text).x;
+
+ Result r;
+ r.line_number = line_number;
+ r.begin = begin;
+ r.end = end;
+ r.draw_begin = (item_text_width - raw_text_width) + font->get_string_size(text.left(r.begin)).x;
+ r.draw_width = font->get_string_size(text.substr(r.begin, r.end - r.begin + 1)).x;
+ _result_items[item] = r;
+
+ if (_with_replace) {
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_checked(0, true);
+ item->set_editable(0, true);
+ }
+}
+
+void FindInFilesPanel::draw_result_text(Object *item_obj, Rect2 rect) {
+
+ TreeItem *item = Object::cast_to<TreeItem>(item_obj);
+ if (!item)
+ return;
+
+ Map<TreeItem *, Result>::Element *E = _result_items.find(item);
+ if (!E)
+ return;
+ Result r = E->value();
+
+ Rect2 match_rect = rect;
+ match_rect.position.x += r.draw_begin;
+ match_rect.size.x = r.draw_width;
+ match_rect.position.y += 1 * EDSCALE;
+ match_rect.size.y -= 2 * EDSCALE;
+
+ _results_display->draw_rect(match_rect, Color(0, 0, 0, 0.5));
+ // Text is drawn by Tree already
+}
+
+void FindInFilesPanel::_on_item_edited() {
+
+ TreeItem *item = _results_display->get_selected();
+
+ if (item->is_checked(0)) {
+ item->set_custom_color(1, _results_display->get_color("font_color"));
+
+ } else {
+ // Grey out
+ Color color = _results_display->get_color("font_color");
+ color.a /= 2.0;
+ item->set_custom_color(1, color);
+ }
}
void FindInFilesPanel::_on_finished() {
@@ -653,10 +770,19 @@ void FindInFilesPanel::_on_cancel_button_clicked() {
stop_search();
}
-void FindInFilesPanel::_on_result_selected(int i) {
+void FindInFilesPanel::_on_result_selected() {
+
+ TreeItem *item = _results_display->get_selected();
+ Map<TreeItem *, Result>::Element *E = _result_items.find(item);
+
+ if (E == NULL)
+ return;
+ Result r = E->value();
+
+ TreeItem *file_item = item->get_parent();
+ String fpath = file_item->get_metadata(0);
- Array meta = _results_display->get_item_metadata(i);
- emit_signal(SIGNAL_RESULT_SELECTED, meta[0], meta[1], meta[2], meta[3]);
+ emit_signal(SIGNAL_RESULT_SELECTED, fpath, r.line_number, r.begin, r.end);
}
void FindInFilesPanel::_on_replace_text_changed(String text) {
@@ -668,39 +794,33 @@ void FindInFilesPanel::_on_replace_all_clicked() {
String replace_text = get_replace_text();
ERR_FAIL_COND(replace_text.empty());
- String last_fpath;
- PoolIntArray locations;
PoolStringArray modified_files;
- for (int i = 0; i < _results_display->get_item_count(); ++i) {
+ for (Map<String, TreeItem *>::Element *E = _file_items.front(); E; E = E->next()) {
- Array meta = _results_display->get_item_metadata(i);
+ TreeItem *file_item = E->value();
+ String fpath = file_item->get_metadata(0);
- String fpath = meta[0];
+ Vector<Result> locations;
+ for (TreeItem *item = file_item->get_children(); item; item = item->get_next()) {
- // Results are sorted by file, so we can batch replaces
- if (fpath != last_fpath) {
- if (locations.size() != 0) {
- apply_replaces_in_file(last_fpath, locations, replace_text);
- modified_files.append(last_fpath);
- locations.resize(0);
- }
- }
+ if (!item->is_checked(0))
+ continue;
- locations.append(meta[1]); // line_number
- locations.append(meta[2]); // begin
- locations.append(meta[3]); // end
-
- last_fpath = fpath;
- }
+ Map<TreeItem *, Result>::Element *E = _result_items.find(item);
+ ERR_FAIL_COND(E == NULL);
+ locations.push_back(E->value());
+ }
- if (locations.size() != 0) {
- apply_replaces_in_file(last_fpath, locations, replace_text);
- modified_files.append(last_fpath);
+ if (locations.size() != 0) {
+ // Results are sorted by file, so we can batch replaces
+ apply_replaces_in_file(fpath, locations, replace_text);
+ modified_files.append(fpath);
+ }
}
// Hide replace bar so we can't trigger the action twice without doing a new search
- set_with_replace(false);
+ _replace_container->hide();
emit_signal(SIGNAL_FILES_MODIFIED, modified_files);
}
@@ -740,11 +860,7 @@ private:
Vector<char> _line_buffer;
};
-void FindInFilesPanel::apply_replaces_in_file(String fpath, PoolIntArray locations, String text) {
-
- ERR_FAIL_COND(locations.size() % 3 != 0);
-
- //print_line(String("Replacing {0} occurrences in {1}").format(varray(fpath, locations.size() / 3)));
+void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result> &locations, String new_text) {
// If the file is already open, I assume the editor will reload it.
// If there are unsaved changes, the user will be asked on focus,
@@ -759,21 +875,34 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, PoolIntArray locatio
ConservativeGetLine conservative;
String line = conservative.get_line(f);
+ String search_text = _finder->get_search_text();
+
+ int offset = 0;
- PoolIntArray::Read locations_read = locations.read();
- for (int i = 0; i < locations.size(); i += 3) {
+ for (int i = 0; i < locations.size(); ++i) {
- int repl_line_number = locations_read[i];
- int repl_begin = locations_read[i + 1];
- int repl_end = locations_read[i + 2];
+ int repl_line_number = locations[i].line_number;
while (current_line < repl_line_number) {
buffer += line;
line = conservative.get_line(f);
++current_line;
+ offset = 0;
+ }
+
+ int repl_begin = locations[i].begin + offset;
+ int repl_end = locations[i].end + offset;
+
+ int _;
+ if (!find_next(line, search_text, repl_begin, _finder->is_match_case(), _finder->is_whole_words(), _, _)) {
+ // Make sure the replace is still valid in case the file was tampered with.
+ print_line(String("Occurrence no longer matches, replace will be ignored in {0}: line {1}, col {2}").format(varray(fpath, repl_line_number, repl_begin)));
+ continue;
}
- line = line.left(repl_begin) + text + line.right(repl_end);
+ line = line.left(repl_begin) + new_text + line.right(repl_end);
+ // keep an offset in case there are successive replaces in the same line
+ offset += new_text.length() - (repl_end - repl_begin);
}
buffer += line;
@@ -811,11 +940,13 @@ void FindInFilesPanel::set_progress_visible(bool visible) {
void FindInFilesPanel::_bind_methods() {
ClassDB::bind_method("_on_result_found", &FindInFilesPanel::_on_result_found);
+ ClassDB::bind_method("_on_item_edited", &FindInFilesPanel::_on_item_edited);
ClassDB::bind_method("_on_finished", &FindInFilesPanel::_on_finished);
ClassDB::bind_method("_on_cancel_button_clicked", &FindInFilesPanel::_on_cancel_button_clicked);
ClassDB::bind_method("_on_result_selected", &FindInFilesPanel::_on_result_selected);
ClassDB::bind_method("_on_replace_text_changed", &FindInFilesPanel::_on_replace_text_changed);
ClassDB::bind_method("_on_replace_all_clicked", &FindInFilesPanel::_on_replace_all_clicked);
+ ClassDB::bind_method("_draw_result_text", &FindInFilesPanel::draw_result_text);
ADD_SIGNAL(MethodInfo(SIGNAL_RESULT_SELECTED,
PropertyInfo(Variant::STRING, "path"),
diff --git a/editor/find_in_files.h b/editor/find_in_files.h
index d57184960b..75ea1c3161 100644
--- a/editor/find_in_files.h
+++ b/editor/find_in_files.h
@@ -131,7 +131,8 @@ private:
};
class Button;
-class ItemList;
+class Tree;
+class TreeItem;
class ProgressBar;
// Display search results
@@ -159,22 +160,37 @@ private:
void _on_result_found(String fpath, int line_number, int begin, int end, String text);
void _on_finished();
void _on_cancel_button_clicked();
- void _on_result_selected(int i);
+ void _on_result_selected();
+ void _on_item_edited();
void _on_replace_text_changed(String text);
void _on_replace_all_clicked();
- void apply_replaces_in_file(String fpath, PoolIntArray locations, String text);
+ struct Result {
+ int line_number;
+ int begin;
+ int end;
+ float draw_begin;
+ float draw_width;
+ };
+ void apply_replaces_in_file(String fpath, const Vector<Result> &locations, String new_text);
void update_replace_buttons();
String get_replace_text();
+
+ void draw_result_text(Object *item_obj, Rect2 rect);
+
void set_progress_visible(bool visible);
+ void clear();
FindInFiles *_finder;
Label *_search_text_label;
- ItemList *_results_display;
+ Tree *_results_display;
Label *_status_label;
Button *_cancel_button;
ProgressBar *_progress_bar;
+ Map<String, TreeItem *> _file_items;
+ Map<TreeItem *, Result> _result_items;
+ bool _with_replace;
HBoxContainer *_replace_container;
LineEdit *_replace_line_edit;
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 17a9394b51..a2d54e0048 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -198,6 +198,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/invert_color"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "stream"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "detect_3d"), p_preset == PRESET_DETECT));
@@ -354,6 +355,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
int srgb = p_options["flags/srgb"];
bool fix_alpha_border = p_options["process/fix_alpha_border"];
bool premult_alpha = p_options["process/premult_alpha"];
+ bool invert_color = p_options["process/invert_color"];
bool stream = p_options["stream"];
int size_limit = p_options["size_limit"];
bool force_rgbe = int(p_options["compress/hdr_mode"]) == 1;
@@ -409,6 +411,19 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
image->premultiply_alpha();
}
+ if (invert_color) {
+ int height = image->get_height();
+ int width = image->get_width();
+
+ image->lock();
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ image->set_pixel(i, j, image->get_pixel(i, j).inverted());
+ }
+ }
+ image->unlock();
+ }
+
bool detect_3d = p_options["detect_3d"];
bool detect_srgb = srgb == 2;
bool detect_normal = normal == 0;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 145a2ef9bb..72248b62a3 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -2276,14 +2276,14 @@ void CanvasItemEditor::_draw_grid() {
real_grid_offset = grid_offset;
}
- const Color grid_minor_color = get_color("grid_minor_color", "Editor");
+ const Color grid_color = EditorSettings::get_singleton()->get("editors/2d/grid_color");
if (grid_step.x != 0) {
for (int i = 0; i < s.width; i++) {
int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(i, 0)).x - real_grid_offset.x) / (grid_step.x * Math::pow(2.0, grid_step_multiplier))));
if (i == 0)
last_cell = cell;
if (last_cell != cell)
- viewport->draw_line(Point2(i, 0), Point2(i, s.height), grid_minor_color);
+ viewport->draw_line(Point2(i, 0), Point2(i, s.height), grid_color);
last_cell = cell;
}
}
@@ -2294,7 +2294,7 @@ void CanvasItemEditor::_draw_grid() {
if (i == 0)
last_cell = cell;
if (last_cell != cell)
- viewport->draw_line(Point2(0, i), Point2(s.width, i), grid_minor_color);
+ viewport->draw_line(Point2(0, i), Point2(s.width, i), grid_color);
last_cell = cell;
}
}
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 49c54ad67d..f5bdf77973 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -616,8 +616,8 @@ void CurveEditor::_draw() {
Vector2 min_edge = get_world_pos(Vector2(0, view_size.y));
Vector2 max_edge = get_world_pos(Vector2(view_size.x, 0));
- const Color grid_color0 = get_color("grid_major_color", "Editor");
- const Color grid_color1 = get_color("grid_minor_color", "Editor");
+ const Color grid_color0 = Color(1.0, 1.0, 1.0, 0.15);
+ const Color grid_color1 = Color(1.0, 1.0, 1.0, 0.07);
draw_line(Vector2(min_edge.x, curve.get_min_value()), Vector2(max_edge.x, curve.get_min_value()), grid_color0);
draw_line(Vector2(max_edge.x, curve.get_max_value()), Vector2(min_edge.x, curve.get_max_value()), grid_color0);
draw_line(Vector2(0, min_edge.y), Vector2(0, max_edge.y), grid_color0);
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 9782b9d1f4..7445e6ce1c 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -4352,10 +4352,13 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
- is_checked = !is_checked;
- VisualServer::get_singleton()->instance_set_visible(origin_instance, is_checked);
+ origin_enabled = !is_checked;
+ VisualServer::get_singleton()->instance_set_visible(origin_instance, origin_enabled);
+ // Update the grid since its appearance depends on whether the origin is enabled
+ _finish_grid();
+ _init_grid();
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), is_checked);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), origin_enabled);
} break;
case MENU_VIEW_GRID: {
@@ -4778,7 +4781,11 @@ void SpatialEditor::_init_grid() {
Vector3 p2_dest = p2 * (-axis_n1 + axis_n2);
Color line_color = secondary_grid_color;
- if (j % primary_grid_steps == 0) {
+ if (origin_enabled && j == 0) {
+ // Don't draw the center lines of the grid if the origin is enabled
+ // The origin would overlap the grid lines in this case, causing flickering
+ continue;
+ } else if (j % primary_grid_steps == 0) {
line_color = primary_grid_color;
}
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index 4057145c2f..5850c0dbf1 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -508,6 +508,7 @@ private:
RID origin;
RID origin_instance;
+ bool origin_enabled;
RID grid[3];
RID grid_instance[3];
bool grid_visible[3]; //currently visible
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index d13e01dc1e..4a9cbfe535 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -70,7 +70,7 @@ void TextureRegionEditor::_region_draw() {
VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D());
if (snap_mode == SNAP_GRID) {
- Color grid_color = get_color("grid_major_color", "Editor");
+ Color grid_color = Color(1.0, 1.0, 1.0, 0.15);
Size2 s = edit_draw->get_size();
int last_cell = 0;
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 101dc3037f..3d14db7d0e 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -533,10 +533,9 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era
return PoolVector<Vector2>();
}
- for (int i = ids.size() - 1; i >= 0; i--) {
- if (ids[i] == prev_id) {
- return PoolVector<Vector2>();
- }
+ if (ids.size() == 1 && ids[0] == prev_id) {
+ // Same ID, nothing to change
+ return PoolVector<Vector2>();
}
Rect2i r = node->get_used_rect();
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 170546f14c..3cebbb5d21 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -231,7 +231,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
if (error != String()) {
- Vector<String> items = error.split("\n");
+ Vector<String> items = error.split("\n", false);
error = "";
for (int i = 0; i < items.size(); i++) {
if (i > 0)
@@ -756,7 +756,7 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0);
if (err != OK) {
- error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted: ") + platform->get_name());
+ error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " " + platform->get_name());
error_dialog->show();
error_dialog->popup_centered_minsize(Size2(300, 80));
ERR_PRINT("Failed to export project");
@@ -956,7 +956,7 @@ ProjectExportDialog::ProjectExportDialog() {
export_error = memnew(Label);
main_vb->add_child(export_error);
export_error->hide();
- export_error->add_color_override("font_color", get_color("error_color", "Editor"));
+ export_error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
export_templates_error = memnew(HBoxContainer);
main_vb->add_child(export_templates_error);
@@ -964,7 +964,7 @@ ProjectExportDialog::ProjectExportDialog() {
Label *export_error2 = memnew(Label);
export_templates_error->add_child(export_error2);
- export_error2->add_color_override("font_color", get_color("error_color", "Editor"));
+ export_error2->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " ");
error_dialog = memnew(AcceptDialog);
@@ -975,6 +975,7 @@ ProjectExportDialog::ProjectExportDialog() {
LinkButton *download_templates = memnew(LinkButton);
download_templates->set_text(TTR("Manage Export Templates"));
+ download_templates->set_v_size_flags(SIZE_SHRINK_CENTER);
export_templates_error->add_child(download_templates);
download_templates->connect("pressed", this, "_open_export_template_manager");
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 197550d686..815ad9c10f 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -51,8 +51,8 @@ bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) co
if (needs) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
- if (m_pickRay && gObj->is_ray_pickable()) {
- return true;
+ if (m_pickRay && !gObj->is_ray_pickable()) {
+ return false;
} else if (m_exclude->has(gObj->get_self())) {
return false;
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index abd56d2757..934c93059a 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -46,12 +46,12 @@
void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("#");
- p_delimiters->push_back("\"\"\" \"\"\"");
}
void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("\" \"");
p_delimiters->push_back("' '");
+ p_delimiters->push_back("\"\"\" \"\"\"");
}
Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
#ifdef TOOLS_ENABLED
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index a2df83925c..f3cf4c9c5d 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -18,14 +18,20 @@ def make_cs_files_header(src, dst):
header.write('#include "ustring.h"\n')
inserted_files = ''
import os
- for file in os.listdir(src):
- if file.endswith('.cs'):
- with open(os.path.join(src, file), 'rb') as f:
+ latest_mtime = 0
+ for root, _, files in os.walk(src):
+ files = [f for f in files if f.endswith('.cs')]
+ for file in files:
+ filepath = os.path.join(root, file)
+ filepath_src_rel = os.path.relpath(filepath, src)
+ mtime = os.path.getmtime(filepath)
+ latest_mtime = mtime if mtime > latest_mtime else latest_mtime
+ with open(filepath, 'rb') as f:
buf = f.read()
decomp_size = len(buf)
import zlib
buf = zlib.compress(buf)
- name = os.path.splitext(file)[0]
+ name = os.path.splitext(os.path.normpath(filepath_src_rel))[0].strip(os.sep).replace(os.sep, '_').replace('.', '_dotto_')
header.write('\nstatic const int _cs_' + name + '_compressed_size = ' + str(len(buf)) + ';\n')
header.write('static const int _cs_' + name + '_uncompressed_size = ' + str(decomp_size) + ';\n')
header.write('static const unsigned char _cs_' + name + '_compressed[] = { ')
@@ -33,18 +39,13 @@ def make_cs_files_header(src, dst):
if i > 0:
header.write(', ')
header.write(byte_to_str(buf[buf_idx]))
- inserted_files += '\tr_files.insert("' + file + '", ' \
+ inserted_files += '\tr_files.insert("' + filepath_src_rel + '", ' \
'CompressedFile(_cs_' + name + '_compressed_size, ' \
'_cs_' + name + '_uncompressed_size, ' \
'_cs_' + name + '_compressed));\n'
header.write(' };\n')
- version_file = os.path.join(src, 'VERSION.txt')
- with open(version_file, 'r') as content_file:
- try:
- glue_version = int(content_file.read()) # make sure the format is valid
- header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
- except ValueError:
- raise ValueError('Invalid C# glue version in: ' + version_file)
+ glue_version = int(latest_mtime) # The latest modified time will do for now
+ header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
header.write('\nstruct CompressedFile\n' '{\n'
'\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n'
'\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n'
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 76907451e7..b97bb5e95f 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -512,6 +512,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
data.resize(file_data.uncompressed_size);
Compression::decompress(data.ptrw(), file_data.uncompressed_size, file_data.data, file_data.compressed_size, Compression::MODE_DEFLATE);
+ String output_dir = output_file.get_base_dir();
+
+ if (!DirAccess::exists(output_dir)) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Error err = da->make_dir_recursive(ProjectSettings::get_singleton()->globalize_path(output_dir));
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+ }
+
FileAccessRef file = FileAccess::open(output_file, FileAccess::WRITE);
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
file->store_buffer(data.ptr(), data.size());
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index b3b259e851..0fb8734410 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -210,6 +210,8 @@ bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_s
if (!FileAccess::exists(api_assembly_file)) {
MonoBuildInfo api_build_info(api_sln_file, p_config);
+ // TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
+ // once we start to actively document manually maintained C# classes
api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings
if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) {
diff --git a/modules/mono/glue/cs_files/VERSION.txt b/modules/mono/glue/cs_files/VERSION.txt
deleted file mode 100755
index ec635144f6..0000000000
--- a/modules/mono/glue/cs_files/VERSION.txt
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/platform/android/detect.py b/platform/android/detect.py
index ada36e2814..0c6c9fdca3 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -128,7 +128,7 @@ def configure(env):
env.extra_suffix = ".armv7" + env.extra_suffix
elif env["android_arch"] == "arm64v8":
if get_platform(env["ndk_platform"]) < 21:
- print("WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than andorid-21; setting ndk_platform=android-21")
+ print("WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21")
env["ndk_platform"] = "android-21"
env['ARCH'] = 'arch-arm64'
target_subpath = "aarch64-linux-android-4.9"
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 34fc3e09b5..7667de160d 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -172,6 +172,7 @@ def configure_msvc(env, manual_msvc_config):
env.Append(CCFLAGS=['/O1'])
env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
+ env.Append(LINKFLAGS=['/OPT:REF'])
elif (env["target"] == "release_debug"):
if (env["optimize"] == "speed"): #optimize for speed (default)
@@ -180,6 +181,7 @@ def configure_msvc(env, manual_msvc_config):
env.Append(CCFLAGS=['/O1'])
env.AppendUnique(CPPDEFINES = ['DEBUG_ENABLED'])
env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+ env.Append(LINKFLAGS=['/OPT:REF'])
elif (env["target"] == "debug_release"):
env.Append(CCFLAGS=['/Z7', '/Od'])
@@ -194,6 +196,10 @@ def configure_msvc(env, manual_msvc_config):
env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
env.Append(LINKFLAGS=['/DEBUG'])
+ if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes"):
+ env.AppendUnique(CCFLAGS=['/Z7'])
+ env.AppendUnique(LINKFLAGS=['/DEBUG'])
+
## Compile/link flags
env.AppendUnique(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo'])
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index d6cfd039d9..d5bb85c035 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -2790,9 +2790,13 @@ bool OS_Windows::is_disable_crash_handler() const {
Error OS_Windows::move_to_trash(const String &p_path) {
SHFILEOPSTRUCTW sf;
+ WCHAR *from = new WCHAR[p_path.length() + 2];
+ wcscpy(from, p_path.c_str());
+ from[p_path.length() + 1] = 0;
+
sf.hwnd = hWnd;
sf.wFunc = FO_DELETE;
- sf.pFrom = p_path.c_str();
+ sf.pFrom = from;
sf.pTo = NULL;
sf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
sf.fAnyOperationsAborted = FALSE;
@@ -2800,6 +2804,7 @@ Error OS_Windows::move_to_trash(const String &p_path) {
sf.lpszProgressTitle = NULL;
int ret = SHFileOperationW(&sf);
+ delete[] from;
if (ret) {
ERR_PRINTS("SHFileOperation error: " + itos(ret));
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 9d1e3291b7..a1e844898e 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -1339,7 +1339,7 @@ void OS_X11::request_attention() {
//
// Sets the _NET_WM_STATE_DEMANDS_ATTENTION atom for WM_STATE
// Will be unset by the window manager after user react on the request for attention
- //
+
XEvent xev;
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
Atom wm_attention = XInternAtom(x11_display, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
@@ -1353,6 +1353,7 @@ void OS_X11::request_attention() {
xev.xclient.data.l[1] = wm_attention;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ XFlush(x11_display);
}
void OS_X11::get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state) {
@@ -2436,7 +2437,19 @@ String OS_X11::get_system_dir(SystemDir p_dir) const {
void OS_X11::move_window_to_foreground() {
- XRaiseWindow(x11_display, x11_window);
+ XEvent xev;
+ Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = x11_window;
+ xev.xclient.message_type = net_active_window;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = 1;
+ xev.xclient.data.l[1] = CurrentTime;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ XFlush(x11_display);
}
void OS_X11::set_cursor_shape(CursorShape p_shape) {
diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp
index 4991cedfab..9b1cb1369a 100644
--- a/scene/animation/skeleton_ik.cpp
+++ b/scene/animation/skeleton_ik.cpp
@@ -34,6 +34,8 @@
#include "skeleton_ik.h"
+#ifndef _3D_DISABLED
+
FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) {
for (int i = childs.size() - 1; 0 <= i; --i) {
if (p_bone_id == childs[i].bone) {
@@ -549,3 +551,5 @@ void SkeletonIK::_solve_chain() {
return;
FabrikInverseKinematic::solve(task, interpolation, use_magnet, magnet_position);
}
+
+#endif // _3D_DISABLED
diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h
index 366c599c01..08fb00e798 100644
--- a/scene/animation/skeleton_ik.h
+++ b/scene/animation/skeleton_ik.h
@@ -31,6 +31,8 @@
#ifndef SKELETON_IK_H
#define SKELETON_IK_H
+#ifndef _3D_DISABLED
+
/**
* @author AndreaCatania
*/
@@ -209,4 +211,6 @@ private:
void _solve_chain();
};
+#endif // _3D_DISABLED
+
#endif // SKELETON_IK_H
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 5c79741682..d61bd97c2a 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -1423,6 +1423,9 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_custom_bg_color", "idx", "custom_bg_color"), &ItemList::set_item_custom_bg_color);
ClassDB::bind_method(D_METHOD("get_item_custom_bg_color", "idx"), &ItemList::get_item_custom_bg_color);
+ ClassDB::bind_method(D_METHOD("set_item_custom_fg_color", "idx", "custom_fg_color"), &ItemList::set_item_custom_fg_color);
+ ClassDB::bind_method(D_METHOD("get_item_custom_fg_color", "idx"), &ItemList::get_item_custom_fg_color);
+
ClassDB::bind_method(D_METHOD("set_item_tooltip_enabled", "idx", "enable"), &ItemList::set_item_tooltip_enabled);
ClassDB::bind_method(D_METHOD("is_item_tooltip_enabled", "idx"), &ItemList::is_item_tooltip_enabled);
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index e81813d7a5..436dda41a4 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -1071,22 +1071,26 @@ void PopupMenu::activate_item(int p_item) {
pop = Object::cast_to<PopupMenu>(next);
}
- emit_signal("id_pressed", id);
- emit_signal("index_pressed", p_item);
-
// Hides popup by default; unless otherwise specified
// by using set_hide_on_item_selection and set_hide_on_checkable_item_selection
+ bool need_hide = true;
+
if (items[p_item].checkable_type) {
if (!hide_on_checkable_item_selection)
- return;
+ need_hide = false;
} else if (0 < items[p_item].max_states) {
if (!hide_on_multistate_item_selection)
- return;
+ need_hide = false;
} else if (!hide_on_item_selection)
- return;
+ need_hide = false;
+
+ emit_signal("id_pressed", id);
+ emit_signal("index_pressed", p_item);
- hide();
+ if (need_hide) {
+ hide();
+ }
}
void PopupMenu::remove_item(int p_idx) {
@@ -1099,6 +1103,7 @@ void PopupMenu::remove_item(int p_idx) {
items.remove(p_idx);
update();
+ minimum_size_changed();
}
void PopupMenu::add_separator(const String &p_text) {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 382bddfb4e..d066814069 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -51,7 +51,6 @@
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
#include "scene/2d/particles_2d.h"
-
#include "scene/2d/path_2d.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/2d/polygon_2d.h"
@@ -366,14 +365,12 @@ void register_scene_types() {
ClassDB::register_class<Spatial>();
ClassDB::register_virtual_class<SpatialGizmo>();
ClassDB::register_class<Skeleton>();
- ClassDB::register_class<SkeletonIK>();
ClassDB::register_class<AnimationPlayer>();
ClassDB::register_class<Tween>();
OS::get_singleton()->yield(); //may take time to init
#ifndef _3D_DISABLED
- ClassDB::register_class<BoneAttachment>();
ClassDB::register_virtual_class<VisualInstance>();
ClassDB::register_virtual_class<GeometryInstance>();
ClassDB::register_class<Camera>();
@@ -438,6 +435,9 @@ void register_scene_types() {
ClassDB::register_class<PhysicalBone>();
ClassDB::register_class<SoftBody>();
+ ClassDB::register_class<SkeletonIK>();
+ ClassDB::register_class<BoneAttachment>();
+
ClassDB::register_class<VehicleBody>();
ClassDB::register_class<VehicleWheel>();
ClassDB::register_class<Area>();
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 875b72159a..143a1438ea 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -34,6 +34,8 @@
void Material::set_next_pass(const Ref<Material> &p_pass) {
+ ERR_FAIL_COND(p_pass == this);
+
if (next_pass == p_pass)
return;
diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h
index dfe48d94cf..c69e44a7da 100644
--- a/scene/resources/physics_material.h
+++ b/scene/resources/physics_material.h
@@ -37,7 +37,7 @@ class PhysicsMaterial : public Resource {
GDCLASS(PhysicsMaterial, Resource);
OBJ_SAVE_TYPE(PhysicsMaterial);
- RES_BASE_EXTENSION("PhyMat");
+ RES_BASE_EXTENSION("phymat");
real_t friction;
bool rough;
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index ca50d0d049..8705033326 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -3875,8 +3875,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
- if (!uniform && (type < TYPE_FLOAT || type > TYPE_VEC4)) {
- _set_error("Invalid type for varying, only float,vec2,vec3,vec4 allowed.");
+ if (!uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) {
+ _set_error("Invalid type for varying, only float,vec2,vec3,vec4,mat2,mat3,mat4 allowed.");
return ERR_PARSE_ERROR;
}