diff options
112 files changed, 1693 insertions, 364 deletions
diff --git a/core/image.cpp b/core/image.cpp index 11429b8782..2f2d7efd7c 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -47,6 +47,7 @@ const char *Image::format_names[Image::FORMAT_MAX] = {  	"RGBA8",  	"RGBA4444",  	"RGBA5551", +	"RGB10A2",  	"RFloat", //float  	"RGFloat",  	"RGBFloat", @@ -112,6 +113,7 @@ int Image::get_format_pixel_size(Format p_format) {  		case FORMAT_RGBA8: return 4;  		case FORMAT_RGBA4444: return 2;  		case FORMAT_RGBA5551: return 2; +		case FORMAT_RGB10A2: return 4;  		case FORMAT_RF:  			return 4; //float  		case FORMAT_RGF: return 8; @@ -1978,6 +1980,15 @@ Color Image::get_pixel(int p_x, int p_y) const {  			float a = ((u >> 15) & 0x1) / 1.0;  			return Color(r, g, b, a);  		} break; +		case FORMAT_RGB10A2: { + +			uint32_t u = ((uint32_t *)ptr)[ofs]; +			float r = (u & 0x3FF) / 1023.0; +			float g = ((u >> 10) & 0x3FF) / 1023.0; +			float b = ((u >> 20) & 0x3FF) / 1023.0; +			float a = ((u >> 30) & 0x3) / 3.0; +			return Color(r, g, b, a); +		} break;  		case FORMAT_RF: {  			float r = ((float *)ptr)[ofs]; @@ -2123,6 +2134,18 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) {  			((uint16_t *)ptr)[ofs] = rgba;  		} break; +		case FORMAT_RGB10A2: { + +			uint32_t rgba = 0; + +			rgba = uint32_t(CLAMP(p_color.r * 1023.0, 0, 1023)); +			rgba |= uint32_t(CLAMP(p_color.g * 1023.0, 0, 1023)) << 10; +			rgba |= uint32_t(CLAMP(p_color.b * 1023.0, 0, 1023)) << 20; +			rgba |= uint32_t(CLAMP(p_color.a * 3.0, 0, 3)) << 30; + +			((uint32_t *)ptr)[ofs] = rgba; + +		} break;  		case FORMAT_RF: {  			((float *)ptr)[ofs] = p_color.r; @@ -2300,6 +2323,7 @@ void Image::_bind_methods() {  	BIND_ENUM_CONSTANT(FORMAT_RGBA8);  	BIND_ENUM_CONSTANT(FORMAT_RGBA4444);  	BIND_ENUM_CONSTANT(FORMAT_RGBA5551); +	BIND_ENUM_CONSTANT(FORMAT_RGB10A2);  	BIND_ENUM_CONSTANT(FORMAT_RF); //float  	BIND_ENUM_CONSTANT(FORMAT_RGF);  	BIND_ENUM_CONSTANT(FORMAT_RGBF); diff --git a/core/image.h b/core/image.h index 767f3c6ac5..efb62a6a29 100644 --- a/core/image.h +++ b/core/image.h @@ -68,6 +68,7 @@ public:  		FORMAT_RGBA8,  		FORMAT_RGBA4444,  		FORMAT_RGBA5551, +		FORMAT_RGB10A2,  		FORMAT_RF, //float  		FORMAT_RGF,  		FORMAT_RGBF, diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index b2145eca85..a3b48320b1 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -30,6 +30,17 @@  #include "geometry.h"  #include "print_string.h" +bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) { + +	Vector<int> indices = Geometry::triangulate_polygon(p_polygon); +	for (int j = 0; j + 3 <= indices.size(); j += 3) { +		int i1 = indices[j], i2 = indices[j + 1], i3 = indices[j + 2]; +		if (Geometry::is_point_in_triangle(p_point, p_polygon[i1], p_polygon[i2], p_polygon[i3])) +			return true; +	} +	return false; +} +  void Geometry::MeshData::optimize_vertices() {  	Map<int, int> vtx_remap; diff --git a/core/math/geometry.h b/core/math/geometry.h index ac1a22289c..fefdd88794 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -512,6 +512,9 @@ public:  		return true;  	} + +	static bool is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon); +  	static Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2 &p_point, const Vector2 *p_segment) {  		Vector2 p = p_point - p_segment[0]; diff --git a/core/os/input.cpp b/core/os/input.cpp index 2795b11243..a44adde425 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -84,7 +84,7 @@ void Input::_bind_methods() {  	ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);  	ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press);  	ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release); -	ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(Vector2())); +	ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));  	ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);  	BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); @@ -92,6 +92,24 @@ void Input::_bind_methods() {  	BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);  	BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED); +	BIND_ENUM_CONSTANT(CURSOR_ARROW); +	BIND_ENUM_CONSTANT(CURSOR_IBEAM); +	BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND); +	BIND_ENUM_CONSTANT(CURSOR_CROSS); +	BIND_ENUM_CONSTANT(CURSOR_WAIT); +	BIND_ENUM_CONSTANT(CURSOR_BUSY); +	BIND_ENUM_CONSTANT(CURSOR_DRAG); +	BIND_ENUM_CONSTANT(CURSOR_CAN_DROP); +	BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN); +	BIND_ENUM_CONSTANT(CURSOR_VSIZE); +	BIND_ENUM_CONSTANT(CURSOR_HSIZE); +	BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE); +	BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE); +	BIND_ENUM_CONSTANT(CURSOR_MOVE); +	BIND_ENUM_CONSTANT(CURSOR_VSPLIT); +	BIND_ENUM_CONSTANT(CURSOR_HSPLIT); +	BIND_ENUM_CONSTANT(CURSOR_HELP); +  	ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")));  } diff --git a/core/os/input.h b/core/os/input.h index 608484ccd0..140d11de4d 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -51,6 +51,28 @@ public:  		MOUSE_MODE_CONFINED  	}; +#undef CursorShape +	enum CursorShape { +		CURSOR_ARROW, +		CURSOR_IBEAM, +		CURSOR_POINTING_HAND, +		CURSOR_CROSS, +		CURSOR_WAIT, +		CURSOR_BUSY, +		CURSOR_DRAG, +		CURSOR_CAN_DROP, +		CURSOR_FORBIDDEN, +		CURSOR_VSIZE, +		CURSOR_HSIZE, +		CURSOR_BDIAGSIZE, +		CURSOR_FDIAGSIZE, +		CURSOR_MOVE, +		CURSOR_VSPLIT, +		CURSOR_HSPLIT, +		CURSOR_HELP, +		CURSOR_MAX +	}; +  	void set_mouse_mode(MouseMode p_mode);  	MouseMode get_mouse_mode() const; @@ -96,7 +118,7 @@ public:  	virtual bool is_emulating_touchscreen() const = 0; -	virtual void set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot = Vector2()) = 0; +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;  	virtual void set_mouse_in_window(bool p_in_window) = 0;  	virtual String get_joy_button_string(int p_button) = 0; @@ -110,5 +132,6 @@ public:  };  VARIANT_ENUM_CAST(Input::MouseMode); +VARIANT_ENUM_CAST(Input::CursorShape);  #endif // INPUT_H diff --git a/core/os/os.h b/core/os/os.h index 5dc39b52d6..c9c228cfaf 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -325,6 +325,7 @@ public:  	virtual int get_virtual_keyboard_height() const;  	virtual void set_cursor_shape(CursorShape p_shape) = 0; +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) = 0;  	virtual bool get_swap_ok_cancel() { return false; }  	virtual void dump_memory_to_file(const char *p_file); diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index a2505cbc53..a0a55ce86e 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -129,15 +129,21 @@ static ObjectID safe_get_instance_id(const Variant &p_v) {  void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_variable) {  	packet_peer_stream->put_var(p_name); + +	Variant var = p_variable; +	if (p_variable.get_type() == Variant::OBJECT && !ObjectDB::instance_validate(p_variable)) { +		var = Variant(); +	} +  	int len = 0; -	Error err = encode_variant(p_variable, NULL, len); +	Error err = encode_variant(var, NULL, len);  	if (err != OK)  		ERR_PRINT("Failed to encode variant");  	if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size  		packet_peer_stream->put_var(Variant());  	} else { -		packet_peer_stream->put_var(p_variable); +		packet_peer_stream->put_var(var);  	}  } diff --git a/core/variant_call.cpp b/core/variant_call.cpp index a2794e7052..81e823b5db 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -101,9 +101,10 @@ struct _VariantCall {  				const Variant *newargs[VARIANT_ARG_MAX];  				for (int i = 0; i < p_argcount; i++)  					newargs[i] = p_args[i]; -				int defargcount = def_argcount; +				// fill in any remaining parameters with defaults +				int first_default_arg = arg_count - def_argcount;  				for (int i = p_argcount; i < arg_count; i++) -					newargs[i] = &default_args[defargcount - (i - p_argcount) - 1]; //default arguments +					newargs[i] = &default_args[i - first_default_arg];  #ifdef DEBUG_ENABLED  				if (!verify_arguments(newargs, r_error))  					return; diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml index bee2cdf387..cd05c83347 100644 --- a/doc/classes/@GDScript.xml +++ b/doc/classes/@GDScript.xml @@ -535,7 +535,7 @@  			<argument index="0" name="path" type="String">  			</argument>  			<description> -				Loads a resource from the filesystem located at 'path'. Note: resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path". +				Loads a resource from the filesystem located at [code]path[/code]. Note: resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path".  				[codeblock]  				# load a scene called main located in the root of the project directory  				var main = load("res://main.tscn") @@ -866,9 +866,10 @@  			<argument index="0" name="s" type="float">  			</argument>  			<description> -				Returns sign of [code]s[/code] -1 or 1. +				Returns the sign of [code]s[/code]: -1 or 1. Returns 0 if [code]s[/code] is 0.  				[codeblock]  				sign(-6) # returns -1 +				sign(0)  # returns 0  				sign(6)  # returns 1  				[/codeblock]  			</description> diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index de5dc18702..6e8b760966 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -93,6 +93,14 @@  		<constant name="MARGIN_BOTTOM" value="3" enum="Margin">  			Bottom margin, used usually for [Control] or [StyleBox] derived classes.  		</constant> +		<constant name="CORNER_TOP_LEFT" value="0" enum="Corner"> +		</constant> +		<constant name="CORNER_TOP_RIGHT" value="1" enum="Corner"> +		</constant> +		<constant name="CORNER_BOTTOM_RIGHT" value="2" enum="Corner"> +		</constant> +		<constant name="CORNER_BOTTOM_LEFT" value="3" enum="Corner"> +		</constant>  		<constant name="VERTICAL" value="1" enum="Orientation">  			General vertical alignment, used usually for [Separator], [ScrollBar], [Slider], etc.  		</constant> @@ -1385,5 +1393,57 @@  		<constant name="TYPE_MAX" value="27" enum="Variant.Type">  			Marker for end of type constants.  		</constant> +		<constant name="OP_EQUAL" value="0" enum="Variant.Operator"> +		</constant> +		<constant name="OP_NOT_EQUAL" value="1" enum="Variant.Operator"> +		</constant> +		<constant name="OP_LESS" value="2" enum="Variant.Operator"> +		</constant> +		<constant name="OP_LESS_EQUAL" value="3" enum="Variant.Operator"> +		</constant> +		<constant name="OP_GREATER" value="4" enum="Variant.Operator"> +		</constant> +		<constant name="OP_GREATER_EQUAL" value="5" enum="Variant.Operator"> +		</constant> +		<constant name="OP_ADD" value="6" enum="Variant.Operator"> +		</constant> +		<constant name="OP_SUBTRACT" value="7" enum="Variant.Operator"> +		</constant> +		<constant name="OP_MULTIPLY" value="8" enum="Variant.Operator"> +		</constant> +		<constant name="OP_DIVIDE" value="9" enum="Variant.Operator"> +		</constant> +		<constant name="OP_NEGATE" value="10" enum="Variant.Operator"> +		</constant> +		<constant name="OP_POSITIVE" value="11" enum="Variant.Operator"> +		</constant> +		<constant name="OP_MODULE" value="12" enum="Variant.Operator"> +		</constant> +		<constant name="OP_STRING_CONCAT" value="13" enum="Variant.Operator"> +		</constant> +		<constant name="OP_SHIFT_LEFT" value="14" enum="Variant.Operator"> +		</constant> +		<constant name="OP_SHIFT_RIGHT" value="15" enum="Variant.Operator"> +		</constant> +		<constant name="OP_BIT_AND" value="16" enum="Variant.Operator"> +		</constant> +		<constant name="OP_BIT_OR" value="17" enum="Variant.Operator"> +		</constant> +		<constant name="OP_BIT_XOR" value="18" enum="Variant.Operator"> +		</constant> +		<constant name="OP_BIT_NEGATE" value="19" enum="Variant.Operator"> +		</constant> +		<constant name="OP_AND" value="20" enum="Variant.Operator"> +		</constant> +		<constant name="OP_OR" value="21" enum="Variant.Operator"> +		</constant> +		<constant name="OP_XOR" value="22" enum="Variant.Operator"> +		</constant> +		<constant name="OP_NOT" value="23" enum="Variant.Operator"> +		</constant> +		<constant name="OP_IN" value="24" enum="Variant.Operator"> +		</constant> +		<constant name="OP_MAX" value="25" enum="Variant.Operator"> +		</constant>  	</constants>  </class> diff --git a/doc/classes/ARVRServer.xml b/doc/classes/ARVRServer.xml index ffe6c35240..7f9eedce50 100644 --- a/doc/classes/ARVRServer.xml +++ b/doc/classes/ARVRServer.xml @@ -14,7 +14,7 @@  		<method name="center_on_hmd">  			<return type="void">  			</return> -			<argument index="0" name="rotation_mode" type="bool"> +			<argument index="0" name="rotation_mode" type="int" enum="ARVRServer.RotationMode">  			</argument>  			<argument index="1" name="keep_height" type="bool">  			</argument> diff --git a/doc/classes/AStar.xml b/doc/classes/AStar.xml index e0e3261edf..08ac12736a 100644 --- a/doc/classes/AStar.xml +++ b/doc/classes/AStar.xml @@ -171,7 +171,7 @@  		<method name="get_point_connections">  			<return type="PoolIntArray">  			</return> -			<argument index="0" name="arg0" type="int"> +			<argument index="0" name="id" type="int">  			</argument>  			<description>  				Returns an array with the ids of the points that form the connect with the given point. diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/BakedLightmap.xml index b351aeac05..b23b608589 100644 --- a/doc/classes/BakedLightmap.xml +++ b/doc/classes/BakedLightmap.xml @@ -27,38 +27,28 @@  		</method>  	</methods>  	<members> -		<member name="bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="BakedLightmap.BakeMode"> +		<member name="bake_cell_size" type="float" setter="set_bake_cell_size" getter="get_bake_cell_size">  		</member> -		<member name="bake_quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="BakedLightmap.BakeQuality"> +		<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">  		</member> -		<member name="bake_subdiv" type="int" setter="set_bake_subdiv" getter="get_bake_subdiv" enum="BakedLightmap.Subdiv"> +		<member name="bake_hdr" type="bool" setter="set_hdr" getter="is_hdr">  		</member> -		<member name="capture_subdiv" type="int" setter="set_capture_subdiv" getter="get_capture_subdiv" enum="BakedLightmap.Subdiv"> +		<member name="bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="BakedLightmap.BakeMode">  		</member> -		<member name="energy" type="float" setter="set_energy" getter="get_energy"> +		<member name="bake_propagation" type="float" setter="set_propagation" getter="get_propagation">  		</member> -		<member name="extents" type="Vector3" setter="set_extents" getter="get_extents"> +		<member name="bake_quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="BakedLightmap.BakeQuality">  		</member> -		<member name="hdr" type="bool" setter="set_hdr" getter="is_hdr"> +		<member name="capture_cell_size" type="float" setter="set_capture_cell_size" getter="get_capture_cell_size">  		</member>  		<member name="image_path" type="String" setter="set_image_path" getter="get_image_path">  		</member>  		<member name="light_data" type="BakedLightmapData" setter="set_light_data" getter="get_light_data">  		</member> -		<member name="propagation" type="float" setter="set_propagation" getter="get_propagation"> -		</member>  	</members>  	<constants> -		<constant name="SUBDIV_128" value="0" enum="Subdiv"> -		</constant> -		<constant name="SUBDIV_256" value="1" enum="Subdiv"> -		</constant> -		<constant name="SUBDIV_512" value="2" enum="Subdiv"> -		</constant> -		<constant name="SUBDIV_1024" value="3" enum="Subdiv"> -		</constant> -		<constant name="SUBDIV_MAX" value="4" enum="Subdiv"> -		</constant>  		<constant name="BAKE_QUALITY_LOW" value="0" enum="BakeQuality">  		</constant>  		<constant name="BAKE_QUALITY_MEDIUM" value="1" enum="BakeQuality"> diff --git a/doc/classes/Camera.xml b/doc/classes/Camera.xml index 91c9ecc774..c2ae9101e1 100644 --- a/doc/classes/Camera.xml +++ b/doc/classes/Camera.xml @@ -150,9 +150,6 @@  		<member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset">  			The horizontal (Y) offset of the Camear viewport.  		</member> -		<member name="vaspect" type="bool" setter="set_vaspect" getter="get_vaspect"> -			A boolean representation of [member keep_aspect] in which [code]true[/code] is equivalent to [code]KEEP_WIDTH[/code]. -		</member>  	</members>  	<constants>  		<constant name="PROJECTION_PERSPECTIVE" value="0" enum="Projection"> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 54eaf6cc7a..230978950b 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -314,6 +314,22 @@  				Loads an image from file [code]path[/code].  			</description>  		</method> +		<method name="load_jpg_from_buffer"> +			<return type="int" enum="Error"> +			</return> +			<argument index="0" name="buffer" type="PoolByteArray"> +			</argument> +			<description> +			</description> +		</method> +		<method name="load_png_from_buffer"> +			<return type="int" enum="Error"> +			</return> +			<argument index="0" name="buffer" type="PoolByteArray"> +			</argument> +			<description> +			</description> +		</method>  		<method name="lock">  			<return type="void">  			</return> @@ -430,65 +446,67 @@  		</constant>  		<constant name="FORMAT_RGBA5551" value="7" enum="Format">  		</constant> -		<constant name="FORMAT_RF" value="8" enum="Format"> +		<constant name="FORMAT_RGB10A2" value="8" enum="Format"> +		</constant> +		<constant name="FORMAT_RF" value="9" enum="Format">  		</constant> -		<constant name="FORMAT_RGF" value="9" enum="Format"> +		<constant name="FORMAT_RGF" value="10" enum="Format">  		</constant> -		<constant name="FORMAT_RGBF" value="10" enum="Format"> +		<constant name="FORMAT_RGBF" value="11" enum="Format">  		</constant> -		<constant name="FORMAT_RGBAF" value="11" enum="Format"> +		<constant name="FORMAT_RGBAF" value="12" enum="Format">  		</constant> -		<constant name="FORMAT_RH" value="12" enum="Format"> +		<constant name="FORMAT_RH" value="13" enum="Format">  		</constant> -		<constant name="FORMAT_RGH" value="13" enum="Format"> +		<constant name="FORMAT_RGH" value="14" enum="Format">  		</constant> -		<constant name="FORMAT_RGBH" value="14" enum="Format"> +		<constant name="FORMAT_RGBH" value="15" enum="Format">  		</constant> -		<constant name="FORMAT_RGBAH" value="15" enum="Format"> +		<constant name="FORMAT_RGBAH" value="16" enum="Format">  		</constant> -		<constant name="FORMAT_RGBE9995" value="16" enum="Format"> +		<constant name="FORMAT_RGBE9995" value="17" enum="Format">  		</constant> -		<constant name="FORMAT_DXT1" value="17" enum="Format"> +		<constant name="FORMAT_DXT1" value="18" enum="Format">  		</constant> -		<constant name="FORMAT_DXT3" value="18" enum="Format"> +		<constant name="FORMAT_DXT3" value="19" enum="Format">  		</constant> -		<constant name="FORMAT_DXT5" value="19" enum="Format"> +		<constant name="FORMAT_DXT5" value="20" enum="Format">  		</constant> -		<constant name="FORMAT_RGTC_R" value="20" enum="Format"> +		<constant name="FORMAT_RGTC_R" value="21" enum="Format">  		</constant> -		<constant name="FORMAT_RGTC_RG" value="21" enum="Format"> +		<constant name="FORMAT_RGTC_RG" value="22" enum="Format">  		</constant> -		<constant name="FORMAT_BPTC_RGBA" value="22" enum="Format"> +		<constant name="FORMAT_BPTC_RGBA" value="23" enum="Format">  		</constant> -		<constant name="FORMAT_BPTC_RGBF" value="23" enum="Format"> +		<constant name="FORMAT_BPTC_RGBF" value="24" enum="Format">  		</constant> -		<constant name="FORMAT_BPTC_RGBFU" value="24" enum="Format"> +		<constant name="FORMAT_BPTC_RGBFU" value="25" enum="Format">  		</constant> -		<constant name="FORMAT_PVRTC2" value="25" enum="Format"> +		<constant name="FORMAT_PVRTC2" value="26" enum="Format">  		</constant> -		<constant name="FORMAT_PVRTC2A" value="26" enum="Format"> +		<constant name="FORMAT_PVRTC2A" value="27" enum="Format">  		</constant> -		<constant name="FORMAT_PVRTC4" value="27" enum="Format"> +		<constant name="FORMAT_PVRTC4" value="28" enum="Format">  		</constant> -		<constant name="FORMAT_PVRTC4A" value="28" enum="Format"> +		<constant name="FORMAT_PVRTC4A" value="29" enum="Format">  		</constant> -		<constant name="FORMAT_ETC" value="29" enum="Format"> +		<constant name="FORMAT_ETC" value="30" enum="Format">  		</constant> -		<constant name="FORMAT_ETC2_R11" value="30" enum="Format"> +		<constant name="FORMAT_ETC2_R11" value="31" enum="Format">  		</constant> -		<constant name="FORMAT_ETC2_R11S" value="31" enum="Format"> +		<constant name="FORMAT_ETC2_R11S" value="32" enum="Format">  		</constant> -		<constant name="FORMAT_ETC2_RG11" value="32" enum="Format"> +		<constant name="FORMAT_ETC2_RG11" value="33" enum="Format">  		</constant> -		<constant name="FORMAT_ETC2_RG11S" value="33" enum="Format"> +		<constant name="FORMAT_ETC2_RG11S" value="34" enum="Format">  		</constant> -		<constant name="FORMAT_ETC2_RGB8" value="34" enum="Format"> +		<constant name="FORMAT_ETC2_RGB8" value="35" enum="Format">  		</constant> -		<constant name="FORMAT_ETC2_RGBA8" value="35" enum="Format"> +		<constant name="FORMAT_ETC2_RGBA8" value="36" enum="Format">  		</constant> -		<constant name="FORMAT_ETC2_RGB8A1" value="36" enum="Format"> +		<constant name="FORMAT_ETC2_RGB8A1" value="37" enum="Format">  		</constant> -		<constant name="FORMAT_MAX" value="37" enum="Format"> +		<constant name="FORMAT_MAX" value="38" enum="Format">  		</constant>  		<constant name="INTERPOLATE_NEAREST" value="0" enum="Interpolation">  		</constant> diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index 1200ac5170..79dc45fa1f 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -275,9 +275,12 @@  			</return>  			<argument index="0" name="image" type="Resource">  			</argument> -			<argument index="1" name="hotspot" type="Vector2" default="Vector2( 0, 0 )"> +			<argument index="1" name="shape" type="int" enum="Input.CursorShape" default="0"> +			</argument> +			<argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">  			</argument>  			<description> +				Set a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified. See enum [code]CURSOR_*[/code] for the list of shapes.  			</description>  		</method>  		<method name="set_mouse_mode"> @@ -347,5 +350,39 @@  		</constant>  		<constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode">  		</constant> +		<constant name="CURSOR_ARROW" value="0" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_IBEAM" value="1" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_POINTING_HAND" value="2" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_CROSS" value="3" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_WAIT" value="4" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_BUSY" value="5" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_DRAG" value="6" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_CAN_DROP" value="7" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_FORBIDDEN" value="8" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_VSIZE" value="9" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_HSIZE" value="10" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_BDIAGSIZE" value="11" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_FDIAGSIZE" value="12" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_MOVE" value="13" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_VSPLIT" value="14" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_HSPLIT" value="15" enum="CursorShape"> +		</constant> +		<constant name="CURSOR_HELP" value="16" enum="CursorShape"> +		</constant>  	</constants>  </class> diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml index cc31da0627..a8abe60f78 100644 --- a/doc/classes/InputEvent.xml +++ b/doc/classes/InputEvent.xml @@ -28,13 +28,6 @@  				Returns a [String] representation of the event.  			</description>  		</method> -		<method name="get_id" qualifiers="const"> -			<return type="int"> -			</return> -			<description> -				Returns the event's ID. -			</description> -		</method>  		<method name="is_action" qualifiers="const">  			<return type="bool">  			</return> @@ -83,14 +76,6 @@  				Returns [code]true[/code] if this input event is pressed. Not relevant for the event types [code]MOUSE_MOTION[/code], [code]SCREEN_DRAG[/code] or [code]NONE[/code].  			</description>  		</method> -		<method name="set_id"> -			<return type="void"> -			</return> -			<argument index="0" name="id" type="int"> -			</argument> -			<description> -			</description> -		</method>  		<method name="shortcut_match" qualifiers="const">  			<return type="bool">  			</return> diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml index 22231cfdf3..af681c9456 100644 --- a/doc/classes/MenuButton.xml +++ b/doc/classes/MenuButton.xml @@ -18,6 +18,14 @@  				Return the [PopupMenu] contained in this button.  			</description>  		</method> +		<method name="set_disable_shortcuts"> +			<return type="void"> +			</return> +			<argument index="0" name="disabled" type="bool"> +			</argument> +			<description> +			</description> +		</method>  	</methods>  	<signals>  		<signal name="about_to_show"> diff --git a/doc/classes/Physics2DServer.xml b/doc/classes/Physics2DServer.xml index 67f5f84a49..8bad396b84 100644 --- a/doc/classes/Physics2DServer.xml +++ b/doc/classes/Physics2DServer.xml @@ -216,7 +216,7 @@  			<argument index="2" name="disable" type="bool">  			</argument>  			<description> -				Disables a given shape in this area if [code]disable is true[/code] +				Disables a given shape in an area.  			</description>  		</method>  		<method name="area_set_shape_transform"> @@ -638,7 +638,7 @@  			<argument index="2" name="enable" type="bool">  			</argument>  			<description> -				Enables one way collision on body if [code]enable is true[/code]. +				Enables one way collision on body if [code]enable[/code] is [code]true[/code].  			</description>  		</method>  		<method name="body_set_shape_disabled"> @@ -651,7 +651,7 @@  			<argument index="2" name="disable" type="bool">  			</argument>  			<description> -				Disables shape in body if [code]disable is true[/code]. +				Disables shape in body if [code]disable[/code] is [code]true[/code].  			</description>  		</method>  		<method name="body_set_shape_metadata"> @@ -1135,6 +1135,12 @@  		<constant name="JOINT_DAMPED_SPRING" value="2" enum="JointType">  			Constant to create damped spring joints.  		</constant> +		<constant name="JOINT_PARAM_BIAS" value="0" enum="JointParam"> +		</constant> +		<constant name="JOINT_PARAM_MAX_BIAS" value="1" enum="JointParam"> +		</constant> +		<constant name="JOINT_PARAM_MAX_FORCE" value="2" enum="JointParam"> +		</constant>  		<constant name="DAMPED_STRING_REST_LENGTH" value="0" enum="DampedStringParam">  			Set the resting length of the spring joint. The joint will always try to go to back this length when pulled apart.  		</constant> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index a78fe03cab..3a4b843b06 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -302,6 +302,14 @@  			<description>  			</description>  		</method> +		<method name="set_quit_on_go_back"> +			<return type="void"> +			</return> +			<argument index="0" name="enabled" type="bool"> +			</argument> +			<description> +			</description> +		</method>  		<method name="set_refuse_new_network_connections">  			<return type="void">  			</return> @@ -402,13 +410,13 @@  		</signal>  	</signals>  	<constants> -		<constant name="GROUP_CALL_DEFAULT" value="0" enum="CallGroupFlags"> +		<constant name="GROUP_CALL_DEFAULT" value="0" enum="GroupCallFlags">  		</constant> -		<constant name="GROUP_CALL_REVERSE" value="1" enum="CallGroupFlags"> +		<constant name="GROUP_CALL_REVERSE" value="1" enum="GroupCallFlags">  		</constant> -		<constant name="GROUP_CALL_REALTIME" value="2" enum="CallGroupFlags"> +		<constant name="GROUP_CALL_REALTIME" value="2" enum="GroupCallFlags">  		</constant> -		<constant name="GROUP_CALL_UNIQUE" value="4" enum="CallGroupFlags"> +		<constant name="GROUP_CALL_UNIQUE" value="4" enum="GroupCallFlags">  		</constant>  		<constant name="STRETCH_MODE_DISABLED" value="0" enum="StretchMode">  		</constant> diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml index 81b0b3d0c3..1e1a8d516e 100644 --- a/doc/classes/ScriptEditor.xml +++ b/doc/classes/ScriptEditor.xml @@ -12,11 +12,11 @@  		<method name="can_drop_data_fw" qualifiers="const">  			<return type="bool">  			</return> -			<argument index="0" name="arg0" type="Vector2"> +			<argument index="0" name="point" type="Vector2">  			</argument> -			<argument index="1" name="arg1" type="Variant"> +			<argument index="1" name="data" type="Variant">  			</argument> -			<argument index="2" name="arg2" type="Control"> +			<argument index="2" name="from" type="Control">  			</argument>  			<description>  			</description> @@ -24,11 +24,11 @@  		<method name="drop_data_fw">  			<return type="void">  			</return> -			<argument index="0" name="arg0" type="Vector2"> +			<argument index="0" name="point" type="Vector2">  			</argument> -			<argument index="1" name="arg1" type="Variant"> +			<argument index="1" name="data" type="Variant">  			</argument> -			<argument index="2" name="arg2" type="Control"> +			<argument index="2" name="from" type="Control">  			</argument>  			<description>  			</description> @@ -43,9 +43,9 @@  		<method name="get_drag_data_fw">  			<return type="Variant">  			</return> -			<argument index="0" name="arg0" type="Vector2"> +			<argument index="0" name="point" type="Vector2">  			</argument> -			<argument index="1" name="arg1" type="Control"> +			<argument index="1" name="from" type="Control">  			</argument>  			<description>  			</description> diff --git a/doc/classes/Spatial.xml b/doc/classes/Spatial.xml index 7940e4065e..d0addcf9f9 100644 --- a/doc/classes/Spatial.xml +++ b/doc/classes/Spatial.xml @@ -34,7 +34,7 @@  				Returns the current [World] resource this Spatial node is registered to.  			</description>  		</method> -		<method name="rotate_object_local"> +		<method name="global_rotate">  			<return type="void">  			</return>  			<argument index="0" name="axis" type="Vector3"> @@ -42,27 +42,15 @@  			<argument index="1" name="angle" type="float">  			</argument>  			<description> -				Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in object-local coordinate system. +				Rotates the global (world) transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in global coordinate system.  			</description>  		</method> -		<method name="scale_object_local"> +		<method name="global_scale">  			<return type="void">  			</return>  			<argument index="0" name="scale" type="Vector3">  			</argument>  			<description> -				Scales the local transformation by given 3D scale factors in object-local coordinate system. -			</description> -		</method> -		<method name="global_rotate"> -			<return type="void"> -			</return> -			<argument index="0" name="axis" type="Vector3"> -			</argument> -			<argument index="1" name="angle" type="float"> -			</argument> -			<description> -				Rotates the global (world) transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in global coordinate system.  			</description>  		</method>  		<method name="global_translate"> @@ -151,6 +139,17 @@  				Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians.  			</description>  		</method> +		<method name="rotate_object_local"> +			<return type="void"> +			</return> +			<argument index="0" name="axis" type="Vector3"> +			</argument> +			<argument index="1" name="angle" type="float"> +			</argument> +			<description> +				Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in object-local coordinate system. +			</description> +		</method>  		<method name="rotate_x">  			<return type="void">  			</return> @@ -178,6 +177,15 @@  				Rotates the local transformation around the Z axis by angle in radians.  			</description>  		</method> +		<method name="scale_object_local"> +			<return type="void"> +			</return> +			<argument index="0" name="scale" type="Vector3"> +			</argument> +			<description> +				Scales the local transformation by given 3D scale factors in object-local coordinate system. +			</description> +		</method>  		<method name="set_as_toplevel">  			<return type="void">  			</return> @@ -264,6 +272,14 @@  				Changes the node's position by given offset [Vector3].  			</description>  		</method> +		<method name="translate_object_local"> +			<return type="void"> +			</return> +			<argument index="0" name="offset" type="Vector3"> +			</argument> +			<description> +			</description> +		</method>  		<method name="update_gizmo">  			<return type="void">  			</return> diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml index d757b6f2d8..8ecd9e5816 100644 --- a/doc/classes/StreamPeer.xml +++ b/doc/classes/StreamPeer.xml @@ -105,7 +105,7 @@  			<return type="int">  			</return>  			<description> -				Get an unsigned 16 bit value from the stream. +				Get an unsigned 64 bit value from the stream.  			</description>  		</method>  		<method name="get_u8"> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index ab722a24c3..f4d80c46b4 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -213,7 +213,7 @@  		<method name="is_line_hidden" qualifiers="const">  			<return type="bool">  			</return> -			<argument index="0" name="arg0" type="int"> +			<argument index="0" name="line" type="int">  			</argument>  			<description>  			</description> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index a09f6b6dc3..daba0a0fc1 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -185,7 +185,7 @@  		<method name="update_bitmask_area">  			<return type="void">  			</return> -			<argument index="0" name="arg0" type="Vector2"> +			<argument index="0" name="position" type="Vector2">  			</argument>  			<description>  				Applies autotiling rules to the cell (and its adjacent cells) referenced by its grid-based X and Y coordinates. diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index 3dbf172c5a..716f89eab6 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -39,7 +39,7 @@  		<method name="autotile_get_bitmask_mode" qualifiers="const">  			<return type="int" enum="TileSet.BitmaskMode">  			</return> -			<argument index="0" name="arg0" type="int"> +			<argument index="0" name="id" type="int">  			</argument>  			<description>  			</description> @@ -47,9 +47,9 @@  		<method name="autotile_set_bitmask_mode">  			<return type="void">  			</return> -			<argument index="0" name="mode" type="int"> +			<argument index="0" name="id" type="int">  			</argument> -			<argument index="1" name="arg1" type="int" enum="TileSet.BitmaskMode"> +			<argument index="1" name="mode" type="int" enum="TileSet.BitmaskMode">  			</argument>  			<description>  			</description> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index 11bd3b3b86..e26082c47e 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -41,6 +41,8 @@  			</return>  			<argument index="0" name="parent" type="Object" default="null">  			</argument> +			<argument index="1" name="idx" type="int" default="-1"> +			</argument>  			<description>  				Create an item in the tree and add it as the last child of [code]parent[/code]. If parent is not given, it will be added as the root's last child, or it'll the be the root itself if the tree is empty.  			</description> diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 5ce544ecfb..365840b2d8 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -193,6 +193,13 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_  			r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1;  		} break; +		case Image::FORMAT_RGB10A2: { + +			r_gl_internal_format = GL_RGB10_A2; +			r_gl_format = GL_RGBA; +			r_gl_type = GL_UNSIGNED_INT_2_10_10_10_REV; + +		} break;  		case Image::FORMAT_RF: {  			r_gl_internal_format = GL_R32F; @@ -6090,7 +6097,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) {  			color_internal_format = GL_RGB10_A2;  			color_format = GL_RGBA;  			color_type = GL_UNSIGNED_INT_2_10_10_10_REV; -			image_format = Image::FORMAT_RGBA8; +			image_format = Image::FORMAT_RGB10A2;  		} else {  			color_internal_format = GL_RGBA8; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 256fe302d7..4b59656903 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1251,7 +1251,7 @@ CodeTextEditor::CodeTextEditor() {  	error = memnew(Label);  	status_bar->add_child(error); -	error->set_clip_text(true); //do not change, or else very long errors can push the whole container to the right +	error->set_autowrap(true);  	error->set_valign(Label::VALIGN_CENTER);  	error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));  	error->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 1d6d933924..7fa4776141 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -131,7 +131,8 @@ EditorAbout::EditorAbout() {  	Label *about_text = memnew(Label);  	about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER); -	about_text->set_text(VERSION_FULL_NAME + hash + String::utf8("\n\xc2\xa9 2007-2018 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2017 ") + +	about_text->set_text(VERSION_FULL_NAME + hash + +						 String::utf8("\n\xc2\xa9 2007-2018 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2018 ") +  						 TTR("Godot Engine contributors") + "\n");  	hbc->add_child(about_text); diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index f2882561aa..c50995fc2b 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -77,12 +77,27 @@ static Ref<BitmapFont> make_font(int p_height, int p_ascent, int p_valign, int p  	Ref<DynamicFont> m_name;                                    \  	m_name.instance();                                          \  	m_name->set_size(m_size);                                   \ -	m_name->set_font_data(DefaultFont);                         \ +	if (CustomFont.is_valid()) {                                \ +		m_name->set_font_data(CustomFont);                      \ +		m_name->add_fallback(DefaultFont);                      \ +	} else {                                                    \ +		m_name->set_font_data(DefaultFont);                     \ +	}                                                           \  	m_name->set_spacing(DynamicFont::SPACING_TOP, -EDSCALE);    \  	m_name->set_spacing(DynamicFont::SPACING_BOTTOM, -EDSCALE); \  	MAKE_FALLBACKS(m_name);  void editor_register_fonts(Ref<Theme> p_theme) { +	/* Custom font */ + +	String custom_font = EditorSettings::get_singleton()->get("interface/editor/custom_font"); +	Ref<DynamicFontData> CustomFont; +	if (custom_font.length() > 0) { +		CustomFont.instance(); +		CustomFont->set_font_path(custom_font); +		CustomFont->set_force_autohinter(true); //just looks better..i think? +	} +  	/* Droid Sans */  	Ref<DynamicFontData> DefaultFont; diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index cf19af7ef6..1b885adf37 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -29,6 +29,7 @@  /*************************************************************************/  #include "editor_log.h" +#include "core/os/keyboard.h"  #include "editor_node.h"  #include "scene/gui/center_container.h"  #include "scene/resources/dynamic_font.h" @@ -154,6 +155,7 @@ EditorLog::EditorLog() {  	clearbutton = memnew(Button);  	hb->add_child(clearbutton);  	clearbutton->set_text(TTR("Clear")); +	clearbutton->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_K));  	clearbutton->connect("pressed", this, "_clear_request");  	log = memnew(RichTextLabel); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index bd37e7d0be..b308d28dba 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4419,10 +4419,11 @@ void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) {  	String to_path = ProjectSettings::get_singleton()->globalize_path(get_filesystem_dock()->get_current_path());  	DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); +	Vector<String> just_copy = String("ttf,otf").split(",");  	for (int i = 0; i < p_files.size(); i++) {  		String from = p_files[i]; -		if (!ResourceFormatImporter::get_singleton()->can_be_imported(from)) { +		if (!ResourceFormatImporter::get_singleton()->can_be_imported(from) && (just_copy.find(from.get_extension().to_lower()) < 0)) {  			continue;  		}  		String to = to_path.plus_file(from.get_file()); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 5a16ec7eab..dc82a02f46 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -277,7 +277,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {  	_initial_set("interface/editor/source_font_size", 14);  	hints["interface/editor/source_font_size"] = PropertyInfo(Variant::INT, "interface/editor/source_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);  	_initial_set("interface/editor/custom_font", ""); -	hints["interface/editor/custom_font"] = PropertyInfo(Variant::STRING, "interface/editor/custom_font", PROPERTY_HINT_GLOBAL_FILE, "*.font,*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); +	hints["interface/editor/custom_font"] = PropertyInfo(Variant::STRING, "interface/editor/custom_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);  	_initial_set("interface/editor/dim_editor_on_dialog_popup", true);  	_initial_set("interface/editor/dim_amount", 0.6f);  	hints["interface/editor/dim_amount"] = PropertyInfo(Variant::REAL, "interface/editor/dim_amount", PROPERTY_HINT_RANGE, "0,1,0.01", PROPERTY_USAGE_DEFAULT); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 3644893663..b19d015455 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1135,16 +1135,5 @@ Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) {  		theme = create_editor_theme(p_theme);  	} -	String global_font = EditorSettings::get_singleton()->get("interface/editor/custom_font"); -	if (global_font != "") { -		Ref<Font> fnt = ResourceLoader::load(global_font); -		if (fnt.is_valid()) { -			if (!theme.is_valid()) { -				theme.instance(); -			} -			theme->set_default_theme_font(fnt); -		} -	} -  	return theme;  } diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 949455ff98..b18cd6b747 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -819,7 +819,7 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin  	DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);  	print_line("Duplicating " + old_path + " -> " + new_path); -	Error err = da->copy(old_path, new_path); +	Error err = p_item.is_file ? da->copy(old_path, new_path) : da->copy_dir(old_path, new_path);  	if (err == OK) {  		//Move/Rename any corresponding import settings too  		if (p_item.is_file && FileAccess::exists(old_path + ".import")) { @@ -980,10 +980,12 @@ void FileSystemDock::_duplicate_operation_confirm() {  		return;  	} -	String old_path = to_duplicate.path.ends_with("/") ? to_duplicate.path.substr(0, to_duplicate.path.length() - 1) : to_rename.path; -	String new_path = old_path.get_base_dir().plus_file(new_name); -	if (old_path == new_path) { -		return; +	String new_path; +	String base_dir = to_duplicate.path.get_base_dir(); +	if (to_duplicate.is_file) { +		new_path = base_dir.plus_file(new_name); +	} else { +		new_path = base_dir.substr(0, base_dir.find_last("/")) + "/" + new_name;  	}  	//Present a more user friendly warning for name conflict @@ -995,7 +997,7 @@ void FileSystemDock::_duplicate_operation_confirm() {  	}  	memdelete(da); -	_try_duplicate_item(to_duplicate, new_name); +	_try_duplicate_item(to_duplicate, new_path);  	//Rescan everything  	print_line("call rescan!"); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 53b52c5f1b..052817f40a 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -612,6 +612,7 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no  	if (Object::cast_to<Viewport>(p_node))  		return; +	const real_t grab_distance = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);  	CanvasItem *c = Object::cast_to<CanvasItem>(p_node);  	for (int i = p_node->get_child_count() - 1; i >= 0; i--) { @@ -630,9 +631,12 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no  	if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !Object::cast_to<CanvasLayer>(c)) {  		Rect2 rect = c->_edit_get_rect(); -		Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos); +		Transform2D to_local = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse(); +		Point2 local_pos = to_local.xform(p_pos); +		const real_t local_grab_distance = (to_local.xform(p_pos + Vector2(grab_distance, 0)) - local_pos).length(); +		Rect2 local_pos_rect = Rect2(local_pos, Vector2(0, 0)).grow(local_grab_distance); -		if (rect.has_point(local_pos)) { +		if (rect.intersects(local_pos_rect) && c->_edit_is_selected_on_click(local_pos, local_grab_distance)) {  			Node2D *node = Object::cast_to<Node2D>(c);  			_SelectResult res; @@ -3464,7 +3468,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {  			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {  				CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); -				if (!canvas_item || !canvas_item->is_visible_in_tree()) +				if (!canvas_item || !canvas_item->is_inside_tree())  					continue;  				if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) @@ -3482,7 +3486,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {  			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {  				CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); -				if (!canvas_item || !canvas_item->is_visible_in_tree()) +				if (!canvas_item || !canvas_item->is_inside_tree())  					continue;  				if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) @@ -3502,7 +3506,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {  			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {  				CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); -				if (!canvas_item || !canvas_item->is_visible_in_tree()) +				if (!canvas_item || !canvas_item->is_inside_tree())  					continue;  				if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) @@ -3520,7 +3524,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {  			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {  				CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); -				if (!canvas_item || !canvas_item->is_visible_in_tree()) +				if (!canvas_item || !canvas_item->is_inside_tree())  					continue;  				if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 73fd64f8db..bc29c92d7f 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1027,6 +1027,15 @@ void ScriptEditor::_menu_option(int p_option) {  			case FILE_COPY_PATH: {  				_copy_script_path();  			} break; +			case SHOW_IN_FILE_SYSTEM: { +				ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(tab_container->get_current_tab())); +				Ref<Script> script = se->get_edited_script(); +				FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock(); +				file_system_dock->navigate_to_path(script->get_path()); +				// Ensure that the FileSystem dock is visible. +				TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control(); +				tab_container->set_current_tab(file_system_dock->get_position_in_parent()); +			} break;  			case CLOSE_DOCS: {  				_close_docs_tab();  			} break; @@ -2164,7 +2173,7 @@ void ScriptEditor::_make_script_list_context_menu() {  		context_menu->add_separator();  		context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/copy_path"), FILE_COPY_PATH);  		context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); - +		context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/show_in_file_system"), SHOW_IN_FILE_SYSTEM);  		Ref<Script> scr = se->get_edited_script();  		if (!scr.is_null() && scr->is_tool()) {  			context_menu->add_separator(); @@ -2613,6 +2622,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {  	file_menu->get_popup()->add_separator();  	file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), FILE_TOOL_RELOAD_SOFT);  	file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH); +	file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/show_in_file_system", TTR("Show In File System")), SHOW_IN_FILE_SYSTEM);  	file_menu->get_popup()->add_separator();  	file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Prev"), KEY_MASK_ALT | KEY_LEFT), WINDOW_PREV); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 3305147442..d90cf7b912 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -137,6 +137,7 @@ class ScriptEditor : public PanelContainer {  		CLOSE_ALL,  		CLOSE_OTHER_TABS,  		TOGGLE_SCRIPTS_PANEL, +		SHOW_IN_FILE_SYSTEM,  		FILE_COPY_PATH,  		FILE_TOOL_RELOAD,  		FILE_TOOL_RELOAD_SOFT, diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index da507db5da..eccb11ba12 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -333,7 +333,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) {  	autotile_list = memnew(ItemList);  	autotile_list->set_v_size_flags(SIZE_EXPAND_FILL);  	autotile_list->set_h_size_flags(SIZE_EXPAND_FILL); -	autotile_list->set_custom_minimum_size(Size2(02, 200)); +	autotile_list->set_custom_minimum_size(Size2(10, 200));  	autotile_list->connect("item_selected", this, "_on_autotile_selected");  	split->add_child(autotile_list); @@ -531,7 +531,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) {  	main_vb->add_child(toolbar); -	ScrollContainer *scroll = memnew(ScrollContainer); +	scroll = memnew(ScrollContainer);  	main_vb->add_child(scroll);  	scroll->set_v_size_flags(SIZE_EXPAND_FILL); @@ -619,6 +619,7 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) {  			tool_containers[TOOLBAR_BITMASK]->hide();  			tool_containers[TOOLBAR_SHAPE]->show();  			tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.")); +			current_shape = PoolVector2Array();  			spin_priority->hide();  		} break;  		default: { @@ -1061,20 +1062,43 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {  							} else {  								int t_id = get_current_tile();  								if (t_id >= 0) { -									Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(t_id); -									for (int i = 0; i < sd.size(); i++) { -										if (sd[i].autotile_coord == edited_shape_coord) { -											Ref<ConvexPolygonShape2D> shape = sd[i].shape; +									if (edit_mode == EDITMODE_COLLISION) { +										Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(t_id); +										for (int i = 0; i < sd.size(); i++) { +											if (sd[i].autotile_coord == edited_shape_coord) { +												Ref<ConvexPolygonShape2D> shape = sd[i].shape; + +												if (!shape.is_null()) { +													sd.remove(i); +													tile_set->tile_set_shapes(get_current_tile(), sd); +													edited_collision_shape = Ref<Shape2D>(); +													workspace->update(); +												} +												break; +											} +										} +									} else if (edit_mode == EDITMODE_OCCLUSION) { +										Map<Vector2, Ref<OccluderPolygon2D> > map = tile_set->autotile_get_light_oclusion_map(t_id); +										for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { +											if (E->key() == edited_shape_coord) { +												tile_set->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); +												break; +											} +										} -											if (!shape.is_null()) { -												sd.remove(i); -												tile_set->tile_set_shapes(get_current_tile(), sd); -												edited_collision_shape = Ref<Shape2D>(); -												current_shape.resize(0); -												workspace->update(); +										edited_occlusion_shape = Ref<OccluderPolygon2D>(); +										workspace->update(); +									} else if (edit_mode == EDITMODE_NAVIGATION) { +										Map<Vector2, Ref<NavigationPolygon> > map = tile_set->autotile_get_navigation_map(t_id); +										for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { +											if (E->key() == edited_shape_coord) { +												tile_set->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord); +												break;  											} -											break;  										} + +										edited_navigation_shape = Ref<NavigationPolygon>(); +										workspace->update();  									}  								} @@ -1095,6 +1119,16 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {  				}  			} break;  		} + +		//Drag Middle Mouse +		if (mm.is_valid()) { +			if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) { + +				Vector2 dragged(mm->get_relative().x, mm->get_relative().y); +				scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x); +				scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x); +			} +		}  	}  } @@ -1453,11 +1487,20 @@ void AutotileEditor::close_shape(const Vector2 &shape_anchor) {  			Ref<ConvexPolygonShape2D> shape = memnew(ConvexPolygonShape2D);  			Vector<Vector2> segments; +			float p_total = 0;  			for (int i = 0; i < current_shape.size(); i++) {  				segments.push_back(current_shape[i] - shape_anchor); + +				if (i != current_shape.size() - 1) +					p_total += ((current_shape[i + 1].x - current_shape[i].x) * (-current_shape[i + 1].y + (-current_shape[i].y))); +				else +					p_total += ((current_shape[0].x - current_shape[i].x) * (-current_shape[0].y + (-current_shape[i].y)));  			} +			if (p_total < 0) +				segments.invert(); +  			shape->set_points(segments);  			tile_set->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord); diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 7d9558d4e7..0f66f04cb1 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -86,6 +86,7 @@ class AutotileEditor : public Control {  	int current_item_index;  	Sprite *preview; +	ScrollContainer *scroll;  	Control *workspace_container;  	Control *workspace;  	Button *tool_editmode[EDITMODE_MAX]; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 0411656857..eb5cec2a2e 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -89,33 +89,50 @@ private:  	String created_folder_path;  	void set_message(const String &p_msg, MessageType p_type = MESSAGE_SUCCESS) { +  		msg->set_text(p_msg); -		if (p_msg == "") { -			status_btn->set_icon(get_icon("StatusSuccess", "EditorIcons")); -			return; -		} -		msg->hide(); +		Ref<Texture> current_icon = status_btn->get_icon(); +  		switch (p_type) { -			case MESSAGE_ERROR: + +			case MESSAGE_ERROR: { +  				msg->add_color_override("font_color", get_color("error_color", "Editor")); -				status_btn->set_icon(get_icon("StatusError", "EditorIcons")); -				msg->show(); -				break; -			case MESSAGE_WARNING: +				Ref<Texture> new_icon = get_icon("StatusError", "EditorIcons"); +				if (current_icon != new_icon) { + +					status_btn->set_icon(new_icon); +					msg->show(); +				} +			} break; +			case MESSAGE_WARNING: { +  				msg->add_color_override("font_color", get_color("warning_color", "Editor")); -				status_btn->set_icon(get_icon("StatusWarning", "EditorIcons")); -				break; -			case MESSAGE_SUCCESS: +				Ref<Texture> new_icon = get_icon("StatusWarning", "EditorIcons"); +				if (current_icon != new_icon) { + +					status_btn->set_icon(new_icon); +					if (current_icon != get_icon("StatusSuccess", "EditorIcons")) +						msg->hide(); +				} +			} break; +			case MESSAGE_SUCCESS: { +  				msg->add_color_override("font_color", get_color("success_color", "Editor")); -				status_btn->set_icon(get_icon("StatusSuccess", "EditorIcons")); -				break; +				Ref<Texture> new_icon = get_icon("StatusSuccess", "EditorIcons"); +				if (current_icon != new_icon) { + +					status_btn->set_icon(new_icon); +					msg->hide(); +				} +			} break;  		} + +		set_size(Size2(500, 0) * EDSCALE);  	}  	String _test_path() { -		set_message(" "); -		get_ok()->set_disabled(true);  		DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);  		String valid_path;  		if (d->change_dir(project_path->get_text()) == OK) { @@ -127,6 +144,7 @@ private:  		if (valid_path == "") {  			set_message(TTR("The path does not exist."), MESSAGE_ERROR);  			memdelete(d); +			get_ok()->set_disabled(true);  			return "";  		} @@ -136,6 +154,7 @@ private:  				set_message(TTR("Please choose a 'project.godot' file."), MESSAGE_ERROR);  				memdelete(d); +				get_ok()->set_disabled(true);  				return "";  			} @@ -155,19 +174,22 @@ private:  			d->list_dir_end();  			if (!is_empty) { +  				set_message(TTR("Your project will be created in a non empty folder (you might want to create a new folder)."), MESSAGE_WARNING); +				memdelete(d); +				get_ok()->set_disabled(false); +				return valid_path;  			} -		} else { - -			if (d->file_exists("project.godot")) { +		} else if (d->file_exists("project.godot")) { -				set_message(TTR("Please choose a folder that does not contain a 'project.godot' file."), MESSAGE_ERROR); -				memdelete(d); -				return ""; -			} +			set_message(TTR("Please choose a folder that does not contain a 'project.godot' file."), MESSAGE_ERROR); +			memdelete(d); +			get_ok()->set_disabled(true); +			return "";  		} +		set_message(TTR("That's a BINGO!"));  		memdelete(d);  		get_ok()->set_disabled(false);  		return valid_path; @@ -213,7 +235,6 @@ private:  		}  		String sp = p.simplify_path();  		project_path->set_text(sp); -		set_message(" "); // just so it does not disappear  		get_ok()->call_deferred("grab_focus");  	} @@ -242,21 +263,32 @@ private:  	void _create_folder() { -		if (project_name->get_text() == "" || created_folder_path != "") { +		if (project_name->get_text() == "" || created_folder_path != "")  			return; -		}  		DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);  		if (d->change_dir(project_path->get_text()) == OK) { +  			if (!d->dir_exists(project_name->get_text())) { +  				if (d->make_dir(project_name->get_text()) == OK) { +  					d->change_dir(project_name->get_text());  					project_path->set_text(d->get_current_dir());  					created_folder_path = d->get_current_dir();  					create_dir->set_disabled(true); +				} else { + +					dialog_error->set_text(TTR("Couldn't create folder.")); +					dialog_error->popup_centered_minsize();  				} +			} else { + +				dialog_error->set_text(TTR("There is already a folder in this path with the specified name.")); +				dialog_error->popup_centered_minsize();  			}  		} +  		memdelete(d);  	} @@ -337,6 +369,7 @@ private:  					if (!pkg) {  						dialog_error->set_text(TTR("Error opening package file, not in zip format.")); +						dialog_error->popup_centered_minsize();  						return;  					} @@ -448,7 +481,10 @@ private:  	}  	void _toggle_message() { +  		msg->set_visible(!msg->is_visible()); +		if (!msg->is_visible()) +			set_size(Size2(500, 0) * EDSCALE);  	}  	void cancel_pressed() { @@ -457,6 +493,15 @@ private:  		project_path->clear();  		project_name->clear(); + +		if (status_btn->get_icon() == get_icon("StatusError", "EditorIcons")) +			msg->show(); +	} + +	void _notification(int p_what) { + +		if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) +			_remove_created_folder();  	}  protected: @@ -558,7 +603,7 @@ public:  			_test_path();  		} -		popup_centered(Size2(500, 125) * EDSCALE); +		popup_centered(Size2(500, 0) * EDSCALE);  	}  	ProjectDialog() { @@ -610,7 +655,6 @@ public:  		pphb->add_child(browse);  		msg = memnew(Label); -		msg->set_text(TTR("That's a BINGO!"));  		msg->set_align(Label::ALIGN_CENTER);  		msg->hide();  		vb->add_child(msg); @@ -652,19 +696,20 @@ struct ProjectItem {  void ProjectManager::_notification(int p_what) { -	if (p_what == NOTIFICATION_ENTER_TREE) { - -		Engine::get_singleton()->set_editor_hint(false); - -	} else if (p_what == NOTIFICATION_READY) { +	switch (p_what) { +		case NOTIFICATION_ENTER_TREE: { -		if (scroll_childs->get_child_count() == 0) { -			open_templates->popup_centered_minsize(); -		} +			Engine::get_singleton()->set_editor_hint(false); +		} break; +		case NOTIFICATION_READY: { -	} else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { +			if (scroll_childs->get_child_count() == 0) +				open_templates->popup_centered_minsize(); +		} break; +		case NOTIFICATION_VISIBILITY_CHANGED: { -		set_process_unhandled_input(is_visible_in_tree()); +			set_process_unhandled_input(is_visible_in_tree()); +		} break;  	}  } @@ -1214,7 +1259,6 @@ void ProjectManager::_run_project_confirm() {  		Error err = OS::get_singleton()->execute(exec, args, false, &pid);  		ERR_FAIL_COND(err);  	} -	//get_scene()->quit(); do not quit  }  void ProjectManager::_run_project() { @@ -1556,9 +1600,6 @@ ProjectManager::ProjectManager() {  	scroll_childs->set_h_size_flags(SIZE_EXPAND_FILL);  	scroll->add_child(scroll_childs); -	//HBoxContainer *hb = memnew( HBoxContainer ); -	//vb->add_child(hb); -  	Button *open = memnew(Button);  	open->set_text(TTR("Edit"));  	tree_vb->add_child(open); @@ -1663,7 +1704,7 @@ ProjectManager::ProjectManager() {  	cancel->connect("pressed", this, "_exit_dialog");  	vb->add_child(cc); -	// +	//////////////////////////////////////////////////////////////  	language_restart_ask = memnew(ConfirmationDialog);  	language_restart_ask->get_ok()->set_text(TTR("Restart Now")); @@ -1772,12 +1813,9 @@ void ProjectListFilter::_filter_option_selected(int p_idx) {  }  void ProjectListFilter::_notification(int p_what) { -	switch (p_what) { -		case NOTIFICATION_ENTER_TREE: { -			clear_search_button->set_icon(get_icon("Close", "EditorIcons")); -		} break; -	} +	if (p_what == NOTIFICATION_ENTER_TREE) +		clear_search_button->set_icon(get_icon("Close", "EditorIcons"));  }  void ProjectListFilter::_bind_methods() { diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 4fe7bef9f7..f1a5aa4654 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1686,6 +1686,45 @@ void ScriptEditorDebugger::_clear_remote_objects() {  	remote_objects.clear();  } +void ScriptEditorDebugger::_clear_errors_list() { + +	error_list->clear(); +	error_count = 0; +	_notification(NOTIFICATION_PROCESS); +} + +// Right click on specific file(s) or folder(s). +void ScriptEditorDebugger::_error_list_item_rmb_selected(int p_item, const Vector2 &p_pos) { + +	item_menu->clear(); +	item_menu->set_size(Size2(1, 1)); + +	// Allow specific actions only on one item. +	bool single_item_selected = error_list->get_selected_items().size() == 1; + +	if (single_item_selected) { +		item_menu->add_icon_item(get_icon("CopyNodePath", "EditorIcons"), TTR("Copy Error"), ITEM_MENU_COPY_ERROR); +	} + +	if (item_menu->get_item_count() > 0) { +		item_menu->set_position(error_list->get_global_position() + p_pos); +		item_menu->popup(); +	} +} + +void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) { + +	switch (p_option) { + +		case ITEM_MENU_COPY_ERROR: { +			String title = error_list->get_item_text(error_list->get_current()); +			String desc = error_list->get_item_tooltip(error_list->get_current()); + +			OS::get_singleton()->set_clipboard(title + "\n----------\n" + desc); +		} break; +	} +} +  void ScriptEditorDebugger::_bind_methods() {  	ClassDB::bind_method(D_METHOD("_stack_dump_frame_selected"), &ScriptEditorDebugger::_stack_dump_frame_selected); @@ -1705,6 +1744,10 @@ void ScriptEditorDebugger::_bind_methods() {  	ClassDB::bind_method(D_METHOD("_error_stack_selected"), &ScriptEditorDebugger::_error_stack_selected);  	ClassDB::bind_method(D_METHOD("_profiler_activate"), &ScriptEditorDebugger::_profiler_activate);  	ClassDB::bind_method(D_METHOD("_profiler_seeked"), &ScriptEditorDebugger::_profiler_seeked); +	ClassDB::bind_method(D_METHOD("_clear_errors_list"), &ScriptEditorDebugger::_clear_errors_list); + +	ClassDB::bind_method(D_METHOD("_error_list_item_rmb_selected"), &ScriptEditorDebugger::_error_list_item_rmb_selected); +	ClassDB::bind_method(D_METHOD("_item_menu_id_pressed"), &ScriptEditorDebugger::_item_menu_id_pressed);  	ClassDB::bind_method(D_METHOD("_paused"), &ScriptEditorDebugger::_paused); @@ -1829,9 +1872,31 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {  		error_split = memnew(HSplitContainer);  		VBoxContainer *errvb = memnew(VBoxContainer); +		HBoxContainer *errhb = memnew(HBoxContainer);  		errvb->set_h_size_flags(SIZE_EXPAND_FILL); +		Label *velb = memnew(Label(TTR("Errors:"))); +		velb->set_h_size_flags(SIZE_EXPAND_FILL); +		errhb->add_child(velb); + +		clearbutton = memnew(Button); +		clearbutton->set_text(TTR("Clear")); +		clearbutton->connect("pressed", this, "_clear_errors_list"); +		errhb->add_child(clearbutton); +		errvb->add_child(errhb); +  		error_list = memnew(ItemList); -		errvb->add_margin_child(TTR("Errors:"), error_list, true); +		error_list->set_v_size_flags(SIZE_EXPAND_FILL); +		error_list->set_h_size_flags(SIZE_EXPAND_FILL); +		error_list->connect("item_rmb_selected", this, "_error_list_item_rmb_selected"); +		error_list->set_allow_rmb_select(true); +		error_list->set_autoscroll_to_bottom(true); + +		item_menu = memnew(PopupMenu); +		item_menu->connect("id_pressed", this, "_item_menu_id_pressed"); +		error_list->add_child(item_menu); + +		errvb->add_child(error_list); +  		error_split->add_child(errvb);  		errvb = memnew(VBoxContainer); diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index e380a56b18..7f8348d82f 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -62,6 +62,10 @@ class ScriptEditorDebugger : public Control {  		MESSAGE_SUCCESS,  	}; +	enum ItemMenu { +		ITEM_MENU_COPY_ERROR, +	}; +  	AcceptDialog *msgdialog;  	Button *debugger_button; @@ -85,6 +89,8 @@ class ScriptEditorDebugger : public Control {  	ItemList *error_list;  	ItemList *error_stack;  	Tree *inspect_scene_tree; +	Button *clearbutton; +	PopupMenu *item_menu;  	int error_count;  	int last_error_count; @@ -175,6 +181,10 @@ class ScriptEditorDebugger : public Control {  	void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj);  	void _clear_remote_objects(); +	void _clear_errors_list(); + +	void _error_list_item_rmb_selected(int p_item, const Vector2 &p_pos); +	void _item_menu_id_pressed(int p_option);  protected:  	void _notification(int p_what); diff --git a/main/input_default.cpp b/main/input_default.cpp index 5026b8bb39..c3454d86f3 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -497,26 +497,16 @@ bool InputDefault::is_emulating_touchscreen() const {  	return emulate_touch;  } -void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot) { -	/* no longer supported, leaving this for reference to anyone who might want to implement hardware cursors +void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +	if (Engine::get_singleton()->is_editor_hint()) +		return; +  	if (custom_cursor == p_cursor)  		return;  	custom_cursor = p_cursor; -	if (p_cursor.is_null()) { -		set_mouse_mode(MOUSE_MODE_VISIBLE); -		//removed, please insist us to implement hardare cursors -		//VisualServer::get_singleton()->cursor_set_visible(false); -	} else { -		Ref<AtlasTexture> atex = custom_cursor; -		Rect2 region = atex.is_valid() ? atex->get_region() : Rect2(); -		set_mouse_mode(MOUSE_MODE_HIDDEN); -		VisualServer::get_singleton()->cursor_set_visible(true); -		VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(), p_hotspot, 0, region); -		VisualServer::get_singleton()->cursor_set_pos(get_mouse_position()); -	} -	*/ +	OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);  }  void InputDefault::set_mouse_in_window(bool p_in_window) { diff --git a/main/input_default.h b/main/input_default.h index 62ba0b0c32..3d9a809325 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -225,7 +225,7 @@ public:  	void set_emulate_touch(bool p_emulate);  	virtual bool is_emulating_touchscreen() const; -	virtual void set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot = Vector2()); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());  	virtual void set_mouse_in_window(bool p_in_window);  	void parse_mapping(String p_mapping); diff --git a/main/main.cpp b/main/main.cpp index 5936a323d4..ac68fe1296 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1107,7 +1107,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {  		if (cursor.is_valid()) {  			//print_line("loaded ok");  			Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot"); -			Input::get_singleton()->set_custom_mouse_cursor(cursor, hotspot); +			Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);  		}  	}  #ifdef TOOLS_ENABLED diff --git a/misc/dist/osx_tools.app/Contents/Info.plist b/misc/dist/osx_tools.app/Contents/Info.plist index 2a4914ec75..895eda14db 100755 --- a/misc/dist/osx_tools.app/Contents/Info.plist +++ b/misc/dist/osx_tools.app/Contents/Info.plist @@ -9,7 +9,7 @@  	<key>CFBundleName</key>  	<string>Godot</string>  	<key>CFBundleGetInfoString</key> -	<string>(c) 2007-2018 Juan Linietsky, Ariel Manzur./string> +	<string>(c) 2007-2018 Juan Linietsky, Ariel Manzur.</string>  	<key>CFBundleIconFile</key>  	<string>Godot.icns</string>  	<key>CFBundleIdentifier</key> @@ -25,7 +25,7 @@  	<key>CFBundleVersion</key>  	<string>3.0-dev</string>  	<key>NSHumanReadableCopyright</key> -	<string>© 2007-2018 Juan Linietsky, Ariel Manzur./string> +	<string>© 2007-2018 Juan Linietsky, Ariel Manzur.</string>  	<key>LSMinimumSystemVersion</key>  	<string>10.9.0</string>  	<key>LSMinimumSystemVersionByArchitecture</key> diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index d97f355400..3023b489e5 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -605,7 +605,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a  #ifdef DEBUG_ENABLED  				if (!valid) {  					if (src->has_method(*index)) { -						err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "'). Did you mean '." + index->operator String() + "()' ?"; +						err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "'). Did you mean '." + index->operator String() + "()' or funcref(obj, \"" + index->operator String() + "\") ?";  					} else {  						err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "').";  					} diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index e9bb90631d..c30c6d77b9 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -95,6 +95,22 @@  				Returns whether or not grid items are centered on the Z axis.  			</description>  		</method> +		<method name="get_collision_layer_bit" qualifiers="const"> +			<return type="bool"> +			</return> +			<argument index="0" name="bit" type="int"> +			</argument> +			<description> +			</description> +		</method> +		<method name="get_collision_mask_bit" qualifiers="const"> +			<return type="bool"> +			</return> +			<argument index="0" name="bit" type="int"> +			</argument> +			<description> +			</description> +		</method>  		<method name="get_meshes">  			<return type="Array">  			</return> @@ -222,6 +238,26 @@  			<description>  			</description>  		</method> +		<method name="set_collision_layer_bit"> +			<return type="void"> +			</return> +			<argument index="0" name="bit" type="int"> +			</argument> +			<argument index="1" name="value" type="bool"> +			</argument> +			<description> +			</description> +		</method> +		<method name="set_collision_mask_bit"> +			<return type="void"> +			</return> +			<argument index="0" name="bit" type="int"> +			</argument> +			<argument index="1" name="value" type="bool"> +			</argument> +			<description> +			</description> +		</method>  		<method name="set_octant_size">  			<return type="void">  			</return> @@ -249,6 +285,12 @@  			</description>  		</method>  	</methods> +	<members> +		<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer"> +		</member> +		<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask"> +		</member> +	</members>  	<constants>  		<constant name="INVALID_CELL_ITEM" value="-1">  			Invalid cell item that can be used in [method set_cell_item] to clear cells (or represent an empty cell in [method get_cell_item]). diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index bd37118847..9a03bc410a 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -198,6 +198,58 @@ void GridMap::_get_property_list(List<PropertyInfo> *p_list) const {  	p_list->push_back(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));  } +void GridMap::set_collision_layer(uint32_t p_layer) { + +	collision_layer = p_layer; +	_reset_physic_bodies_collision_filters(); +} + +uint32_t GridMap::get_collision_layer() const { + +	return collision_layer; +} + +void GridMap::set_collision_mask(uint32_t p_mask) { + +	collision_mask = p_mask; +	_reset_physic_bodies_collision_filters(); +} + +uint32_t GridMap::get_collision_mask() const { + +	return collision_mask; +} + +void GridMap::set_collision_mask_bit(int p_bit, bool p_value) { + +	uint32_t mask = get_collision_mask(); +	if (p_value) +		mask |= 1 << p_bit; +	else +		mask &= ~(1 << p_bit); +	set_collision_mask(mask); +} + +bool GridMap::get_collision_mask_bit(int p_bit) const { + +	return get_collision_mask() & (1 << p_bit); +} + +void GridMap::set_collision_layer_bit(int p_bit, bool p_value) { + +	uint32_t mask = get_collision_layer(); +	if (p_value) +		mask |= 1 << p_bit; +	else +		mask &= ~(1 << p_bit); +	set_collision_layer(mask); +} + +bool GridMap::get_collision_layer_bit(int p_bit) const { + +	return get_collision_layer() & (1 << p_bit); +} +  void GridMap::set_theme(const Ref<MeshLibrary> &p_theme) {  	if (!theme.is_null()) @@ -311,6 +363,8 @@ void GridMap::set_cell_item(int p_x, int p_y, int p_z, int p_item, int p_rot) {  		g->dirty = true;  		g->static_body = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC);  		PhysicsServer::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id()); +		PhysicsServer::get_singleton()->body_set_collision_layer(g->static_body, collision_layer); +		PhysicsServer::get_singleton()->body_set_collision_mask(g->static_body, collision_mask);  		SceneTree *st = SceneTree::get_singleton();  		if (st && st->is_debugging_collisions_hint()) { @@ -575,6 +629,13 @@ bool GridMap::_octant_update(const OctantKey &p_key) {  	return false;  } +void GridMap::_reset_physic_bodies_collision_filters() { +	for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) { +		PhysicsServer::get_singleton()->body_set_collision_layer(E->get()->static_body, collision_layer); +		PhysicsServer::get_singleton()->body_set_collision_mask(E->get()->static_body, collision_mask); +	} +} +  void GridMap::_octant_enter_world(const OctantKey &p_key) {  	ERR_FAIL_COND(!octant_map.has(p_key)); @@ -815,6 +876,18 @@ void GridMap::_update_octants_callback() {  void GridMap::_bind_methods() { +	ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &GridMap::set_collision_layer); +	ClassDB::bind_method(D_METHOD("get_collision_layer"), &GridMap::get_collision_layer); + +	ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &GridMap::set_collision_mask); +	ClassDB::bind_method(D_METHOD("get_collision_mask"), &GridMap::get_collision_mask); + +	ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &GridMap::set_collision_mask_bit); +	ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &GridMap::get_collision_mask_bit); + +	ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &GridMap::set_collision_layer_bit); +	ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &GridMap::get_collision_layer_bit); +  	ClassDB::bind_method(D_METHOD("set_theme", "theme"), &GridMap::set_theme);  	ClassDB::bind_method(D_METHOD("get_theme"), &GridMap::get_theme); @@ -855,6 +928,10 @@ void GridMap::_bind_methods() {  	ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes);  	ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1)); +	ADD_GROUP("Collision", "collision_"); +	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); +	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); +  	BIND_CONSTANT(INVALID_CELL_ITEM);  } @@ -1067,6 +1144,9 @@ RID GridMap::get_bake_mesh_instance(int p_idx) {  GridMap::GridMap() { +	collision_layer = 1; +	collision_mask = 1; +  	cell_size = Vector3(2, 2, 2);  	octant_size = 8;  	awaiting_update = false; diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 18a9551edf..7b97fe3183 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -136,6 +136,9 @@ class GridMap : public Spatial {  		OctantKey() { key = 0; }  	}; +	uint32_t collision_layer; +	uint32_t collision_mask; +  	Transform last_transform;  	bool _in_tree; @@ -173,6 +176,7 @@ class GridMap : public Spatial {  		return Vector3(p_key.x, p_key.y, p_key.z) * cell_size * octant_size;  	} +	void _reset_physic_bodies_collision_filters();  	void _octant_enter_world(const OctantKey &p_key);  	void _octant_exit_world(const OctantKey &p_key);  	bool _octant_update(const OctantKey &p_key); @@ -210,6 +214,18 @@ public:  		INVALID_CELL_ITEM = -1  	}; +	void set_collision_layer(uint32_t p_layer); +	uint32_t get_collision_layer() const; + +	void set_collision_mask(uint32_t p_mask); +	uint32_t get_collision_mask() const; + +	void set_collision_layer_bit(int p_bit, bool p_value); +	bool get_collision_layer_bit(int p_bit) const; + +	void set_collision_mask_bit(int p_bit, bool p_value); +	bool get_collision_mask_bit(int p_bit) const; +  	void set_theme(const Ref<MeshLibrary> &p_theme);  	Ref<MeshLibrary> get_theme() const; diff --git a/modules/thekla_unwrap/register_types.cpp b/modules/thekla_unwrap/register_types.cpp index 2dc9217e48..eb11325dde 100644 --- a/modules/thekla_unwrap/register_types.cpp +++ b/modules/thekla_unwrap/register_types.cpp @@ -28,7 +28,9 @@  /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */  /*************************************************************************/  #include "register_types.h" +#include "error_macros.h"  #include "thirdparty/thekla_atlas/thekla/thekla_atlas.h" +  #include <stdio.h>  #include <stdlib.h>  extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y); @@ -74,6 +76,11 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver  	delete[] input_mesh.face_array;  	delete[] input_mesh.vertex_array; +	if (output == NULL) { +		ERR_PRINT("could not generate atlas output mesh"); +		return false; +	} +  	if (err != Thekla::Atlas_Error_Success) {  		printf("error with atlas\n");  	} else { diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 5702134791..2ff3fb6d7a 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -309,9 +309,6 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {  	/* and now we have it all.  initialize decoders */  	if (theora_p) {  		td = th_decode_alloc(&ti, ts); -		printf("Ogg logical stream %lx is Theora %dx%d %.02f fps", -				to.serialno, ti.pic_width, ti.pic_height, -				(double)ti.fps_numerator / ti.fps_denominator);  		px_fmt = ti.pixel_fmt;  		switch (ti.pixel_fmt) {  			case TH_PF_420: printf(" 4:2:0 video\n"); break; @@ -322,9 +319,6 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {  				printf(" video\n  (UNKNOWN Chroma sampling!)\n");  				break;  		} -		if (ti.pic_width != ti.frame_width || ti.pic_height != ti.frame_height) -			printf("  Frame content is %dx%d with offset (%d,%d).\n", -					ti.frame_width, ti.frame_height, ti.pic_x, ti.pic_y);  		th_decode_ctl(td, TH_DECCTL_GET_PPLEVEL_MAX, &pp_level_max,  				sizeof(pp_level_max));  		pp_level = 0; @@ -351,10 +345,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {  	if (vorbis_p) {  		vorbis_synthesis_init(&vd, &vi);  		vorbis_block_init(&vd, &vb); -		fprintf(stderr, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n", -				vo.serialno, vi.channels, vi.rate);  		//_setup(vi.channels, vi.rate); -  	} else {  		/* tear down the partial vorbis setup */  		vorbis_info_clear(&vi); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index dd23a81977..97e81874c9 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -248,6 +248,9 @@ void OS_Android::set_cursor_shape(CursorShape p_shape) {  	//android really really really has no mouse.. how amazing..  } +void OS_Android::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +} +  void OS_Android::main_loop_begin() {  	if (main_loop) diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 744dce7ff1..adfd88b59b 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -182,6 +182,7 @@ public:  	virtual bool can_draw() const;  	virtual void set_cursor_shape(CursorShape p_shape); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);  	void main_loop_begin();  	bool main_loop_iterate(); diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index 3324b33e95..65a220f8ca 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -200,6 +200,10 @@ void OS_Haiku::set_cursor_shape(CursorShape p_shape) {  	//ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED");  } +void OS_Haiku::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +	// TODO +} +  int OS_Haiku::get_screen_count() const {  	// TODO: implement get_screen_count()  	return 1; diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index b4d0add04b..6d69c1997f 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -87,6 +87,7 @@ public:  	virtual Point2 get_mouse_position() const;  	virtual int get_mouse_button_state() const;  	virtual void set_cursor_shape(CursorShape p_shape); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);  	virtual int get_screen_count() const;  	virtual int get_current_screen() const; diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index dcb7b8b1f4..507d4f22db 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -490,6 +490,8 @@ String OSIPhone::get_user_data_dir() const {  	return data_dir;  }; +void OSIPhone::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot){}; +  String OSIPhone::get_name() {  	return "iOS"; diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 7e310e3a03..8e701a7fab 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -173,6 +173,7 @@ public:  	virtual int get_virtual_keyboard_height() const;  	virtual void set_cursor_shape(CursorShape p_shape); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);  	virtual Size2 get_window_size() const; diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index a24bf6c0bc..0411b4e72b 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -41,6 +41,7 @@  #include "servers/visual/rasterizer.h"  #include "servers/visual/visual_server_wrap_mt.h"  #include "servers/visual_server.h" +#include <AppKit/NSCursor.h>  #include <ApplicationServices/ApplicationServices.h>  #undef CursorShape @@ -86,6 +87,7 @@ public:  	id context;  	CursorShape cursor_shape; +	NSCursor *cursors[CURSOR_MAX] = { NULL };  	MouseMode mouse_mode;  	String title; @@ -137,6 +139,7 @@ public:  	virtual void alert(const String &p_alert, const String &p_title = "ALERT!");  	virtual void set_cursor_shape(CursorShape p_shape); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);  	virtual void set_mouse_show(bool p_show);  	virtual void set_mouse_grab(bool p_grab); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 0cd02663da..99c5995d7a 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -577,8 +577,11 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {  		return;  	if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)  		OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER); -	if (OS_OSX::singleton->input) +	if (OS_OSX::singleton->input) {  		OS_OSX::singleton->input->set_mouse_in_window(true); +		OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX; +		OS_OSX::singleton->set_cursor_shape(OS::CURSOR_ARROW); +	}  }  - (void)magnifyWithEvent:(NSEvent *)event { @@ -1240,30 +1243,84 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) {  	if (cursor_shape == p_shape)  		return; -	switch (p_shape) { -		case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break; -		case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break; -		case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break; -		case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break; -		case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break; -		case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break; -		case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break; -		case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break; -		case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break; -		case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break; -		case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break; -		case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break; -		case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break; -		case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break; -		case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break; -		case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break; -		case CURSOR_HELP: [[NSCursor arrowCursor] set]; break; -		default: {}; +	if (cursors[p_shape] != NULL) { +		[cursors[p_shape] set]; +	} else { +		switch (p_shape) { +			case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break; +			case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break; +			case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break; +			case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break; +			case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break; +			case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break; +			case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break; +			case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break; +			case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break; +			case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break; +			case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break; +			case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break; +			case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break; +			case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break; +			case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break; +			case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break; +			case CURSOR_HELP: [[NSCursor arrowCursor] set]; break; +			default: {}; +		}  	}  	cursor_shape = p_shape;  } +void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +	if (p_cursor.is_valid()) { +		Ref<Texture> texture = p_cursor; +		Ref<Image> image = texture->get_data(); + +		int image_size = 32 * 32; + +		ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32); + +		NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc] +				initWithBitmapDataPlanes:NULL +							  pixelsWide:image->get_width() +							  pixelsHigh:image->get_height() +						   bitsPerSample:8 +						 samplesPerPixel:4 +								hasAlpha:YES +								isPlanar:NO +						  colorSpaceName:NSDeviceRGBColorSpace +							 bytesPerRow:image->get_width() * 4 +							bitsPerPixel:32] autorelease]; + +		ERR_FAIL_COND(imgrep == nil); +		uint8_t *pixels = [imgrep bitmapData]; + +		int len = image->get_width() * image->get_height(); +		PoolVector<uint8_t> data = image->get_data(); +		PoolVector<uint8_t>::Read r = data.read(); + +		/* Premultiply the alpha channel */ +		for (int i = 0; i < len; i++) { +			uint8_t alpha = r[i * 4 + 3]; +			pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255); +			pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255); +			pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255); +			pixels[i * 4 + 3] = alpha; +		} + +		NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(image->get_width(), image->get_height())] autorelease]; +		[nsimage addRepresentation:imgrep]; + +		NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)]; + +		cursors[p_shape] = cursor; + +		if (p_shape == CURSOR_ARROW) { +			[cursor set]; +		} +	} +} +  void OS_OSX::set_mouse_show(bool p_show) {  } diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index c34567aaab..13264ed46e 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -179,6 +179,9 @@ void OS_Server::move_window_to_foreground() {  void OS_Server::set_cursor_shape(CursorShape p_shape) {  } +void OS_Server::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +} +  OS::PowerState OS_Server::get_power_state() {  	return power_manager->get_power_state();  } diff --git a/platform/server/os_server.h b/platform/server/os_server.h index c58c48500e..7b7d4a38a8 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -75,6 +75,7 @@ public:  	virtual String get_name();  	virtual void set_cursor_shape(CursorShape p_shape); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);  	virtual void set_mouse_show(bool p_show);  	virtual void set_mouse_grab(bool p_grab); diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index ceccfb281c..603a918cca 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -651,6 +651,10 @@ void OSUWP::set_cursor_shape(CursorShape p_shape) {  	cursor_shape = p_shape;  } +void OSUWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +	// TODO +} +  Error OSUWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {  	return FAILED; diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 7c2371b097..976eda1fe1 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -218,6 +218,7 @@ public:  	virtual String get_clipboard() const;  	void set_cursor_shape(CursorShape p_shape); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);  	void set_icon(const Ref<Image> &p_icon);  	virtual String get_executable_path() const; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 8edc2c5cff..e3af82b629 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1844,10 +1844,125 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) {  		IDC_HELP  	}; -	SetCursor(LoadCursor(hInstance, win_cursors[p_shape])); +	if (cursors[p_shape] != NULL) { +		SetCursor(cursors[p_shape]); +	} else { +		SetCursor(LoadCursor(hInstance, win_cursors[p_shape])); +	}  	cursor_shape = p_shape;  } +void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +	if (p_cursor.is_valid()) { +		Ref<Texture> texture = p_cursor; +		Ref<Image> image = texture->get_data(); + +		UINT image_size = 32 * 32; +		UINT size = sizeof(UINT) * image_size; + +		ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32); + +		// Create the BITMAP with alpha channel +		COLORREF *buffer = (COLORREF *)malloc(sizeof(COLORREF) * image_size); + +		image->lock(); +		for (UINT index = 0; index < image_size; index++) { +			int column_index = floor(index / 32); +			int row_index = index % 32; + +			Color pcColor = image->get_pixel(row_index, column_index); +			*(buffer + index) = image->get_pixel(row_index, column_index).to_argb32(); +		} +		image->unlock(); + +		// Using 4 channels, so 4 * 8 bits +		HBITMAP bitmap = CreateBitmap(32, 32, 1, 4 * 8, buffer); +		COLORREF clrTransparent = -1; + +		// Create the AND and XOR masks for the bitmap +		HBITMAP hAndMask = NULL; +		HBITMAP hXorMask = NULL; + +		GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask); + +		if (NULL == hAndMask || NULL == hXorMask) { +			return; +		} + +		// Finally, create the icon +		ICONINFO iconinfo = { 0 }; +		iconinfo.fIcon = FALSE; +		iconinfo.xHotspot = p_hotspot.x; +		iconinfo.yHotspot = p_hotspot.y; +		iconinfo.hbmMask = hAndMask; +		iconinfo.hbmColor = hXorMask; + +		cursors[p_shape] = CreateIconIndirect(&iconinfo); + +		if (p_shape == CURSOR_ARROW) { +			SetCursor(cursors[p_shape]); +		} + +		if (hAndMask != NULL) { +			DeleteObject(hAndMask); +		} + +		if (hXorMask != NULL) { +			DeleteObject(hXorMask); +		} +	} +} + +void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) { + +	// Get the system display DC +	HDC hDC = GetDC(NULL); + +	// Create helper DC +	HDC hMainDC = CreateCompatibleDC(hDC); +	HDC hAndMaskDC = CreateCompatibleDC(hDC); +	HDC hXorMaskDC = CreateCompatibleDC(hDC); + +	// Get the dimensions of the source bitmap +	BITMAP bm; +	GetObject(hSourceBitmap, sizeof(BITMAP), &bm); + +	// Create the mask bitmaps +	hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color +	hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color + +	// Release the system display DC +	ReleaseDC(NULL, hDC); + +	// Select the bitmaps to helper DC +	HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap); +	HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap); +	HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap); + +	// Assign the monochrome AND mask bitmap pixels so that a pixels of the source bitmap +	// with 'clrTransparent' will be white pixels of the monochrome bitmap +	SetBkColor(hMainDC, clrTransparent); +	BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY); + +	// Assign the color XOR mask bitmap pixels so that a pixels of the source bitmap +	// with 'clrTransparent' will be black and rest the pixels same as corresponding +	// pixels of the source bitmap +	SetBkColor(hXorMaskDC, RGB(0, 0, 0)); +	SetTextColor(hXorMaskDC, RGB(255, 255, 255)); +	BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY); +	BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND); + +	// Deselect bitmaps from the helper DC +	SelectObject(hMainDC, hOldMainBitmap); +	SelectObject(hAndMaskDC, hOldAndMaskBitmap); +	SelectObject(hXorMaskDC, hOldXorMaskBitmap); + +	// Delete the helper DC +	DeleteDC(hXorMaskDC); +	DeleteDC(hAndMaskDC); +	DeleteDC(hMainDC); +} +  Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {  	if (p_blocking && r_pipe) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index d709fb3fe5..9d254ccf27 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -113,6 +113,7 @@ class OS_Windows : public OS {  	bool window_has_focus;  	uint32_t last_button_state; +	HCURSOR cursors[CURSOR_MAX] = { NULL };  	CursorShape cursor_shape;  	InputDefault *input; @@ -244,6 +245,8 @@ public:  	virtual String get_clipboard() const;  	void set_cursor_shape(CursorShape p_shape); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); +	void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);  	void set_icon(const Ref<Image> &p_icon);  	virtual String get_executable_path() const; diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 240d6638a9..e9920b18a4 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -1050,13 +1050,59 @@ void OS_X11::set_window_maximized(bool p_enabled) {  	XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); -	while (p_enabled && !is_window_maximized()) { -		// Wait for effective resizing (so the GLX context is too). +	if (is_window_maximize_allowed()) { +		while (p_enabled && !is_window_maximized()) { +			// Wait for effective resizing (so the GLX context is too). +		}  	}  	maximized = p_enabled;  } +bool OS_X11::is_window_maximize_allowed() { +	Atom property = XInternAtom(x11_display, "_NET_WM_ALLOWED_ACTIONS", False); +	Atom type; +	int format; +	unsigned long len; +	unsigned long remaining; +	unsigned char *data = NULL; + +	int result = XGetWindowProperty( +			x11_display, +			x11_window, +			property, +			0, +			1024, +			False, +			XA_ATOM, +			&type, +			&format, +			&len, +			&remaining, +			&data); + +	if (result == Success) { +		Atom *atoms = (Atom *)data; +		Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False); +		Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False); +		bool found_wm_act_max_horz = false; +		bool found_wm_act_max_vert = false; + +		for (unsigned int i = 0; i < len; i++) { +			if (atoms[i] == wm_act_max_horz) +				found_wm_act_max_horz = true; +			if (atoms[i] == wm_act_max_vert) +				found_wm_act_max_vert = true; + +			if (found_wm_act_max_horz || found_wm_act_max_vert) +				return true; +		} +		XFree(atoms); +	} + +	return false; +} +  bool OS_X11::is_window_maximized() const {  	// Using EWMH -- Extended Window Manager Hints  	Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False); @@ -2205,6 +2251,48 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) {  	current_cursor = p_shape;  } +void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +	if (p_cursor.is_valid()) { +		Ref<Texture> texture = p_cursor; +		Ref<Image> image = texture->get_data(); + +		ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32); + +		// Create the cursor structure +		XcursorImage *cursor_image = XcursorImageCreate(texture->get_width(), texture->get_height()); +		XcursorUInt image_size = 32 * 32; +		XcursorDim size = sizeof(XcursorPixel) * image_size; + +		cursor_image->version = 1; +		cursor_image->size = size; +		cursor_image->xhot = p_hotspot.x; +		cursor_image->yhot = p_hotspot.y; + +		// allocate memory to contain the whole file +		cursor_image->pixels = (XcursorPixel *)malloc(size); + +		image->lock(); + +		for (XcursorPixel index = 0; index < image_size; index++) { +			int column_index = floor(index / 32); +			int row_index = index % 32; + +			*(cursor_image->pixels + index) = image->get_pixel(row_index, column_index).to_argb32(); +		} + +		image->unlock(); + +		ERR_FAIL_COND(cursor_image->pixels == NULL); + +		// Save it for a further usage +		cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image); + +		if (p_shape == CURSOR_ARROW) { +			XDefineCursor(x11_display, x11_window, cursors[p_shape]); +		} +	} +} +  void OS_X11::release_rendering_thread() {  	context_gl->release_current(); diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 59b9c8caa8..04243a9b36 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -200,10 +200,13 @@ protected:  	void _window_changed(XEvent *xevent); +	bool is_window_maximize_allowed(); +  public:  	virtual String get_name();  	virtual void set_cursor_shape(CursorShape p_shape); +	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);  	void set_mouse_mode(MouseMode p_mode);  	MouseMode get_mouse_mode() const; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index e994ebb5aa..1db9e4902a 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -229,6 +229,7 @@ public:  	// Used to resize/move/select the node  	virtual void _edit_set_rect(const Rect2 &p_rect){};  	virtual Rect2 _edit_get_rect() const { return Rect2(-32, -32, 64, 64); }; +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return true; }  	Rect2 _edit_get_item_and_children_rect() const;  	virtual bool _edit_use_rect() const { return false; }; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index eaa650b140..e46bf3c77d 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -248,6 +248,11 @@ Rect2 CollisionPolygon2D::_edit_get_rect() const {  	return aabb;  } +bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	return Geometry::is_point_in_polygon(p_point, Variant(polygon)); +} +  String CollisionPolygon2D::get_configuration_warning() const {  	if (!Object::cast_to<CollisionObject2D>(get_parent())) { diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 4c8b55a9ee..fa7e5e1046 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -70,6 +70,7 @@ public:  	Vector<Point2> get_polygon() const;  	virtual Rect2 _edit_get_rect() const; +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;  	virtual String get_configuration_warning() const; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index 1cadbe83d0..135ede829d 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -163,6 +163,14 @@ Rect2 CollisionShape2D::_edit_get_rect() const {  	return rect;  } +bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	if (!shape.is_valid()) +		return false; + +	return shape->_edit_is_selected_on_click(p_point, p_tolerance); +} +  String CollisionShape2D::get_configuration_warning() const {  	if (!Object::cast_to<CollisionObject2D>(get_parent())) { diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index 833d9ae5cb..921066c5c8 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -52,6 +52,7 @@ protected:  public:  	virtual Rect2 _edit_get_rect() const; +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;  	void set_shape(const Ref<Shape2D> &p_shape);  	Ref<Shape2D> get_shape() const; diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index f108df140f..abc80216d4 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -48,6 +48,32 @@ Line2D::Line2D() :  	_round_precision = 8;  } +Rect2 Line2D::_edit_get_rect() const { + +	if (_points.size() == 0) +		return Rect2(0, 0, 0, 0); +	Vector2 d = Vector2(_width, _width); +	Rect2 aabb = Rect2(_points[0] - d, 2 * d); +	for (int i = 1; i < _points.size(); i++) { +		aabb.expand_to(_points[i] - d); +		aabb.expand_to(_points[i] + d); +	} +	return aabb; +} + +bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	const real_t d = _width / 2 + p_tolerance; +	PoolVector<Vector2>::Read points = _points.read(); +	for (int i = 0; i < _points.size() - 1; i++) { +		Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, &points[i]); +		if (p.distance_to(p_point) <= d) +			return true; +	} + +	return false; +} +  void Line2D::set_points(const PoolVector<Vector2> &p_points) {  	_points = p_points;  	update(); diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 123728ab39..54a4683dc7 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -57,6 +57,9 @@ public:  	Line2D(); +	virtual Rect2 _edit_get_rect() const; +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_points(const PoolVector<Vector2> &p_points);  	PoolVector<Vector2> get_points() const; diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index 9c297db52b..dde41dbf3f 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -35,9 +35,50 @@  #include "thirdparty/misc/triangulator.h" +Rect2 NavigationPolygon::_edit_get_rect() const { + +	if (rect_cache_dirty) { +		item_rect = Rect2(); +		bool first = true; + +		for (int i = 0; i < outlines.size(); i++) { +			const PoolVector<Vector2> &outline = outlines[i]; +			const int outline_size = outline.size(); +			if (outline_size < 3) +				continue; +			PoolVector<Vector2>::Read p = outline.read(); +			for (int j = 0; j < outline_size; j++) { +				if (first) { +					item_rect = Rect2(p[j], Vector2(0, 0)); +					first = false; +				} else { +					item_rect.expand_to(p[j]); +				} +			} +		} + +		rect_cache_dirty = false; +	} +	return item_rect; +} + +bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	for (int i = 0; i < outlines.size(); i++) { +		const PoolVector<Vector2> &outline = outlines[i]; +		const int outline_size = outline.size(); +		if (outline_size < 3) +			continue; +		if (Geometry::is_point_in_polygon(p_point, Variant(outline))) +			return true; +	} +	return false; +} +  void NavigationPolygon::set_vertices(const PoolVector<Vector2> &p_vertices) {  	vertices = p_vertices; +	rect_cache_dirty = true;  }  PoolVector<Vector2> NavigationPolygon::get_vertices() const { @@ -70,6 +111,7 @@ void NavigationPolygon::_set_outlines(const Array &p_array) {  	for (int i = 0; i < p_array.size(); i++) {  		outlines[i] = p_array[i];  	} +	rect_cache_dirty = true;  }  Array NavigationPolygon::_get_outlines() const { @@ -93,6 +135,7 @@ void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {  void NavigationPolygon::add_outline_at_index(const PoolVector<Vector2> &p_outline, int p_index) {  	outlines.insert(p_index, p_outline); +	rect_cache_dirty = true;  }  int NavigationPolygon::get_polygon_count() const { @@ -112,6 +155,7 @@ void NavigationPolygon::clear_polygons() {  void NavigationPolygon::add_outline(const PoolVector<Vector2> &p_outline) {  	outlines.push_back(p_outline); +	rect_cache_dirty = true;  }  int NavigationPolygon::get_outline_count() const { @@ -122,12 +166,14 @@ int NavigationPolygon::get_outline_count() const {  void NavigationPolygon::set_outline(int p_idx, const PoolVector<Vector2> &p_outline) {  	ERR_FAIL_INDEX(p_idx, outlines.size());  	outlines[p_idx] = p_outline; +	rect_cache_dirty = true;  }  void NavigationPolygon::remove_outline(int p_idx) {  	ERR_FAIL_INDEX(p_idx, outlines.size());  	outlines.remove(p_idx); +	rect_cache_dirty = true;  }  PoolVector<Vector2> NavigationPolygon::get_outline(int p_idx) const { @@ -138,6 +184,7 @@ PoolVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {  void NavigationPolygon::clear_outlines() {  	outlines.clear(); +	rect_cache_dirty = true;  }  void NavigationPolygon::make_polygons_from_outlines() { @@ -269,7 +316,8 @@ void NavigationPolygon::_bind_methods() {  	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_outlines", "_get_outlines");  } -NavigationPolygon::NavigationPolygon() { +NavigationPolygon::NavigationPolygon() : +		rect_cache_dirty(true) {  }  void NavigationPolygonInstance::set_enabled(bool p_enabled) { @@ -311,6 +359,16 @@ bool NavigationPolygonInstance::is_enabled() const {  ///////////////////////////// +Rect2 NavigationPolygonInstance::_edit_get_rect() const { + +	return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2(); +} + +bool NavigationPolygonInstance::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false; +} +  void NavigationPolygonInstance::_notification(int p_what) {  	switch (p_what) { diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h index febdcf2ca6..7b5220f92d 100644 --- a/scene/2d/navigation_polygon.h +++ b/scene/2d/navigation_polygon.h @@ -43,6 +43,9 @@ class NavigationPolygon : public Resource {  	Vector<Polygon> polygons;  	Vector<PoolVector<Vector2> > outlines; +	mutable Rect2 item_rect; +	mutable bool rect_cache_dirty; +  protected:  	static void _bind_methods(); @@ -53,6 +56,9 @@ protected:  	Array _get_outlines() const;  public: +	Rect2 _edit_get_rect() const; +	bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_vertices(const PoolVector<Vector2> &p_vertices);  	PoolVector<Vector2> get_vertices() const; @@ -93,6 +99,9 @@ protected:  	static void _bind_methods();  public: +	virtual Rect2 _edit_get_rect() const; +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_enabled(bool p_enabled);  	bool is_enabled() const; diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 06bd55858c..d2a307a9ed 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -32,6 +32,51 @@  #include "engine.h"  #include "scene/scene_string_names.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_scale.h" +#endif + +Rect2 Path2D::_edit_get_rect() const { + +	if (curve->get_point_count() == 0) +		return Rect2(0, 0, 0, 0); + +	Rect2 aabb = Rect2(curve->get_point_position(0), Vector2(0, 0)); + +	for (int i = 0; i < curve->get_point_count(); i++) { + +		for (int j = 0; j <= 8; j++) { + +			real_t frac = j / 8.0; +			Vector2 p = curve->interpolate(i, frac); +			aabb.expand_to(p); +		} +	} + +	return aabb; +} + +bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	for (int i = 0; i < curve->get_point_count(); i++) { +		Vector2 s[2]; +		s[0] = curve->get_point_position(i); + +		for (int j = 1; j <= 8; j++) { +			real_t frac = j / 8.0; +			s[1] = curve->interpolate(i, frac); + +			Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, s); +			if (p.distance_to(p_point) <= p_tolerance) +				return true; + +			s[0] = s[1]; +		} +	} + +	return false; +} +  void Path2D::_notification(int p_what) {  	if (p_what == NOTIFICATION_DRAW && curve.is_valid()) { @@ -41,6 +86,13 @@ void Path2D::_notification(int p_what) {  			return;  		} +#if TOOLS_ENABLED +		const float line_width = 2 * EDSCALE; +#else +		const float line_width = 2; +#endif +		const Color color = Color(0.5, 0.6, 1.0, 0.7); +  		for (int i = 0; i < curve->get_point_count(); i++) {  			Vector2 prev_p = curve->get_point_position(i); @@ -49,7 +101,7 @@ void Path2D::_notification(int p_what) {  				real_t frac = j / 8.0;  				Vector2 p = curve->interpolate(i, frac); -				draw_line(prev_p, p, Color(0.5, 0.6, 1.0, 0.7), 2); +				draw_line(prev_p, p, color, line_width);  				prev_p = p;  			}  		} diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index ebfa77d605..7f53821c7e 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -46,6 +46,9 @@ protected:  	static void _bind_methods();  public: +	virtual Rect2 _edit_get_rect() const; +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_curve(const Ref<Curve2D> &p_curve);  	Ref<Curve2D> get_curve() const; diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index a2f49d938b..f9951cdd08 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -28,6 +28,7 @@  /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */  /*************************************************************************/  #include "polygon_2d.h" +#include "core/math/geometry.h"  Rect2 Polygon2D::_edit_get_rect() const { @@ -42,13 +43,17 @@ Rect2 Polygon2D::_edit_get_rect() const {  			else  				item_rect.expand_to(pos);  		} -		item_rect = item_rect.grow(20);  		rect_cache_dirty = false;  	}  	return item_rect;  } +bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	return Geometry::is_point_in_polygon(p_point, Variant(polygon)); +} +  void Polygon2D::_edit_set_pivot(const Point2 &p_pivot) {  	set_offset(p_pivot); diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index a23e223e6e..5014cbc6e9 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -104,6 +104,7 @@ public:  	virtual bool _edit_use_pivot() const;  	virtual Rect2 _edit_get_rect() const; +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;  	Polygon2D();  }; diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index c4a7e5aebd..68df95c042 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -47,6 +47,40 @@ bool Sprite::_edit_use_pivot() const {  	return true;  } +void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const { + +	Size2 s; +	r_filter_clip = false; + +	if (region) { + +		s = region_rect.size; +		r_src_rect = region_rect; +		r_filter_clip = region_filter_clip; +	} else { +		s = Size2(texture->get_size()); +		s = s / Size2(hframes, vframes); + +		r_src_rect.size = s; +		r_src_rect.position.x += float(frame % hframes) * s.x; +		r_src_rect.position.y += float(frame / hframes) * s.y; +	} + +	Point2 ofs = offset; +	if (centered) +		ofs -= s / 2; +	if (Engine::get_singleton()->get_use_pixel_snap()) { +		ofs = ofs.floor(); +	} + +	r_dst_rect = Rect2(ofs, s); + +	if (hflip) +		r_dst_rect.size.x = -r_dst_rect.size.x; +	if (vflip) +		r_dst_rect.size.y = -r_dst_rect.size.y; +} +  void Sprite::_notification(int p_what) {  	switch (p_what) { @@ -63,38 +97,9 @@ void Sprite::_notification(int p_what) {  			break;  			*/ -			Size2 s; -			Rect2 src_rect; -			bool filter_clip = false; - -			if (region) { - -				s = region_rect.size; -				src_rect = region_rect; -				filter_clip = region_filter_clip; -			} else { -				s = Size2(texture->get_size()); -				s = s / Size2(hframes, vframes); - -				src_rect.size = s; -				src_rect.position.x += float(frame % hframes) * s.x; -				src_rect.position.y += float(frame / hframes) * s.y; -			} - -			Point2 ofs = offset; -			if (centered) -				ofs -= s / 2; -			if (Engine::get_singleton()->get_use_pixel_snap()) { -				ofs = ofs.floor(); -			} - -			Rect2 dst_rect(ofs, s); - -			if (hflip) -				dst_rect.size.x = -dst_rect.size.x; -			if (vflip) -				dst_rect.size.y = -dst_rect.size.y; - +			Rect2 src_rect, dst_rect; +			bool filter_clip; +			_get_rects(src_rect, dst_rect, filter_clip);  			texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, filter_clip);  		} break; @@ -257,6 +262,30 @@ int Sprite::get_hframes() const {  	return hframes;  } +bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	if (texture.is_null()) +		return false; + +	Rect2 src_rect, dst_rect; +	bool filter_clip; +	_get_rects(src_rect, dst_rect, filter_clip); + +	if (!dst_rect.has_point(p_point)) +		return false; + +	Vector2 q = ((p_point - dst_rect.position) / dst_rect.size) * src_rect.size + src_rect.position; + +	Ref<Image> image = texture->get_data(); +	ERR_FAIL_COND_V(image.is_null(), false); + +	image->lock(); +	const Color c = image->get_pixel((int)q.x, (int)q.y); +	image->unlock(); + +	return c.a > 0.01; +} +  Rect2 Sprite::_edit_get_rect() const {  	if (texture.is_null()) diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h index c437f6d404..7d9b2cf457 100644 --- a/scene/2d/sprite.h +++ b/scene/2d/sprite.h @@ -54,6 +54,8 @@ class Sprite : public Node2D {  	int vframes;  	int hframes; +	void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const; +  protected:  	void _notification(int p_what); @@ -65,6 +67,7 @@ public:  	virtual void _edit_set_pivot(const Point2 &p_pivot);  	virtual Point2 _edit_get_pivot() const;  	virtual bool _edit_use_pivot() const; +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;  	virtual Rect2 _edit_get_rect() const;  	void set_texture(const Ref<Texture> &p_texture); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 6463180d9e..bac95c6cca 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -547,12 +547,14 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f  			if (!backwards && cd.pos <= len && next_pos == len /*&& playback.blend.empty()*/) {  				//playback finished -				end_notify = true; +				end_reached = true; +				end_notify = cd.pos < len; // Notify only if not already at the end  			}  			if (backwards && cd.pos >= 0 && next_pos == 0 /*&& playback.blend.empty()*/) {  				//playback finished -				end_notify = true; +				end_reached = true; +				end_notify = cd.pos > 0; // Notify only if not already at the beginning  			}  		} @@ -679,24 +681,26 @@ void AnimationPlayer::_animation_process(float p_delta) {  	if (playback.current.from) { +		end_reached = false;  		end_notify = false;  		_animation_process2(p_delta);  		_animation_update_transforms(); -		if (end_notify) { +		if (end_reached) {  			if (queued.size()) {  				String old = playback.assigned;  				play(queued.front()->get());  				String new_name = playback.assigned;  				queued.pop_front(); -				end_notify = false; -				emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name); +				if (end_notify) +					emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name);  			} else {  				//stop();  				playing = false;  				_set_process(false); -				end_notify = false; -				emit_signal(SceneStringNames::get_singleton()->animation_finished, playback.assigned); +				if (end_notify) +					emit_signal(SceneStringNames::get_singleton()->animation_finished, playback.assigned);  			} +			end_reached = false;  		}  	} else { @@ -954,7 +958,7 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float  	c.current.speed_scale = p_custom_scale;  	c.assigned = p_name; -	if (!end_notify) +	if (!end_reached)  		queued.clear();  	_set_process(true); // always process when starting an animation  	playing = true; @@ -1348,6 +1352,7 @@ AnimationPlayer::AnimationPlayer() {  	cache_update_size = 0;  	cache_update_prop_size = 0;  	speed_scale = 1; +	end_reached = false;  	end_notify = false;  	animation_process_mode = ANIMATION_PROCESS_IDLE;  	processing = false; diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 57c658e054..40a7252528 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -205,6 +205,7 @@ private:  	List<StringName> queued; +	bool end_reached;  	bool end_notify;  	String autoplay; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 2f30337cb8..1711fbffee 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -561,57 +561,50 @@ void Tween::_tween_process(float p_delta) {  			data.finish = true;  		} -		switch (data.type) { -			case INTER_PROPERTY: -			case INTER_METHOD: { -				Variant result = _run_equation(data); -				emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result); -				_apply_tween_value(data, result); -				if (data.finish) -					_apply_tween_value(data, data.final_val); -			} break; - -			case INTER_CALLBACK: -				if (data.finish) { -					if (data.call_deferred) { - -						switch (data.args) { -							case 0: -								object->call_deferred(data.key[0]); -								break; -							case 1: -								object->call_deferred(data.key[0], data.arg[0]); -								break; -							case 2: -								object->call_deferred(data.key[0], data.arg[0], data.arg[1]); -								break; -							case 3: -								object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2]); -								break; -							case 4: -								object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3]); -								break; -							case 5: -								object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3], data.arg[4]); -								break; -						} -					} else { -						Variant::CallError error; -						Variant *arg[5] = { -							&data.arg[0], -							&data.arg[1], -							&data.arg[2], -							&data.arg[3], -							&data.arg[4], -						}; -						object->call(data.key[0], (const Variant **)arg, data.args, error); +		if (data.type == INTER_CALLBACK) { +			if (data.finish) { +				if (data.call_deferred) { + +					switch (data.args) { +						case 0: +							object->call_deferred(data.key[0]); +							break; +						case 1: +							object->call_deferred(data.key[0], data.arg[0]); +							break; +						case 2: +							object->call_deferred(data.key[0], data.arg[0], data.arg[1]); +							break; +						case 3: +							object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2]); +							break; +						case 4: +							object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3]); +							break; +						case 5: +							object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3], data.arg[4]); +							break;  					} +				} else { +					Variant::CallError error; +					Variant *arg[5] = { +						&data.arg[0], +						&data.arg[1], +						&data.arg[2], +						&data.arg[3], +						&data.arg[4], +					}; +					object->call(data.key[0], (const Variant **)arg, data.args, error);  				} -				break; -			default: {} +			} +		} else { +			Variant result = _run_equation(data); +			emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result); +			_apply_tween_value(data, result);  		}  		if (data.finish) { +			_apply_tween_value(data, data.final_val);  			emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false));  			// not repeat mode, remove completed action  			if (!repeat) diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index b1c862d1d1..5a4a0b2106 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -930,6 +930,9 @@ void ItemList::_notification(int p_what) {  						scroll_bar->hide();  					} else {  						scroll_bar->show(); + +						if (do_autoscroll_to_bottom) +							scroll_bar->set_value(max);  					}  					break;  				} @@ -1313,6 +1316,11 @@ Size2 ItemList::get_minimum_size() const {  	return Size2();  } +void ItemList::set_autoscroll_to_bottom(const bool p_enable) { + +	do_autoscroll_to_bottom = p_enable; +} +  void ItemList::set_auto_height(bool p_enable) {  	auto_height = p_enable; @@ -1466,6 +1474,7 @@ ItemList::ItemList() {  	ensure_selected_visible = false;  	defer_select_single = -1;  	allow_rmb_select = false; +	do_autoscroll_to_bottom = false;  	icon_scale = 1.0f;  	set_clip_contents(true); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index df751d8b9d..e56d5e5224 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -107,6 +107,8 @@ private:  	real_t icon_scale; +	bool do_autoscroll_to_bottom; +  	Array _get_items() const;  	void _set_items(const Array &p_items); @@ -212,6 +214,8 @@ public:  	Size2 get_minimum_size() const; +	void set_autoscroll_to_bottom(const bool p_enable); +  	VScrollBar *get_v_scroll() { return scroll_bar; }  	ItemList(); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 34abb1fbcc..dff7722a9e 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -368,6 +368,18 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {  					shift_selection_check_post(k->get_shift());  				} break; +				case KEY_UP: { + +					shift_selection_check_pre(k->get_shift()); +					set_cursor_position(0); +					shift_selection_check_post(k->get_shift()); +				} break; +				case KEY_DOWN: { + +					shift_selection_check_pre(k->get_shift()); +					set_cursor_position(text.length()); +					shift_selection_check_post(k->get_shift()); +				} break;  				case KEY_DELETE: {  					if (!editable) diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 2ce31ea1b3..5fbc0c9064 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2725,6 +2725,8 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {  					_scroll_lines_down();  					break;  				} + +				{  #else  				if (k->get_command() && k->get_alt()) {  					_scroll_lines_down(); @@ -2733,9 +2735,15 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {  				if (k->get_command())  					cursor_set_line(text.size() - 1, true, false); -				else +				else {  #endif -				cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false); +					if (!is_last_visible_line(cursor.line)) { +						cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false); +					} else { +						cursor_set_line(text.size() - 1); +						cursor_set_column(get_line(cursor.line).length(), true); +					} +				}  				if (k->get_shift())  					_post_shift_selection(); @@ -3131,6 +3139,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {  void TextEdit::_scroll_up(real_t p_delta) { +	if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(-p_delta)) +		scrolling = false; +  	if (scrolling) {  		target_v_scroll = (target_v_scroll - p_delta);  	} else { @@ -3141,8 +3152,12 @@ void TextEdit::_scroll_up(real_t p_delta) {  		if (target_v_scroll <= 0) {  			target_v_scroll = 0;  		} -		scrolling = true; -		set_physics_process(true); +		if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) { +			v_scroll->set_value(target_v_scroll); +		} else { +			scrolling = true; +			set_physics_process(true); +		}  	} else {  		v_scroll->set_value(target_v_scroll);  	} @@ -3150,6 +3165,9 @@ void TextEdit::_scroll_up(real_t p_delta) {  void TextEdit::_scroll_down(real_t p_delta) { +	if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(p_delta)) +		scrolling = false; +  	if (scrolling) {  		target_v_scroll = (target_v_scroll + p_delta);  	} else { @@ -3166,8 +3184,13 @@ void TextEdit::_scroll_down(real_t p_delta) {  		if (target_v_scroll > max_v_scroll) {  			target_v_scroll = max_v_scroll;  		} -		scrolling = true; -		set_physics_process(true); + +		if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) { +			v_scroll->set_value(target_v_scroll); +		} else { +			scrolling = true; +			set_physics_process(true); +		}  	} else {  		v_scroll->set_value(target_v_scroll);  	} @@ -4584,6 +4607,24 @@ int TextEdit::num_lines_from(int p_line_from, int unhidden_amount) const {  	return num_total;  } +bool TextEdit::is_last_visible_line(int p_line) const { + +	ERR_FAIL_INDEX_V(p_line, text.size(), false); + +	if (p_line == text.size() - 1) +		return true; + +	if (!is_hiding_enabled()) +		return false; + +	for (int i = p_line + 1; i < text.size(); i++) { +		if (!is_line_hidden(i)) +			return false; +	} + +	return true; +} +  int TextEdit::get_indent_level(int p_line) const {  	ERR_FAIL_INDEX_V(p_line, text.size(), 0); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 320bb6d9fd..ccd7ba8278 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -433,6 +433,7 @@ public:  	void fold_all_lines();  	void unhide_all_lines();  	int num_lines_from(int p_line_from, int unhidden_amount) const; +	bool is_last_visible_line(int p_line) const;  	bool can_fold(int p_line) const;  	bool is_folded(int p_line) const;  	void fold_line(int p_line); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 07f93fa52b..632d912e43 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -2126,6 +2126,7 @@ void SceneTree::_bind_methods() {  	ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);  	ClassDB::bind_method(D_METHOD("set_auto_accept_quit", "enabled"), &SceneTree::set_auto_accept_quit); +	ClassDB::bind_method(D_METHOD("set_quit_on_go_back", "enabled"), &SceneTree::set_quit_on_go_back);  	ClassDB::bind_method(D_METHOD("set_debug_collisions_hint", "enable"), &SceneTree::set_debug_collisions_hint);  	ClassDB::bind_method(D_METHOD("is_debugging_collisions_hint"), &SceneTree::is_debugging_collisions_hint); diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index 7b2dbf8e8c..2722ff7207 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -32,6 +32,25 @@  #include "servers/physics_2d_server.h"  #include "servers/visual_server.h" +Vector<Vector2> CapsuleShape2D::_get_points() const { + +	Vector<Vector2> points; +	for (int i = 0; i < 24; i++) { +		Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5); + +		points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs); +		if (i == 6 || i == 18) +			points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs); +	} + +	return points; +} + +bool CapsuleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	return Geometry::is_point_in_polygon(p_point, _get_points()); +} +  void CapsuleShape2D::_update_shape() {  	Physics2DServer::get_singleton()->shape_set_data(get_rid(), Vector2(radius, height)); @@ -62,15 +81,7 @@ real_t CapsuleShape2D::get_height() const {  void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) { -	Vector<Vector2> points; -	for (int i = 0; i < 24; i++) { -		Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5); - -		points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs); -		if (i == 6 || i == 18) -			points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs); -	} - +	Vector<Vector2> points = _get_points();  	Vector<Color> col;  	col.push_back(p_color);  	VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h index 7ce6a4ed63..784f2c02c8 100644 --- a/scene/resources/capsule_shape_2d.h +++ b/scene/resources/capsule_shape_2d.h @@ -39,11 +39,14 @@ class CapsuleShape2D : public Shape2D {  	real_t radius;  	void _update_shape(); +	Vector<Vector2> _get_points() const;  protected:  	static void _bind_methods();  public: +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_height(real_t p_height);  	real_t get_height() const; diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index d9d0ddbe8f..669b1d8e7d 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -31,6 +31,12 @@  #include "servers/physics_2d_server.h"  #include "servers/visual_server.h" + +bool CircleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	return p_point.length() < get_radius() + p_tolerance; +} +  void CircleShape2D::_update_shape() {  	Physics2DServer::get_singleton()->shape_set_data(get_rid(), radius); diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h index f14f8f6776..3668521a55 100644 --- a/scene/resources/circle_shape_2d.h +++ b/scene/resources/circle_shape_2d.h @@ -42,6 +42,8 @@ protected:  	static void _bind_methods();  public: +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_radius(real_t p_radius);  	real_t get_radius() const; diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp index 19985d4acf..69765796f6 100644 --- a/scene/resources/concave_polygon_shape_2d.cpp +++ b/scene/resources/concave_polygon_shape_2d.cpp @@ -32,6 +32,23 @@  #include "servers/physics_2d_server.h"  #include "servers/visual_server.h" +bool ConcavePolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	PoolVector<Vector2> s = get_segments(); +	int len = s.size(); +	if (len == 0 || (len % 2) == 1) +		return false; + +	PoolVector<Vector2>::Read r = s.read(); +	for (int i = 0; i < len; i += 2) { +		Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, &r[i]); +		if (p_point.distance_to(closest) < p_tolerance) +			return true; +	} + +	return false; +} +  void ConcavePolygonShape2D::set_segments(const PoolVector<Vector2> &p_segments) {  	Physics2DServer::get_singleton()->shape_set_data(get_rid(), p_segments); diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h index 4a5defe72c..7ca14d4d66 100644 --- a/scene/resources/concave_polygon_shape_2d.h +++ b/scene/resources/concave_polygon_shape_2d.h @@ -39,6 +39,8 @@ protected:  	static void _bind_methods();  public: +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_segments(const PoolVector<Vector2> &p_segments);  	PoolVector<Vector2> get_segments() const; diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp index 98ef2ca7c6..0402a70898 100644 --- a/scene/resources/convex_polygon_shape_2d.cpp +++ b/scene/resources/convex_polygon_shape_2d.cpp @@ -33,6 +33,11 @@  #include "servers/physics_2d_server.h"  #include "servers/visual_server.h" +bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	return Geometry::is_point_in_polygon(p_point, points); +} +  void ConvexPolygonShape2D::_update_shape() {  	Physics2DServer::get_singleton()->shape_set_data(get_rid(), points); diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h index f492b7651b..320cf94a5e 100644 --- a/scene/resources/convex_polygon_shape_2d.h +++ b/scene/resources/convex_polygon_shape_2d.h @@ -42,6 +42,8 @@ protected:  	static void _bind_methods();  public: +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_point_cloud(const Vector<Vector2> &p_points);  	void set_points(const Vector<Vector2> &p_points);  	Vector<Vector2> get_points() const; diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp index 4682ef5cb3..346599b25a 100644 --- a/scene/resources/segment_shape_2d.cpp +++ b/scene/resources/segment_shape_2d.cpp @@ -32,6 +32,13 @@  #include "servers/physics_2d_server.h"  #include "servers/visual_server.h" +bool SegmentShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	Vector2 l[2] = { a, b }; +	Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l); +	return p_point.distance_to(closest) < p_tolerance; +} +  void SegmentShape2D::_update_shape() {  	Rect2 r; diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h index 1285ae4f82..39a71f61d5 100644 --- a/scene/resources/segment_shape_2d.h +++ b/scene/resources/segment_shape_2d.h @@ -44,6 +44,8 @@ protected:  	static void _bind_methods();  public: +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_a(const Vector2 &p_a);  	void set_b(const Vector2 &p_b); diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index 5c2c24ed74..877a159aee 100644 --- a/scene/resources/shape_2d.h +++ b/scene/resources/shape_2d.h @@ -44,6 +44,8 @@ protected:  	Shape2D(const RID &p_rid);  public: +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return true; } +  	void set_custom_solver_bias(real_t p_bias);  	real_t get_custom_solver_bias() const; diff --git a/scene/resources/shape_line_2d.cpp b/scene/resources/shape_line_2d.cpp index c6cc3659f6..9548d35370 100644 --- a/scene/resources/shape_line_2d.cpp +++ b/scene/resources/shape_line_2d.cpp @@ -30,6 +30,21 @@  #include "shape_line_2d.h"  #include "servers/physics_2d_server.h"  #include "servers/visual_server.h" + +bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + +	Vector2 point = get_d() * get_normal(); +	Vector2 l[2][2] = { { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }, { point, point + get_normal() * 30 } }; + +	for (int i = 0; i < 2; i++) { +		Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l[i]); +		if (p_point.distance_to(closest) < p_tolerance) +			return true; +	} + +	return false; +} +  void LineShape2D::_update_shape() {  	Array arr; diff --git a/scene/resources/shape_line_2d.h b/scene/resources/shape_line_2d.h index 747500b0ac..fe6f2d675e 100644 --- a/scene/resources/shape_line_2d.h +++ b/scene/resources/shape_line_2d.h @@ -44,6 +44,8 @@ protected:  	static void _bind_methods();  public: +	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +  	void set_normal(const Vector2 &p_normal);  	void set_d(real_t p_d); diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp index a8422b805e..67b83b7618 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -6,6 +6,7 @@  /*                      https://godotengine.org                          */  /*************************************************************************/  /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 4062f91438..48a76aea6b 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -6,6 +6,7 @@  /*                      https://godotengine.org                          */  /*************************************************************************/  /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */  /*                                                                       */  /* Permission is hereby granted, free of charge, to any person obtaining */  /* a copy of this software and associated documentation files (the       */ diff --git a/thirdparty/thekla_atlas/godot-changes.patch b/thirdparty/thekla_atlas/godot-changes.patch new file mode 100644 index 0000000000..0e56403336 --- /dev/null +++ b/thirdparty/thekla_atlas/godot-changes.patch @@ -0,0 +1,154 @@ +diff --git a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp +index 5ce452c..11e635d 100644 +--- a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp ++++ b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp +@@ -142,9 +142,11 @@ AtlasPacker::AtlasPacker(Atlas * atlas) : m_atlas(atlas), m_bitmap(256, 256) + { +     m_width = 0; +     m_height = 0; +-     +-    m_debug_bitmap.allocate(256, 256); +-    m_debug_bitmap.fill(Color32(0,0,0,0)); ++ ++    // -- GODOT start -- ++    //m_debug_bitmap.allocate(256, 256); ++    //m_debug_bitmap.fill(Color32(0,0,0,0)); ++    // -- GODOT end -- + } +  + AtlasPacker::~AtlasPacker() +@@ -465,7 +467,11 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned +                     nvDebug("origin: %f %f\n", origin.x, origin.y); +                     nvDebug("majorAxis: %f %f\n", majorAxis.x, majorAxis.y); +                     nvDebug("minorAxis: %f %f\n", minorAxis.x, minorAxis.y); +-                    nvDebugBreak(); ++                    // -- GODOT start -- ++                    //nvDebugBreak(); ++                    m_atlas->setFailed(); ++                    return; ++                    // -- GODOT end -- +                 } +                 //nvCheck(tmp.x >= 0 && tmp.y >= 0); +  +@@ -597,8 +603,10 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned +     m_bitmap.clearAll(); +     if (approximateExtent > m_bitmap.width()) { +         m_bitmap.resize(approximateExtent, approximateExtent, false); +-        m_debug_bitmap.resize(approximateExtent, approximateExtent); +-        m_debug_bitmap.fill(Color32(0,0,0,0)); ++        // -- GODOT start -- ++        //m_debug_bitmap.resize(approximateExtent, approximateExtent); ++        //m_debug_bitmap.fill(Color32(0,0,0,0)); ++        // -- GODOT end -- +     } +  +      +@@ -680,20 +688,24 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned +         { +             //nvDebug("Resize bitmap (%d, %d).\n", nextPowerOfTwo(w), nextPowerOfTwo(h)); +             m_bitmap.resize(nextPowerOfTwo(U32(w)), nextPowerOfTwo(U32(h)), false); +-            m_debug_bitmap.resize(nextPowerOfTwo(U32(w)), nextPowerOfTwo(U32(h))); ++            // -- GODOT start -- ++            //m_debug_bitmap.resize(nextPowerOfTwo(U32(w)), nextPowerOfTwo(U32(h))); ++            // -- GODOT end -- +         } +  +         //nvDebug("Add chart at (%d, %d).\n", best_x, best_y); +  +         addChart(&chart_bitmap, w, h, best_x, best_y, best_r, /*debugOutput=*/NULL); +  ++        // -- GODOT start -- +         // IC: Output chart again to debug bitmap. +-        if (chart->isVertexMapped()) { ++        /*if (chart->isVertexMapped()) { +             addChart(&chart_bitmap, w, h, best_x, best_y, best_r, &m_debug_bitmap); +         } +         else { +             addChart(chart, w, h, best_x, best_y, best_r, &m_debug_bitmap); +-        } ++        }*/ ++        // -- GODOT end -- +  +         //float best_angle = 2 * PI * best_r; +  +@@ -842,8 +854,10 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned +     nvCheck(isAligned(m_width, 4)); +     nvCheck(isAligned(m_height, 4)); +  +-    m_debug_bitmap.resize(m_width, m_height); +-    m_debug_bitmap.setFormat(Image::Format_ARGB); ++    // -- GODOT start -- ++    //m_debug_bitmap.resize(m_width, m_height); ++    //m_debug_bitmap.setFormat(Image::Format_ARGB); ++    // -- GODOT end -- +  + #if DEBUG_OUTPUT +     //outputDebugBitmap("debug_packer_final.tga", m_bitmap, w, h); +diff --git a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h +index 2d305f3..845dbfb 100644 +--- a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h ++++ b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h +@@ -48,7 +48,9 @@ namespace nv +  +         Atlas * m_atlas; +         BitMap m_bitmap; +-        Image m_debug_bitmap; ++        // -- GODOT start -- ++        //Image m_debug_bitmap; ++        // -- GODOT end -- +         RadixSort m_radix; +  +         uint m_width; +diff --git a/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp b/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp +index d6f0acc..de1953d 100644 +--- a/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp ++++ b/thirdparty/thekla_atlas/thekla/thekla_atlas.cpp +@@ -2,6 +2,9 @@ + #include "thekla_atlas.h" +  + #include <cfloat> ++// -- GODOT start -- ++#include <stdio.h> ++// -- GODOT end -- +  + #include "nvmesh/halfedge/Edge.h" + #include "nvmesh/halfedge/Mesh.h" +@@ -112,6 +115,8 @@ static Atlas_Output_Mesh * mesh_atlas_to_output(const HalfEdge::Mesh * mesh, con +     output->index_count = face_count * 3; +     output->index_array = new int[face_count * 3]; +  ++    // -- GODOT start -- ++    int face_ofs = 0; +     // Set face indices. +     for (int f = 0; f < face_count; f++) { +         uint c = charts->faceChartAt(f); +@@ -121,14 +126,26 @@ static Atlas_Output_Mesh * mesh_atlas_to_output(const HalfEdge::Mesh * mesh, con +         const Chart * chart = charts->chartAt(c); +         nvDebugCheck(chart->faceAt(i) == f); +  ++        if (i >= chart->chartMesh()->faceCount()) { ++            printf("WARNING: Faces may be missing in the final vertex, which could not be packed\n"); ++            continue; ++        } ++ +         const HalfEdge::Face * face = chart->chartMesh()->faceAt(i); +         const HalfEdge::Edge * edge = face->edge; +  +-        output->index_array[3*f+0] = vertexOffset + edge->vertex->id; +-        output->index_array[3*f+1] = vertexOffset + edge->next->vertex->id; +-        output->index_array[3*f+2] = vertexOffset + edge->next->next->vertex->id; ++        //output->index_array[3*f+0] = vertexOffset + edge->vertex->id; ++        //output->index_array[3*f+1] = vertexOffset + edge->next->vertex->id; ++        //output->index_array[3*f+2] = vertexOffset + edge->next->next->vertex->id; ++        output->index_array[3 * face_ofs + 0] = vertexOffset + edge->vertex->id; ++        output->index_array[3 * face_ofs + 1] = vertexOffset + edge->next->vertex->id; ++        output->index_array[3 * face_ofs + 2] = vertexOffset + edge->next->next->vertex->id; ++        face_ofs++; +     } +  ++    output->index_count = face_ofs * 3; ++    // -- GODOT end -- ++ +     *error = Atlas_Error_Success; +     output->atlas_width = w; +     output->atlas_height = h; diff --git a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp index fd37b8c59c..11e635db17 100644 --- a/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp +++ b/thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp @@ -467,7 +467,11 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned                      nvDebug("origin: %f %f\n", origin.x, origin.y);                      nvDebug("majorAxis: %f %f\n", majorAxis.x, majorAxis.y);                      nvDebug("minorAxis: %f %f\n", minorAxis.x, minorAxis.y); -                    nvDebugBreak(); +                    // -- GODOT start -- +                    //nvDebugBreak(); +                    m_atlas->setFailed(); +                    return; +                    // -- GODOT end --                  }                  //nvCheck(tmp.x >= 0 && tmp.y >= 0);  |