diff options
161 files changed, 2263 insertions, 641 deletions
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/math/matrix3.cpp b/core/math/matrix3.cpp index e1708a44b0..ceaff04ae8 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -228,12 +228,24 @@ void Basis::scale(const Vector3 &p_scale) { } Basis Basis::scaled(const Vector3 &p_scale) const { - Basis m = *this; m.scale(p_scale); return m; } +void Basis::scale_local(const Vector3 &p_scale) { + // performs a scaling in object-local coordinate system: + // M -> (M.S.Minv).M = M.S. + *this = scaled_local(p_scale); +} + +Basis Basis::scaled_local(const Vector3 &p_scale) const { + Basis b; + b.set_scale(p_scale); + + return (*this) * b; +} + void Basis::set_scale(const Vector3 &p_scale) { set_axis(0, get_axis(0).normalized() * p_scale.x); @@ -312,7 +324,8 @@ void Basis::rotate(const Vector3 &p_axis, real_t p_phi) { } void Basis::rotate_local(const Vector3 &p_axis, real_t p_phi) { - + // performs a rotation in object-local coordinate system: + // M -> (M.R.Minv).M = M.R. *this = rotated_local(p_axis, p_phi); } Basis Basis::rotated_local(const Vector3 &p_axis, real_t p_phi) const { diff --git a/core/math/matrix3.h b/core/math/matrix3.h index 71971bdea8..c426435729 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -103,6 +103,9 @@ public: void scale(const Vector3 &p_scale); Basis scaled(const Vector3 &p_scale) const; + void scale_local(const Vector3 &p_scale); + Basis scaled_local(const Vector3 &p_scale) const; + void set_scale(const Vector3 &p_scale); Vector3 get_scale() const; Vector3 get_signed_scale() const; diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index c906fa7333..eadb8e8546 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -293,7 +293,7 @@ String DirAccess::get_full_path(const String &p_path, AccessType p_access) { return full; } -Error DirAccess::copy(String p_from, String p_to, int chmod_flags) { +Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { //printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data()); Error err; @@ -330,9 +330,9 @@ Error DirAccess::copy(String p_from, String p_to, int chmod_flags) { fdst->store_8(fsrc->get_8()); } - if (err == OK && chmod_flags != -1) { + if (err == OK && p_chmod_flags != -1) { fdst->close(); - err = fdst->_chmod(p_to, chmod_flags); + err = fdst->_chmod(p_to, p_chmod_flags); // If running on a platform with no chmod support (i.e., Windows), don't fail if (err == ERR_UNAVAILABLE) err = OK; diff --git a/core/os/dir_access.h b/core/os/dir_access.h index f29f61e838..c94ced657b 100644 --- a/core/os/dir_access.h +++ b/core/os/dir_access.h @@ -92,8 +92,8 @@ public: static bool exists(String p_dir); virtual size_t get_space_left() = 0; - Error copy_dir(String p_from, String p_to, int chmod_flags = -1); - virtual Error copy(String p_from, String p_to, int chmod_flags = -1); + Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1); + virtual Error copy(String p_from, String p_to, int p_chmod_flags = -1); virtual Error rename(String p_from, String p_to) = 0; virtual Error remove(String p_name) = 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..a4f07df0e8 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -121,7 +121,7 @@ protected: void add_logger(Logger *p_logger); virtual void initialize_core() = 0; - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) = 0; + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) = 0; virtual void set_main_loop(MainLoop *p_main_loop) = 0; virtual void delete_main_loop() = 0; @@ -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/ring_buffer.h b/core/ring_buffer.h index 4b4a7fe9cf..c8562a0570 100644 --- a/core/ring_buffer.h +++ b/core/ring_buffer.h @@ -40,7 +40,7 @@ class RingBuffer { int write_pos; int size_mask; - inline int inc(int &p_var, int p_size) { + inline int inc(int &p_var, int p_size) const { int ret = p_var; p_var += p_size; p_var = p_var & size_mask; @@ -50,7 +50,7 @@ class RingBuffer { public: T read() { ERR_FAIL_COND_V(space_left() < 1, T()); - return data[inc(read_pos, 1)]; + return data.ptr()[inc(read_pos, 1)]; }; int read(T *p_buf, int p_size, bool p_advance = true) { @@ -63,8 +63,9 @@ public: int end = pos + to_read; end = MIN(end, size()); int total = end - pos; + const T *read = data.ptr(); for (int i = 0; i < total; i++) { - p_buf[dst++] = data[pos + i]; + p_buf[dst++] = read[pos + i]; }; to_read -= total; pos = 0; @@ -75,7 +76,7 @@ public: return p_size; }; - int copy(T *p_buf, int p_offset, int p_size) { + int copy(T *p_buf, int p_offset, int p_size) const { int left = data_left(); if ((p_offset + p_size) > left) { @@ -101,7 +102,7 @@ public: return p_size; }; - int find(const T &t, int p_offset, int p_max_size) { + int find(const T &t, int p_offset, int p_max_size) const { int left = data_left(); if ((p_offset + p_max_size) > left) { @@ -164,7 +165,7 @@ public: return p_size; }; - inline int space_left() { + inline int space_left() const { int left = read_pos - write_pos; if (left < 0) { return size() + left - 1; @@ -174,11 +175,11 @@ public: }; return left - 1; }; - inline int data_left() { + inline int data_left() const { return size() - space_left() - 1; }; - inline int size() { + inline int size() const { return data.size(); }; diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 27633ec553..a0a55ce86e 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -67,17 +67,20 @@ Error ScriptDebuggerRemote::connect_to_host(const String &p_host, uint16_t p_por int port = p_port; - int tries = 3; + const int tries = 6; + int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 }; + tcp_client->connect_to_host(ip, port); - while (tries--) { + for (int i = 0; i < tries; i++) { if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) { break; } else { - OS::get_singleton()->delay_usec(1000000); - print_line("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in 1 sec."); + const int ms = waits[i]; + OS::get_singleton()->delay_usec(ms * 1000); + print_line("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in " + String::num(ms) + " msec."); }; }; @@ -126,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/Basis.xml b/doc/classes/Basis.xml index a873bd9a27..1573596487 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -38,7 +38,7 @@ <argument index="1" name="phi" type="float"> </argument> <description> - Create a rotation matrix which rotates around the given axis by the specified angle. The axis must be a normalized vector. + Create a rotation matrix which rotates around the given axis by the specified angle, in radians. The axis must be a normalized vector. </description> </method> <method name="Basis"> 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..a01ffc99be 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> 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/Node2D.xml b/doc/classes/Node2D.xml index 81978809d7..5b7def99dc 100644 --- a/doc/classes/Node2D.xml +++ b/doc/classes/Node2D.xml @@ -157,12 +157,12 @@ <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform"> Local [Transform2D]. </member> - <member name="z" type="int" setter="set_z" getter="get_z"> - Z-index. Controls the order in which the nodes render. A node with a higher Z-index will display in front of others. - </member> <member name="z_as_relative" type="bool" setter="set_z_as_relative" getter="is_z_relative"> If [code]true[/code] the node's Z-index is relative to its parent's Z-index. If this node's Z-index is 2 and its parent's effective Z-index is 3, then this node's effective Z-index will be 2 + 3 = 5. </member> + <member name="z_index" type="int" setter="set_z_index" getter="get_z_index"> + Z-index. Controls the order in which the nodes render. A node with a higher Z-index will display in front of others. + </member> </members> <constants> </constants> 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 ea04192a5e..d0addcf9f9 100644 --- a/doc/classes/Spatial.xml +++ b/doc/classes/Spatial.xml @@ -5,6 +5,8 @@ </brief_description> <description> Most basic 3D game object, with a 3D [Transform] and visibility settings. All other 3D game objects inherit from Spatial. Use Spatial as a parent node to move, scale, rotate and show/hide children in a 3D project. + + Affine operations (rotate, scale, translate) happen in parent's local coordinate system, unless the Spatial object is set as top level. Affine operations in this coordinate system correspond to direct affine operations on the Spatial's transform. The word local below refers to this coordinate system. The coordinate system that is attached to the Spatial object itself is referred to as object-local coordinate system. </description> <tutorials> </tutorials> @@ -35,12 +37,20 @@ <method name="global_rotate"> <return type="void"> </return> - <argument index="0" name="normal" type="Vector3"> + <argument index="0" name="axis" type="Vector3"> </argument> - <argument index="1" name="radians" type="float"> + <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_scale"> + <return type="void"> + </return> + <argument index="0" name="scale" type="Vector3"> </argument> <description> - Rotates the current node along normal [Vector3] by angle in radians in Global space. </description> </method> <method name="global_translate"> @@ -49,7 +59,7 @@ <argument index="0" name="offset" type="Vector3"> </argument> <description> - Moves the node by [Vector3] offset in Global space. + Moves the global (world) transformation by [Vector3] offset. The offset is in global coordinate system. </description> </method> <method name="hide"> @@ -115,45 +125,65 @@ <return type="void"> </return> <description> - Resets this node's transformations (like scale, skew and taper) preserving its rotation and translation. Performs orthonormalization on this node [Transform3D]. + Resets this node's transformations (like scale, skew and taper) preserving its rotation and translation by performing Gram-Schmidt orthonormalization on this node's [Transform3D]. </description> </method> <method name="rotate"> <return type="void"> </return> - <argument index="0" name="normal" type="Vector3"> + <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. + </description> + </method> + <method name="rotate_object_local"> + <return type="void"> + </return> + <argument index="0" name="axis" type="Vector3"> </argument> - <argument index="1" name="radians" type="float"> + <argument index="1" name="angle" type="float"> </argument> <description> - Rotates the node in local space on given normal [Vector3] by angle in radians. + 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> - <argument index="0" name="radians" type="float"> + <argument index="0" name="angle" type="float"> </argument> <description> - Rotates the node in local space on X axis by angle in radians. + Rotates the local transformation around the X axis by angle in radians </description> </method> <method name="rotate_y"> <return type="void"> </return> - <argument index="0" name="radians" type="float"> + <argument index="0" name="angle" type="float"> </argument> <description> - Rotates the node in local space on Y axis by angle in radians. + Rotates the local transformation around the Y axis by angle in radians. </description> </method> <method name="rotate_z"> <return type="void"> </return> - <argument index="0" name="radians" type="float"> + <argument index="0" name="angle" type="float"> </argument> <description> - Rotates the node in local space on Z axis by angle in radians. + 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"> @@ -242,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> @@ -255,16 +293,18 @@ World space (global) [Transform] of this node. </member> <member name="rotation" type="Vector3" setter="set_rotation" getter="get_rotation"> - Local euler rotation in radians of this node. + Rotation part of the local transformation, specified in terms of YXZ-Euler angles in the format (X-angle, Y-angle, Z-angle), in radians. + + Note that in the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three indepdent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful. </member> <member name="rotation_degrees" type="Vector3" setter="set_rotation_degrees" getter="get_rotation_degrees"> - Local euler rotation in degrees of this node. + Rotation part of the local transformation, specified in terms of YXZ-Euler angles in the format (X-angle, Y-angle, Z-angle), in degrees. </member> <member name="scale" type="Vector3" setter="set_scale" getter="get_scale"> - Local scale of this node. + Scale part of the local transformation. </member> <member name="transform" type="Transform" setter="set_transform" getter="get_transform"> - Local space [Transform] of this node. + Local space [Transform] of this node, with respect to the parent node. </member> <member name="translation" type="Vector3" setter="set_translation" getter="get_translation"> Local translation of this node. 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/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index 0cba132de8..28fb83d572 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -504,26 +504,26 @@ Sets if the canvas item (including its children) is visible. </description> </method> - <method name="canvas_item_set_z"> + <method name="canvas_item_set_z_as_relative_to_parent"> <return type="void"> </return> <argument index="0" name="item" type="RID"> </argument> - <argument index="1" name="z" type="int"> + <argument index="1" name="enabled" type="bool"> </argument> <description> - Sets the [CanvasItem]'s z order position. + If this is enabled, the z-index of the parent will be added to the children's z-index. </description> </method> - <method name="canvas_item_set_z_as_relative_to_parent"> + <method name="canvas_item_set_z_index"> <return type="void"> </return> <argument index="0" name="item" type="RID"> </argument> - <argument index="1" name="enabled" type="bool"> + <argument index="1" name="z_index" type="int"> </argument> <description> - If this is enabled, the z-position of the parent will be added to the childrens z-position. + Sets the [CanvasItem]'s z-index, i.e. its draw order (lower indexes are drawn first). </description> </method> <method name="canvas_light_attach_to_canvas"> diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index cd0108019b..492f3b6d54 100644 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -276,6 +276,15 @@ def make_type(t): return ':ref:`' + t + '<class_' + t.lower() + '>`' return t +def make_enum(t): + global class_names + p = t.find(".") + if p >= 0: + c = t[0:p] + e = t[p+1:] + if c in class_names: + return ':ref:`' + e + '<enum_' + c.lower() + '_' + e.lower() + '>`' + return t def make_method( f, @@ -470,7 +479,10 @@ def make_rst_class(node): # Leading two spaces necessary to prevent breaking the <ul> f.write(" .. _class_" + name + "_" + c.attrib['name'] + ":\n\n") s = '- ' - s += make_type(c.attrib['type']) + ' ' + if 'enum' in c.attrib: + s += make_enum(c.attrib['enum']) + ' ' + else: + s += make_type(c.attrib['type']) + ' ' s += '**' + c.attrib['name'] + '**' if c.text.strip() != '': s += ' - ' + rstize_text(c.text.strip(), name) @@ -478,9 +490,20 @@ def make_rst_class(node): f.write('\n') constants = node.find('constants') + consts = [] + enum_names = set() + enums = [] if constants != None and len(list(constants)) > 0: - f.write(make_heading('Numeric Constants', '-')) for c in list(constants): + if 'enum' in c.attrib: + enum_names.add(c.attrib['enum']) + enums.append(c) + else: + consts.append(c) + + if len(consts) > 0: + f.write(make_heading('Numeric Constants', '-')) + for c in list(consts): s = '- ' s += '**' + c.attrib['name'] + '**' if 'value' in c.attrib: @@ -489,6 +512,24 @@ def make_rst_class(node): s += ' --- ' + rstize_text(c.text.strip(), name) f.write(s + '\n') f.write('\n') + + if len(enum_names) > 0: + f.write(make_heading('Enums', '-')) + for e in enum_names: + f.write(" .. _enum_" + name + "_" + e + ":\n\n") + f.write("enum **" + e + "**\n\n") + for c in enums: + if c.attrib['enum'] != e: + continue + s = '- ' + s += '**' + c.attrib['name'] + '**' + if 'value' in c.attrib: + s += ' = **' + c.attrib['value'] + '**' + if c.text.strip() != '': + s += ' --- ' + rstize_text(c.text.strip(), name) + f.write(s + '\n') + f.write('\n') + f.write('\n') descr = node.find('description') if descr != None and descr.text.strip() != '': diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 5f3b42abf6..7ae1758643 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -338,6 +338,15 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); +#if 1 + + Size2 win_size = OS::get_singleton()->get_window_size(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); + glBlitFramebuffer(0, 0, rt->width, rt->height, p_screen_rect.position.x, win_size.height - p_screen_rect.position.y - p_screen_rect.size.height, p_screen_rect.position.x + p_screen_rect.size.width, win_size.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + +#else canvas->canvas_begin(); glDisable(GL_BLEND); glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); @@ -350,6 +359,7 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1)); glBindTexture(GL_TEXTURE_2D, 0); canvas->canvas_end(); +#endif } void RasterizerGLES3::end_frame(bool p_swap_buffers) { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 5ce544ecfb..d35d624589 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -6943,6 +6943,10 @@ bool RasterizerStorageGLES3::free(RID p_rid) { glDeleteTextures(1, &cls->distance); canvas_light_shadow_owner.free(p_rid); memdelete(cls); + } else if (particles_owner.owns(p_rid)) { + Particles *particles = particles_owner.get(p_rid); + particles_owner.free(p_rid); + memdelete(particles); } else { return false; } diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 4ef4926a1a..74bd0a3cc1 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1180,7 +1180,7 @@ public: clear = true; inactive = true; - inactive_time = false; + inactive_time = 0.0; glGenBuffers(2, particle_buffers); glGenVertexArrays(2, particle_vaos); diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 0b8230234b..46641482ec 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -42,7 +42,7 @@ uniform highp mat4 modelview_matrix; uniform highp mat4 extra_matrix; -out mediump vec2 uv_interp; +out highp vec2 uv_interp; out mediump vec4 color_interp; #ifdef USE_NINEPATCH @@ -207,7 +207,7 @@ uniform mediump sampler2D color_texture; // texunit:0 uniform highp vec2 color_texpixel_size; uniform mediump sampler2D normal_texture; // texunit:1 -in mediump vec2 uv_interp; +in highp vec2 uv_interp; in mediump vec4 color_interp; diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index cc4d060c02..fa8094f31a 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -298,7 +298,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo args.push_back(0); #ifdef __FreeBSD__ - if (p_path.find("/")) { + if (p_path.find("/") != -1) { // exec name contains path so use it execv(p_path.utf8().get_data(), &args[0]); } else { diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 7929a791cb..d224a55647 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -55,7 +55,7 @@ protected: virtual void initialize_core(); virtual int unix_initialize_audio(int p_audio_driver); - //virtual void initialize(int p_video_driver,int p_audio_driver); + //virtual Error initialize(int p_video_driver,int p_audio_driver); virtual void finalize_core(); 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/create_dialog.cpp b/editor/create_dialog.cpp index a601c8cd2b..96c3a27ea7 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -37,7 +37,7 @@ #include "print_string.h" #include "scene/gui/box_container.h" -void CreateDialog::popup_create(bool p_dontclear) { +void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) { recent->clear(); @@ -89,11 +89,12 @@ void CreateDialog::popup_create(bool p_dontclear) { popup_centered_ratio(); } - if (p_dontclear) + if (p_dont_clear) { search_box->select_all(); - else { + } else { search_box->clear(); } + search_box->grab_focus(); _update_search(); @@ -104,8 +105,19 @@ void CreateDialog::popup_create(bool p_dontclear) { if (enable_rl) { search_options->add_constant_override("draw_relationship_lines", 1); search_options->add_color_override("relationship_line_color", rl_color); - } else + } else { search_options->add_constant_override("draw_relationship_lines", 0); + } + + is_replace_mode = p_replace_mode; + + if (p_replace_mode) { + set_title(vformat(TTR("Change %s Type"), base_type)); + get_ok()->set_text(TTR("Change")); + } else { + set_title(vformat(TTR("Create New %s"), base_type)); + get_ok()->set_text(TTR("Create")); + } } void CreateDialog::_text_changed(const String &p_newtext) { @@ -369,7 +381,11 @@ void CreateDialog::_notification(int p_what) { void CreateDialog::set_base_type(const String &p_base) { base_type = p_base; - set_title(vformat(TTR("Create New %s"), p_base)); + if (is_replace_mode) + set_title(vformat(TTR("Change %s Type"), p_base)); + else + set_title(vformat(TTR("Create New %s"), p_base)); + _update_search(); } @@ -624,6 +640,8 @@ void CreateDialog::_bind_methods() { CreateDialog::CreateDialog() { + is_replace_mode = false; + ClassDB::get_class_list(&type_list); type_list.sort_custom<StringName::AlphCompare>(); @@ -678,7 +696,6 @@ CreateDialog::CreateDialog() { search_box->connect("gui_input", this, "_sbox_input"); search_options = memnew(Tree); vbc->add_margin_child(TTR("Matches:"), search_options, true); - get_ok()->set_text(TTR("Create")); get_ok()->set_disabled(true); register_text_enter(search_box); set_hide_on_ok(false); diff --git a/editor/create_dialog.h b/editor/create_dialog.h index 56ba7f8a3e..ed23fb4ae8 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -52,6 +52,7 @@ class CreateDialog : public ConfirmationDialog { Button *favorite; LineEdit *search_box; Tree *search_options; + bool is_replace_mode; String base_type; String preferred_search_result_type; EditorHelpBit *help_bit; @@ -97,7 +98,7 @@ public: void set_preferred_search_result_type(const String &p_preferred_type); String get_preferred_search_result_type(); - void popup_create(bool p_dontclear); + void popup_create(bool p_dont_clear, bool p_replace_mode = false); CreateDialog(); }; 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_data.cpp b/editor/editor_data.cpp index 4acee1363c..c12a112fa4 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -880,6 +880,7 @@ void EditorSelection::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_node", "node"), &EditorSelection::remove_node); ClassDB::bind_method(D_METHOD("get_selected_nodes"), &EditorSelection::_get_selected_nodes); ClassDB::bind_method(D_METHOD("get_transformable_selected_nodes"), &EditorSelection::_get_transformable_selected_nodes); + ClassDB::bind_method(D_METHOD("_emit_change"), &EditorSelection::_emit_change); ADD_SIGNAL(MethodInfo("selection_changed")); } @@ -923,7 +924,15 @@ void EditorSelection::update() { if (!changed) return; changed = false; + if (!emitted) { + emitted = true; + call_deferred("_emit_change"); + } +} + +void EditorSelection::_emit_change() { emit_signal("selection_changed"); + emitted = false; } List<Node *> &EditorSelection::get_selected_node_list() { @@ -947,6 +956,7 @@ void EditorSelection::clear() { } EditorSelection::EditorSelection() { + emitted = false; changed = false; nl_changed = false; } diff --git a/editor/editor_data.h b/editor/editor_data.h index 2c95c3feea..3bc0e6e75c 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -210,9 +210,10 @@ class EditorSelection : public Object { GDCLASS(EditorSelection, Object); -public: +private: Map<Node *, Object *> selection; + bool emitted; bool changed; bool nl_changed; @@ -224,6 +225,7 @@ public: void _update_nl(); Array _get_selected_nodes(); Array _get_transformable_selected_nodes(); + void _emit_change(); protected: static void _bind_methods(); 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..79542f3b5c 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" @@ -65,7 +66,9 @@ void EditorLog::_notification(int p_what) { Ref<DynamicFont> df_output_code = get_font("output_source", "EditorFonts"); if (df_output_code.is_valid()) { df_output_code->set_size(int(EDITOR_DEF("run/output/font_size", 13)) * EDSCALE); - log->add_font_override("normal_font", get_font("output_source", "EditorFonts")); + if (log != NULL) { + log->add_font_override("normal_font", get_font("output_source", "EditorFonts")); + } } } @@ -154,6 +157,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..b52161813d 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()) != -1)) { continue; } String to = to_path.plus_file(from.get_file()); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index b3ac5e4ce5..16e60edda7 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -200,6 +200,14 @@ ScriptEditor *EditorInterface::get_script_editor() { return ScriptEditor::get_singleton(); } +void EditorInterface::select_file(const String &p_file) { + return EditorNode::get_singleton()->get_filesystem_dock()->select_file(p_file); +} + +String EditorInterface::get_selected_path() const { + return EditorNode::get_singleton()->get_filesystem_dock()->get_selected_path(); +} + void EditorInterface::inspect_object(Object *p_obj, const String &p_for_property) { EditorNode::get_singleton()->push_item(p_obj, p_for_property); @@ -259,6 +267,8 @@ void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_resource_filesystem"), &EditorInterface::get_resource_file_system); ClassDB::bind_method(D_METHOD("get_editor_viewport"), &EditorInterface::get_editor_viewport); ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews); + ClassDB::bind_method(D_METHOD("select_file", "p_file"), &EditorInterface::select_file); + ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path); ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene); ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true)); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 4bfa1fa7cf..887e599208 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -76,6 +76,9 @@ public: Array get_open_scenes() const; ScriptEditor *get_script_editor(); + void select_file(const String &p_file); + String get_selected_path() const; + void inspect_object(Object *p_obj, const String &p_for_property = String()); EditorSelection *get_selection(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 5a16ec7eab..a5001cb1ac 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); @@ -1329,8 +1329,44 @@ Ref<ShortCut> ED_GET_SHORTCUT(const String &p_path) { return sc; } +struct ShortCutMapping { + const char *path; + uint32_t keycode; +}; + Ref<ShortCut> ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p_keycode) { +#ifdef OSX_ENABLED + static const ShortCutMapping macos_mappings[] = { + { "editor/play", KEY_MASK_CMD | KEY_B }, + { "editor/play_scene", KEY_MASK_CMD | KEY_R }, + { "editor/pause_scene", KEY_MASK_CMD | KEY_MASK_CTRL | KEY_Y }, + { "editor/stop", KEY_MASK_CMD | KEY_PERIOD }, + { "editor/play_custom_scene", KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_R }, + { "editor/editor_2d", KEY_MASK_ALT | KEY_1 }, + { "editor/editor_3d", KEY_MASK_ALT | KEY_2 }, + { "editor/editor_script", KEY_MASK_ALT | KEY_3 }, + { "editor/editor_help", KEY_MASK_ALT | KEY_SPACE }, + { "editor/fullscreen_mode", KEY_MASK_CMD | KEY_MASK_CTRL | KEY_F }, + { "editor/distraction_free_mode", KEY_MASK_CMD | KEY_MASK_CTRL | KEY_D }, + { "script_text_editor/contextual_help", KEY_MASK_ALT | KEY_MASK_SHIFT | KEY_SPACE }, + { "script_text_editor/find_next", KEY_MASK_CMD | KEY_G }, + { "script_text_editor/find_previous", KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G }, + { "script_text_editor/toggle_breakpoint", KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B } + }; + + if (p_keycode == KEY_DELETE) { + p_keycode = KEY_MASK_CMD | KEY_BACKSPACE; + } else { + for (int i = 0; i < sizeof(macos_mappings) / sizeof(ShortCutMapping); i++) { + if (p_path == macos_mappings[i].path) { + p_keycode = macos_mappings[i].keycode; + break; + } + } + } +#endif + Ref<InputEventKey> ie; if (p_keycode) { ie.instance(); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 3644893663..8a3e7e6716 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -332,6 +332,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color font_color = mono_color.linear_interpolate(base_color, 0.25); const Color font_color_hl = mono_color.linear_interpolate(base_color, 0.15); const Color font_color_disabled = Color(mono_color.r, mono_color.g, mono_color.b, 0.3); + const Color font_color_selection = Color::html("#7d7d7d"); const Color color_disabled = mono_color.inverted().linear_interpolate(base_color, 0.7); const Color color_disabled_bg = mono_color.inverted().linear_interpolate(base_color, 0.9); @@ -790,6 +791,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("read_only", "LineEdit", font_color_disabled); theme->set_color("font_color", "LineEdit", font_color); theme->set_color("cursor_color", "LineEdit", font_color); + theme->set_color("selection_color", "LineEdit", font_color_selection); // TextEdit theme->set_stylebox("normal", "TextEdit", style_widget); @@ -799,6 +801,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons")); theme->set_color("font_color", "TextEdit", font_color); theme->set_color("caret_color", "TextEdit", highlight_color); + theme->set_color("selection_color", "TextEdit", font_color_selection); // H/VSplitContainer theme->set_stylebox("bg", "VSplitContainer", make_stylebox(theme->get_icon("GuiVsplitBg", "EditorIcons"), 1, 1, 1, 1)); @@ -1135,16 +1138,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/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp index 08f4d06ef7..6849563ae2 100644 --- a/editor/plugins/baked_lightmap_editor_plugin.cpp +++ b/editor/plugins/baked_lightmap_editor_plugin.cpp @@ -20,7 +20,6 @@ void BakedLightmapEditorPlugin::_bake() { case BakedLightmap::BAKE_ERROR_CANT_CREATE_IMAGE: EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable.")); break; - defaut : {} } } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 53b52c5f1b..a52c914096 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,14 +631,17 @@ 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; res.item = c; - res.z = node ? node->get_z() : 0; + res.z_index = node ? node->get_z_index() : 0; res.has_z = node; r_items.push_back(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/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index f14f1a92a6..0866fe77aa 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -252,10 +252,10 @@ class CanvasItemEditor : public VBoxContainer { struct _SelectResult { CanvasItem *item; - float z; + float z_index; bool has_z; _FORCE_INLINE_ bool operator<(const _SelectResult &p_rr) const { - return has_z && p_rr.has_z ? p_rr.z < z : p_rr.has_z; + return has_z && p_rr.has_z ? p_rr.z_index < z_index : p_rr.has_z; } }; diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index c865ddd4b0..3be68f21af 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -347,7 +347,8 @@ void CurveEditor::open_context_menu(Vector2 pos) { _context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_LINEAR), is_linear); } else { - _context_menu->add_separator(); + if (_selected_point > 0 || _selected_point + 1 < _curve_ref->get_point_count()) + _context_menu->add_separator(); if (_selected_point > 0) { _context_menu->add_check_item(TTR("Left linear"), CONTEXT_LEFT_LINEAR); @@ -367,6 +368,7 @@ void CurveEditor::open_context_menu(Vector2 pos) { _context_menu->add_submenu_item(TTR("Load preset"), _presets_menu->get_name()); + _context_menu->set_size(Size2(0, 0)); _context_menu->popup(); } @@ -566,7 +568,6 @@ static void plot_curve_accurate(const Curve &curve, float step, T plot_func) { Vector2 prev_pos = a; float len = b.x - a.x; - //float step = 4.f / view_size.x; for (float x = step; x < len; x += step) { pos.x = a.x + x; @@ -694,24 +695,6 @@ void CurveEditor::_draw() { CanvasItemPlotCurve plot_func(*this, line_color, edge_line_color); plot_curve_accurate(curve, 4.f / view_size.x, plot_func); - /*// TEST draw baked curve - { - Vector2 pos = Vector2(0, curve.interpolate_baked(0)); - Vector2 prev_pos = pos; - - float len = 1.0; - float step = 4.f / view_size.x; - - for(float x = step; x < len; x += step) { - pos.x = x; - pos.y = curve.interpolate_baked(x); - draw_line(get_point_view_pos(prev_pos), get_point_view_pos(pos), Color(0,1,0)); - prev_pos = pos; - } - - draw_line(get_point_view_pos(prev_pos), get_point_view_pos(Vector2(1, curve.interpolate_baked(1))), Color(0,1,0)); - }//*/ - // Draw points draw_set_transform_matrix(Transform2D()); 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..50db80ba01 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -238,19 +238,16 @@ void TileSetEditor::_bind_methods() { TileSetEditor::TileSetEditor(EditorNode *p_editor) { - Panel *panel = memnew(Panel); - panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); - add_child(panel); - MenuButton *options = memnew(MenuButton); - panel->add_child(options); - options->set_position(Point2(1, 1)); - options->set_text(TTR("Tile Set")); - options->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); - options->get_popup()->add_item(TTR("Remove Item"), MENU_OPTION_REMOVE_ITEM); - options->get_popup()->add_separator(); - options->get_popup()->add_item(TTR("Create from Scene"), MENU_OPTION_CREATE_FROM_SCENE); - options->get_popup()->add_item(TTR("Merge from Scene"), MENU_OPTION_MERGE_FROM_SCENE); - options->get_popup()->connect("id_pressed", this, "_menu_cbk"); + menu = memnew(MenuButton); + CanvasItemEditor::get_singleton()->add_control_to_menu_panel(menu); + menu->hide(); + menu->set_text(TTR("Tile Set")); + menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); + menu->get_popup()->add_item(TTR("Remove Item"), MENU_OPTION_REMOVE_ITEM); + menu->get_popup()->add_separator(); + menu->get_popup()->add_item(TTR("Create from Scene"), MENU_OPTION_CREATE_FROM_SCENE); + menu->get_popup()->add_item(TTR("Merge from Scene"), MENU_OPTION_MERGE_FROM_SCENE); + menu->get_popup()->connect("id_pressed", this, "_menu_cbk"); editor = p_editor; cd = memnew(ConfirmationDialog); add_child(cd); @@ -286,6 +283,7 @@ void TileSetEditorPlugin::make_visible(bool p_visible) { if (p_visible) { tileset_editor->show(); + tileset_editor->menu->show(); autotile_button->show(); autotile_editor->side_panel->show(); if (autotile_button->is_pressed()) { @@ -293,6 +291,7 @@ void TileSetEditorPlugin::make_visible(bool p_visible) { } } else { tileset_editor->hide(); + tileset_editor->menu->hide(); autotile_editor->side_panel->hide(); autotile_editor->hide(); autotile_button->hide(); @@ -333,7 +332,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); @@ -345,7 +344,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { helper = memnew(AutotileEditorHelper(this)); property_editor->edit(helper); - // Editor + //Editor dragging_point = -1; creating_shape = false; @@ -420,8 +419,6 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { p.push_back((int)SHAPE_DELETE); tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", p); tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_DELETE]); - //tools[SHAPE_CREATE_FROM_NOT_BITMASKED] = memnew(ToolButton); - //tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_CREATE_FROM_NOT_BITMASKED]); tool_containers[TOOLBAR_SHAPE]->add_change_receptor(memnew(VSeparator)); tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton); tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true); @@ -531,7 +528,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 +616,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 +1059,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 +1116,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 +1484,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 233e07c4c7..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; } } @@ -1039,9 +1084,9 @@ void ProjectManager::_load_recent_projects() { favorite->set_normal_texture(favorite_icon); if (!is_favorite) favorite->set_modulate(Color(1, 1, 1, 0.2)); - favorite->set_v_size_flags(SIZE_EXPAND); favorite->connect("pressed", this, "_favorite_pressed", varray(hb)); favorite_box->add_child(favorite); + favorite_box->set_alignment(BoxContainer::ALIGN_CENTER); hb->add_child(favorite_box); TextureRect *tf = memnew(TextureRect); @@ -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/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 7e8a6fcb6d..e7da78a35c 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -307,7 +307,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } break; case TOOL_REPLACE: { - create_dialog->popup_create(false); + create_dialog->popup_create(false, true); } break; case TOOL_ATTACH_SCRIPT: { @@ -417,7 +417,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (editor_selection->is_selected(edited_scene)) { current_option = -1; - //accept->get_cancel()->hide(); accept->get_ok()->set_text(TTR("I see..")); accept->set_text(TTR("This operation can't be done on the tree root.")); accept->popup_centered_minsize(); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index ad6ea2180f..96863a59d2 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -232,7 +232,7 @@ void ScriptCreateDialog::_lang_changed(int l) { String path = file_path->get_text(); String extension = ""; if (path != "") { - if (path.find(".") >= 0) { + if (path.find(".") != -1) { extension = path.get_extension(); } @@ -359,16 +359,14 @@ void ScriptCreateDialog::_path_changed(const String &p_path) { return; } - if (p.find("/") || p.find("\\")) { - DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES); - if (d->change_dir(p.get_base_dir()) != OK) { - _msg_path_valid(false, TTR("Invalid base path")); - memdelete(d); - _update_dialog(); - return; - } + DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (d->change_dir(p.get_base_dir()) != OK) { + _msg_path_valid(false, TTR("Invalid base path")); memdelete(d); + _update_dialog(); + return; } + memdelete(d); /* Does file already exist */ 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..1cb89e87ef 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -983,7 +983,10 @@ Error Main::setup2(Thread::ID p_main_tid_override) { Thread::_main_thread_id = p_main_tid_override; } - OS::get_singleton()->initialize(video_mode, video_driver_idx, audio_driver_idx); + Error err = OS::get_singleton()->initialize(video_mode, video_driver_idx, audio_driver_idx); + if (err != OK) { + return err; + } if (init_use_custom_pos) { OS::get_singleton()->set_window_position(init_custom_pos); } @@ -1107,7 +1110,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/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index a6337c2f6a..57db9ac51c 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -130,6 +130,9 @@ bool GDNative::initialize() { // we should pass library name to dlopen(). The library name is flattened // during export. String path = lib_path.get_file(); +#elif defined(UWP_ENABLED) + // On UWP we use a relative path from the app + String path = lib_path.replace("res://", ""); #else String path = ProjectSettings::get_singleton()->globalize_path(lib_path); #endif diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp index b2ca640cb0..6424b66d1e 100644 --- a/modules/gdnative/gdnative_library_editor_plugin.cpp +++ b/modules/gdnative/gdnative_library_editor_plugin.cpp @@ -299,8 +299,8 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() { NativePlatformConfig platform_uwp; platform_uwp.name = "Windows Universal"; platform_uwp.entries.push_back("arm"); - platform_uwp.entries.push_back("x86"); - platform_uwp.entries.push_back("x64"); + platform_uwp.entries.push_back("32"); + platform_uwp.entries.push_back("64"); platform_uwp.library_extension = "*.dll"; platforms["UWP"] = platform_uwp; 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/SCsub b/platform/android/SCsub index 0cd91276ef..d2285a82dd 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -104,7 +104,7 @@ gradle_asset_dirs_text = "" gradle_default_config_text = "" minSdk = 18 -targetSdk = 23 +targetSdk = 27 for x in env.android_default_config: if x.startswith("minSdkVersion") and int(x.split(" ")[-1]) < minSdk: diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 4a44d1c5f9..13b4d3b6c7 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -31,8 +31,8 @@ android { disable 'MissingTranslation' } - compileSdkVersion 26 - buildToolsVersion "26.0.1" + compileSdkVersion 27 + buildToolsVersion "27.0.3" useLibrary 'org.apache.http.legacy' packagingOptions { diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties index ee6901c9d7..fe37fa74a9 100644 --- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index dd23a81977..1542f4a5e4 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -120,7 +120,7 @@ void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { gl_extensions = p_gl_extensions; } -void OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { use_gl2 = p_video_driver != 1; @@ -146,6 +146,8 @@ void OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int input->set_fallback_mapping("Default Android Gamepad"); //power_manager = memnew(power_android); + + return OK; } void OS_Android::set_main_loop(MainLoop *p_main_loop) { @@ -248,6 +250,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..c0ab2acd2e 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -145,7 +145,7 @@ public: virtual const char *get_audio_driver_name(int p_driver) const; virtual void initialize_core(); - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void set_main_loop(MainLoop *p_main_loop); virtual void delete_main_loop(); @@ -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..2d1d976399 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -79,7 +79,7 @@ const char *OS_Haiku::get_video_driver_name(int p_driver) const { return "GLES3"; } -void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { main_loop = NULL; current_video_mode = p_desired; @@ -114,7 +114,7 @@ void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_ visual_server = memnew(VisualServerRaster(rasterizer)); - ERR_FAIL_COND(!visual_server); + ERR_FAIL_COND(!visual_server, ERR_UNAVAILABLE); // TODO: enable multithreaded VS /* @@ -132,6 +132,8 @@ void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_ AudioDriverManager::initialize(p_audio_driver); power_manager = memnew(PowerHaiku); + + return OK; } void OS_Haiku::finalize() { @@ -200,6 +202,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..9af15eefc0 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -66,7 +66,7 @@ protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); virtual void set_main_loop(MainLoop *p_main_loop); @@ -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..d420f95e33 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -97,7 +97,7 @@ void OSIPhone::initialize_core() { set_data_dir(data_dir); }; -void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { supported_orientations = 0; supported_orientations |= ((GLOBAL_DEF("video_mode/allow_horizontal", true) ? 1 : 0) << LandscapeLeft); @@ -144,6 +144,8 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_ //icloud->connect(); #endif Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", memnew(iOS))); + + return OK; }; MainLoop *OSIPhone::get_main_loop() const { @@ -490,6 +492,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..611bc2d4cb 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -87,7 +87,7 @@ private: virtual const char *get_video_driver_name(int p_driver) const; virtual void initialize_core(); - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void set_main_loop(MainLoop *p_main_loop); virtual MainLoop *get_main_loop() const; @@ -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/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 0bdd090ba9..665280df96 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -419,7 +419,7 @@ void send_notification(int notif) { } } -void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { print_line("Init OS"); @@ -429,7 +429,7 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i attributes.antialias = false; attributes.majorVersion = 2; EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(NULL, &attributes); - ERR_FAIL_COND(emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS); + ERR_FAIL_COND(emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS, ERR_UNAVAILABLE); video_mode = p_desired; // can't fulfil fullscreen request due to browser security @@ -507,6 +507,8 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i #undef EM_CHECK visual_server->init(); + + return OK; } void OS_JavaScript::set_main_loop(MainLoop *p_main_loop) { diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 8acaac9ef3..eaf8465be9 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -82,7 +82,7 @@ public: virtual const char *get_audio_driver_name(int p_driver) const; virtual void initialize_core(); - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void set_main_loop(MainLoop *p_main_loop); virtual void delete_main_loop(); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index a24bf6c0bc..2a71de12e9 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; @@ -121,7 +123,7 @@ protected: virtual const char *get_video_driver_name(int p_driver) const; virtual void initialize_core(); - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); virtual void set_main_loop(MainLoop *p_main_loop); @@ -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..a16391c30f 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -99,10 +99,28 @@ static Vector2 get_mouse_pos(NSEvent *event) { @implementation GodotApplication -// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost -// This works around an AppKit bug, where key up events while holding -// down the command key don't get sent to the key window. - (void)sendEvent:(NSEvent *)event { + + // special case handling of command-period, which is traditionally a special + // shortcut in macOS and doesn't arrive at our regular keyDown handler. + if ([event type] == NSKeyDown) { + if (([event modifierFlags] & NSEventModifierFlagCommand) && [event keyCode] == 0x2f) { + + Ref<InputEventKey> k; + k.instance(); + + get_key_modifier_state([event modifierFlags], k); + k->set_pressed(true); + k->set_scancode(KEY_PERIOD); + k->set_echo([event isARepeat]); + + OS_OSX::singleton->push_input(k); + } + } + + // From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost + // This works around an AppKit bug, where key up events while holding + // down the command key don't get sent to the key window. if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) [[self keyWindow] sendEvent:event]; else @@ -577,8 +595,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 { @@ -955,7 +976,7 @@ static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplay displays_arrangement_dirty = true; } -void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { /*** OSX INITIALIZATION ***/ /*** OSX INITIALIZATION ***/ @@ -992,7 +1013,7 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au backing:NSBackingStoreBuffered defer:NO]; - ERR_FAIL_COND(window_object == nil); + ERR_FAIL_COND(window_object == nil, ERR_UNAVAILABLE); window_view = [[GodotContentView alloc] init]; @@ -1079,11 +1100,11 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au #undef ADD_ATTR2 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - ERR_FAIL_COND(pixelFormat == nil); + ERR_FAIL_COND(pixelFormat == nil, ERR_UNAVAILABLE); context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; - ERR_FAIL_COND(context == nil); + ERR_FAIL_COND(context == nil, ERR_UNAVAILABLE); [context setView:window_view]; @@ -1127,6 +1148,8 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au _ensure_user_data_dir(); restore_rect = Rect2(get_window_position(), get_window_size()); + + return OK; } void OS_OSX::finalize() { @@ -1240,30 +1263,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..e8d076322c 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -47,7 +47,7 @@ const char *OS_Server::get_video_driver_name(int p_driver) const { return "Dummy"; } -void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { args = OS::get_singleton()->get_cmdline_args(); current_videomode = p_desired; @@ -67,13 +67,15 @@ void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p spatial_sound_2d_server = memnew(SpatialSound2DServerSW); spatial_sound_2d_server->init(); - ERR_FAIL_COND(!visual_server); + ERR_FAIL_COND(!visual_server, ERR_UNAVAILABLE); visual_server->init(); input = memnew(InputDefault); _ensure_user_data_dir(); + + return OK; } void OS_Server::finalize() { @@ -179,6 +181,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..6739375468 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -66,7 +66,7 @@ protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); virtual void set_main_loop(MainLoop *p_main_loop); @@ -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/export/export.cpp b/platform/uwp/export/export.cpp index f9a8b6f26e..620f6c0f24 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -1024,6 +1024,17 @@ public: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { r_features->push_back("s3tc"); r_features->push_back("etc"); + switch ((int)p_preset->get("architecture/target")) { + case EditorExportUWP::ARM: { + r_features->push_back("arm"); + } break; + case EditorExportUWP::X86: { + r_features->push_back("32"); + } break; + case EditorExportUWP::X64: { + r_features->push_back("64"); + } break; + } } virtual void get_export_options(List<ExportOption> *r_options) { diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index a665bf4aff..96f9c895bc 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -194,7 +194,7 @@ void OSUWP::screen_size_changed() { gl_context->reset(); }; -void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { main_loop = NULL; outside = true; @@ -297,6 +297,8 @@ void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_aud display_request->RequestActive(); set_keep_screen_on(GLOBAL_DEF("display/window/keep_screen_on", true)); + + return OK; } void OSUWP::set_clipboard(const String &p_text) { @@ -651,6 +653,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; @@ -745,6 +751,51 @@ void OSUWP::hide_virtual_keyboard() { pane->TryHide(); } +static String format_error_message(DWORD id) { + + LPWSTR messageBuffer = NULL; + size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); + + String msg = "Error " + itos(id) + ": " + String(messageBuffer, size); + + LocalFree(messageBuffer); + + return msg; +} + +Error OSUWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { + + String full_path = "game/" + p_path; + p_library_handle = (void *)LoadPackagedLibrary(full_path.c_str(), 0); + + if (!p_library_handle) { + ERR_EXPLAIN("Can't open dynamic library: " + full_path + ". Error: " + format_error_message(GetLastError())); + ERR_FAIL_V(ERR_CANT_OPEN); + } + return OK; +} + +Error OSUWP::close_dynamic_library(void *p_library_handle) { + if (!FreeLibrary((HMODULE)p_library_handle)) { + return FAILED; + } + return OK; +} + +Error OSUWP::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { + p_symbol_handle = (void *)GetProcAddress((HMODULE)p_library_handle, p_name.utf8().get_data()); + if (!p_symbol_handle) { + if (!p_optional) { + ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + String::num(GetLastError())); + ERR_FAIL_V(ERR_CANT_RESOLVE); + } else { + return ERR_CANT_RESOLVE; + } + } + return OK; +} + void OSUWP::run() { if (!main_loop) diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 63a2355d25..ad12b6286f 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -158,7 +158,7 @@ protected: virtual const char *get_audio_driver_name(int p_driver) const; virtual void initialize_core(); - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void set_main_loop(MainLoop *p_main_loop); virtual void delete_main_loop(); @@ -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; @@ -242,6 +243,10 @@ public: virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2()); virtual void hide_virtual_keyboard(); + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); + virtual Error close_dynamic_library(void *p_library_handle); + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); + virtual Error shell_open(String p_uri); void run(); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 8edc2c5cff..a48ae8cc8c 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -929,7 +929,7 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS { SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2 } SHC_PROCESS_DPI_AWARENESS; -void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { main_loop = NULL; outside = true; @@ -975,7 +975,7 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int if (!RegisterClassExW(&wc)) { MessageBox(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION); - return; // Return + return ERR_UNAVAILABLE; } pre_fs_valid = true; @@ -1045,7 +1045,7 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int RECT rect; if (!GetClientRect(hWnd, &rect)) { MessageBoxW(NULL, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION); - return; // Return FALSE + return ERR_UNAVAILABLE; }; video_mode.width = rect.right; video_mode.height = rect.bottom; @@ -1063,7 +1063,7 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int NULL, NULL, hInstance, NULL); if (!hWnd) { MessageBoxW(NULL, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION); - return; // Return FALSE + return ERR_UNAVAILABLE; } }; @@ -1127,6 +1127,8 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int SetForegroundWindow(hWnd); // Slightly Higher Priority SetFocus(hWnd); // Sets Keyboard Focus To } + + return OK; } void OS_Windows::set_clipboard(const String &p_text) { @@ -1844,10 +1846,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..1863642f39 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; @@ -147,7 +148,7 @@ protected: virtual const char *get_audio_driver_name(int p_driver) const; virtual void initialize_core(); - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void set_main_loop(MainLoop *p_main_loop); virtual void delete_main_loop(); @@ -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..5ca3ad45b8 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -100,7 +100,7 @@ void OS_X11::initialize_core() { OS_Unix::initialize_core(); } -void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { long im_event_mask = 0; last_button_state = 0; @@ -123,21 +123,24 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au /** XLIB INITIALIZATION **/ x11_display = XOpenDisplay(NULL); + if (!x11_display) { + ERR_PRINT("X11 Display is not available"); + return ERR_UNAVAILABLE; + } + char *modifiers = NULL; Bool xkb_dar = False; - if (x11_display) { - XAutoRepeatOn(x11_display); - xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, NULL); + XAutoRepeatOn(x11_display); + xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, NULL); - // Try to support IME if detectable auto-repeat is supported - if (xkb_dar == True) { + // Try to support IME if detectable auto-repeat is supported + if (xkb_dar == True) { #ifdef X_HAVE_UTF8_STRING - // Xutf8LookupString will be used later instead of XmbLookupString before - // the multibyte sequences can be converted to unicode string. - modifiers = XSetLocaleModifiers(""); + // Xutf8LookupString will be used later instead of XmbLookupString before + // the multibyte sequences can be converted to unicode string. + modifiers = XSetLocaleModifiers(""); #endif - } } if (modifiers == NULL) { @@ -331,8 +334,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au AudioDriverManager::initialize(p_audio_driver); - ERR_FAIL_COND(!visual_server); - ERR_FAIL_COND(x11_window == 0); + ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE); + ERR_FAIL_COND_V(x11_window == 0, ERR_UNAVAILABLE); XSetWindowAttributes new_attr; @@ -1050,13 +1053,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 +2254,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..2bf2f3cf26 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -193,17 +193,20 @@ protected: virtual const char *get_audio_driver_name(int p_driver) const; virtual void initialize_core(); - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); virtual void set_main_loop(MainLoop *p_main_loop); 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..8c6b25f296 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -131,7 +131,7 @@ void CollisionPolygon2D::_notification(int p_what) { /*if (Engine::get_singleton()->is_editor_hint()) { //display above all else set_z_as_relative(false); - set_z(VS::CANVAS_ITEM_Z_MAX - 1); + set_z_index(VS::CANVAS_ITEM_Z_MAX - 1); }*/ } break; @@ -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..1956e23421 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -64,7 +64,7 @@ void CollisionShape2D::_notification(int p_what) { /*if (Engine::get_singleton()->is_editor_hint()) { //display above all else set_z_as_relative(false); - set_z(VS::CANVAS_ITEM_Z_MAX - 1); + set_z_index(VS::CANVAS_ITEM_Z_MAX - 1); }*/ } break; @@ -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/node_2d.cpp b/scene/2d/node_2d.cpp index 2a305512af..e133f86ef7 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -329,13 +329,13 @@ void Node2D::set_global_transform(const Transform2D &p_transform) { set_transform(p_transform); } -void Node2D::set_z(int p_z) { +void Node2D::set_z_index(int p_z) { ERR_FAIL_COND(p_z < VS::CANVAS_ITEM_Z_MIN); ERR_FAIL_COND(p_z > VS::CANVAS_ITEM_Z_MAX); - z = p_z; - VS::get_singleton()->canvas_item_set_z(get_canvas_item(), z); - _change_notify("z"); + z_index = p_z; + VS::get_singleton()->canvas_item_set_z_index(get_canvas_item(), z_index); + _change_notify("z_index"); } void Node2D::set_z_as_relative(bool p_enabled) { @@ -351,9 +351,9 @@ bool Node2D::is_z_relative() const { return z_relative; } -int Node2D::get_z() const { +int Node2D::get_z_index() const { - return z; + return z_index; } Transform2D Node2D::get_relative_transform_to_parent(const Node *p_parent) const { @@ -427,8 +427,8 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node2D::to_local); ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node2D::to_global); - ClassDB::bind_method(D_METHOD("set_z", "z"), &Node2D::set_z); - ClassDB::bind_method(D_METHOD("get_z"), &Node2D::get_z); + ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &Node2D::set_z_index); + ClassDB::bind_method(D_METHOD("get_z_index"), &Node2D::get_z_index); ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative); ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative); @@ -448,8 +448,8 @@ void Node2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_scale", PROPERTY_HINT_NONE, "", 0), "set_global_scale", "get_global_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform"); - ADD_GROUP("Z", ""); - ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "z", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z", "get_z"); + ADD_GROUP("Z Index", ""); + ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative"); } @@ -458,6 +458,6 @@ Node2D::Node2D() { angle = 0; _scale = Vector2(1, 1); _xform_dirty = false; - z = 0; + z_index = 0; z_relative = true; } diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 7d2e5aa00c..321021a748 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -39,7 +39,7 @@ class Node2D : public CanvasItem { Point2 pos; float angle; Size2 _scale; - int z; + int z_index; bool z_relative; Transform2D _mat; @@ -96,8 +96,8 @@ public: void set_global_rotation_degrees(float p_degrees); void set_global_scale(const Size2 &p_scale); - void set_z(int p_z); - int get_z() const; + void set_z_index(int p_z); + int get_z_index() const; void look_at(const Vector2 &p_pos); float get_angle_to(const Vector2 &p_pos) 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/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 73fce4be75..8bd5676bc7 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -336,7 +336,7 @@ void TileMap::_update_dirty_quadrants() { debug_canvas_item = vs->canvas_item_create(); vs->canvas_item_set_parent(debug_canvas_item, canvas_item); vs->canvas_item_set_z_as_relative_to_parent(debug_canvas_item, false); - vs->canvas_item_set_z(debug_canvas_item, VS::CANVAS_ITEM_Z_MAX - 1); + vs->canvas_item_set_z_index(debug_canvas_item, VS::CANVAS_ITEM_Z_MAX - 1); q.canvas_items.push_back(debug_canvas_item); prev_debug_canvas_item = debug_canvas_item; } diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index ef60a2151d..aaa378bb68 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -160,14 +160,14 @@ void Skeleton::_notification(int p_what) { //if moved, just update transforms VisualServer *vs = VisualServer::get_singleton(); - Bone *bonesptr = &bones[0]; + const Bone *bonesptr = bones.ptr(); int len = bones.size(); Transform global_transform = get_global_transform(); Transform global_transform_inverse = global_transform.affine_inverse(); for (int i = 0; i < len; i++) { - Bone &b = bonesptr[i]; + const Bone &b = bonesptr[i]; vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse)); } } break; diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 8b5c85763a..a55c4a2cc5 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -555,30 +555,36 @@ bool Spatial::is_visible() const { return data.visible; } -void Spatial::rotate(const Vector3 &p_normal, float p_radians) { +void Spatial::rotate_object_local(const Vector3 &p_axis, float p_angle) { + Transform t = get_transform(); + t.basis.rotate_local(p_axis, p_angle); + set_transform(t); +} + +void Spatial::rotate(const Vector3 &p_axis, float p_angle) { Transform t = get_transform(); - t.basis.rotate_local(p_normal, p_radians); //use local rotation here, as it makes more sense here in tree hierarchy + t.basis.rotate(p_axis, p_angle); set_transform(t); } -void Spatial::rotate_x(float p_radians) { +void Spatial::rotate_x(float p_angle) { Transform t = get_transform(); - t.basis.rotate_local(Vector3(1, 0, 0), p_radians); + t.basis.rotate(Vector3(1, 0, 0), p_angle); set_transform(t); } -void Spatial::rotate_y(float p_radians) { +void Spatial::rotate_y(float p_angle) { Transform t = get_transform(); - t.basis.rotate_local(Vector3(0, 1, 0), p_radians); + t.basis.rotate(Vector3(0, 1, 0), p_angle); set_transform(t); } -void Spatial::rotate_z(float p_radians) { +void Spatial::rotate_z(float p_angle) { Transform t = get_transform(); - t.basis.rotate_local(Vector3(0, 0, 1), p_radians); + t.basis.rotate(Vector3(0, 0, 1), p_angle); set_transform(t); } @@ -589,19 +595,45 @@ void Spatial::translate(const Vector3 &p_offset) { set_transform(t); } +void Spatial::translate_object_local(const Vector3 &p_offset) { + Transform t = get_transform(); + + Transform s; + s.translate(p_offset); + set_transform(t * s); +} + void Spatial::scale(const Vector3 &p_ratio) { Transform t = get_transform(); t.basis.scale(p_ratio); set_transform(t); } -void Spatial::global_rotate(const Vector3 &p_normal, float p_radians) { - Basis rotation(p_normal, p_radians); +void Spatial::scale_object_local(const Vector3 &p_scale) { + Transform t = get_transform(); + t.basis.scale_local(p_scale); + set_transform(t); +} + +void Spatial::global_rotate(const Vector3 &p_axis, float p_angle) { + + Basis rotation(p_axis, p_angle); Transform t = get_global_transform(); t.basis = rotation * t.basis; set_global_transform(t); } + +void Spatial::global_scale(const Vector3 &p_scale) { + + Basis s; + s.set_scale(p_scale); + + Transform t = get_global_transform(); + t.basis = s * t.basis; + set_global_transform(t); +} + void Spatial::global_translate(const Vector3 &p_offset) { Transform t = get_global_transform(); t.origin += p_offset; @@ -620,7 +652,7 @@ void Spatial::set_identity() { set_transform(Transform()); } -void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up_normal) { +void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) { Transform lookat; lookat.origin = get_global_transform().origin; @@ -629,19 +661,19 @@ void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up_normal) { ERR_FAIL(); } - if (p_up_normal.cross(p_target - lookat.origin) == Vector3()) { + if (p_up.cross(p_target - lookat.origin) == Vector3()) { ERR_EXPLAIN("Up vector and direction between node origin and target are aligned, look_at() failed"); ERR_FAIL(); } - lookat = lookat.looking_at(p_target, p_up_normal); + lookat = lookat.looking_at(p_target, p_up); set_global_transform(lookat); } -void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up_normal) { +void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { Transform lookat; lookat.origin = p_pos; - lookat = lookat.looking_at(p_target, p_up_normal); + lookat = lookat.looking_at(p_target, p_up); set_global_transform(lookat); } @@ -677,9 +709,9 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("get_transform"), &Spatial::get_transform); ClassDB::bind_method(D_METHOD("set_translation", "translation"), &Spatial::set_translation); ClassDB::bind_method(D_METHOD("get_translation"), &Spatial::get_translation); - ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Spatial::set_rotation); + ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Spatial::set_rotation); ClassDB::bind_method(D_METHOD("get_rotation"), &Spatial::get_rotation); - ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Spatial::set_rotation_degrees); + ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Spatial::set_rotation_degrees); ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Spatial::get_rotation_degrees); ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Spatial::set_scale); ClassDB::bind_method(D_METHOD("get_scale"), &Spatial::get_scale); @@ -711,22 +743,26 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &Spatial::set_notify_transform); ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &Spatial::is_transform_notification_enabled); - void rotate(const Vector3 &p_normal, float p_radians); - void rotate_x(float p_radians); - void rotate_y(float p_radians); - void rotate_z(float p_radians); + void rotate(const Vector3 &p_axis, float p_angle); + void rotate_x(float p_angle); + void rotate_y(float p_angle); + void rotate_z(float p_angle); void translate(const Vector3 &p_offset); void scale(const Vector3 &p_ratio); - void global_rotate(const Vector3 &p_normal, float p_radians); + void global_rotate(const Vector3 &p_axis, float p_angle); void global_translate(const Vector3 &p_offset); - ClassDB::bind_method(D_METHOD("rotate", "normal", "radians"), &Spatial::rotate); - ClassDB::bind_method(D_METHOD("global_rotate", "normal", "radians"), &Spatial::global_rotate); - ClassDB::bind_method(D_METHOD("rotate_x", "radians"), &Spatial::rotate_x); - ClassDB::bind_method(D_METHOD("rotate_y", "radians"), &Spatial::rotate_y); - ClassDB::bind_method(D_METHOD("rotate_z", "radians"), &Spatial::rotate_z); - ClassDB::bind_method(D_METHOD("translate", "offset"), &Spatial::translate); + ClassDB::bind_method(D_METHOD("rotate", "axis", "angle"), &Spatial::rotate); + ClassDB::bind_method(D_METHOD("global_rotate", "axis", "angle"), &Spatial::global_rotate); + ClassDB::bind_method(D_METHOD("global_scale", "scale"), &Spatial::global_scale); ClassDB::bind_method(D_METHOD("global_translate", "offset"), &Spatial::global_translate); + ClassDB::bind_method(D_METHOD("rotate_object_local", "axis", "angle"), &Spatial::rotate_object_local); + ClassDB::bind_method(D_METHOD("scale_object_local", "scale"), &Spatial::scale_object_local); + ClassDB::bind_method(D_METHOD("translate_object_local", "offset"), &Spatial::translate_object_local); + ClassDB::bind_method(D_METHOD("rotate_x", "angle"), &Spatial::rotate_x); + ClassDB::bind_method(D_METHOD("rotate_y", "angle"), &Spatial::rotate_y); + ClassDB::bind_method(D_METHOD("rotate_z", "angle"), &Spatial::rotate_z); + ClassDB::bind_method(D_METHOD("translate", "offset"), &Spatial::translate); ClassDB::bind_method(D_METHOD("orthonormalize"), &Spatial::orthonormalize); ClassDB::bind_method(D_METHOD("set_identity"), &Spatial::set_identity); diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 5ebe2f5214..1c2e73d5ba 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -158,17 +158,23 @@ public: Transform get_relative_transform(const Node *p_parent) const; - void rotate(const Vector3 &p_normal, float p_radians); - void rotate_x(float p_radians); - void rotate_y(float p_radians); - void rotate_z(float p_radians); + void rotate(const Vector3 &p_axis, float p_angle); + void rotate_x(float p_angle); + void rotate_y(float p_angle); + void rotate_z(float p_angle); void translate(const Vector3 &p_offset); void scale(const Vector3 &p_ratio); - void global_rotate(const Vector3 &p_normal, float p_radians); + + void rotate_object_local(const Vector3 &p_axis, float p_angle); + void scale_object_local(const Vector3 &p_scale); + void translate_object_local(const Vector3 &p_offset); + + void global_rotate(const Vector3 &p_axis, float p_angle); + void global_scale(const Vector3 &p_scale); void global_translate(const Vector3 &p_offset); - void look_at(const Vector3 &p_target, const Vector3 &p_up_normal); - void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up_normal); + void look_at(const Vector3 &p_target, const Vector3 &p_up); + void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up); Vector3 to_local(Vector3 p_global) const; Vector3 to_global(Vector3 p_local) const; 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/color_picker.cpp b/scene/gui/color_picker.cpp index 95298f5a18..63478886c6 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -209,6 +209,7 @@ Color ColorPicker::get_pick_color() const { } void ColorPicker::add_preset(const Color &p_color) { + if (presets.find(p_color)) { presets.move_to_back(presets.find(p_color)); } else { 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/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 4f2cfccd4a..bf048ea1b6 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -371,19 +371,20 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & cw = tab_size * font->get_char_size(' ').width; } - if (underline) { - Color uc = color; - uc.a *= 0.5; - int uy = y + lh - fh + ascent + 2; - float underline_width = 1.0; -#ifdef TOOLS_ENABLED - underline_width *= EDSCALE; -#endif - VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + pofs, uy), p_ofs + Point2(align_ofs + pofs + cw, uy), uc, underline_width); - } ofs += cw; } } + + if (underline) { + Color uc = color; + uc.a *= 0.5; + int uy = y + lh - fh + ascent + 2; + float underline_width = 1.0; +#ifdef TOOLS_ENABLED + underline_width *= EDSCALE; +#endif + VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, underline_width); + } } ADVANCE(fw); @@ -451,6 +452,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & table->columns[i].width = 0; } //compute minimum width for each cell + const int available_width = p_width - hseparation * (table->columns.size() - 1) - wofs; + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { ERR_CONTINUE(E->get()->type != ITEM_FRAME); //children should all be frames ItemFrame *frame = static_cast<ItemFrame *>(E->get()); @@ -461,7 +464,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < frame->lines.size(); i++) { - _process_line(frame, Point2(), ly, p_width, i, PROCESS_CACHE, cfont, Color()); + _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color()); table->columns[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width); } idx++; @@ -470,11 +473,11 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & //compute available width and total ratio (for expanders) int total_ratio = 0; - int available_width = p_width - hseparation * (table->columns.size() - 1); + int remaining_width = available_width; table->total_width = hseparation; for (int i = 0; i < table->columns.size(); i++) { - available_width -= table->columns[i].min_width; + remaining_width -= table->columns[i].min_width; if (table->columns[i].expand) total_ratio += table->columns[i].expand_ratio; } @@ -484,7 +487,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < table->columns.size(); i++) { table->columns[i].width = table->columns[i].min_width; if (table->columns[i].expand) - table->columns[i].width += table->columns[i].expand_ratio * available_width / total_ratio; + table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; table->total_width += table->columns[i].width + hseparation; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 46ad956b68..87043c65eb 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1498,7 +1498,7 @@ void TextEdit::_notification(int p_what) { if (OS::get_singleton()->has_virtual_keyboard()) OS::get_singleton()->show_virtual_keyboard(get_text(), get_global_rect()); if (raised_from_completion) { - VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 1); + VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1); } } break; @@ -1512,7 +1512,7 @@ void TextEdit::_notification(int p_what) { if (OS::get_singleton()->has_virtual_keyboard()) OS::get_singleton()->hide_virtual_keyboard(); if (raised_from_completion) { - VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 0); + VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0); } } break; } @@ -1822,10 +1822,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->is_pressed()) { if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) { - _scroll_up(3 * mb->get_factor()); + if (mb->get_shift()) { + h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor())); + } else { + _scroll_up(3 * mb->get_factor()); + } } if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) { - _scroll_down(3 * mb->get_factor()); + if (mb->get_shift()) { + h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor())); + } else { + _scroll_down(3 * mb->get_factor()); + } } if (mb->get_button_index() == BUTTON_WHEEL_LEFT) { h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor())); @@ -2581,22 +2589,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc == 0 && cursor.line > 0) { cursor_set_line(cursor.line - 1); cursor_set_column(text[cursor.line].length()); - break; - } - - while (cc > 0) { - - bool ischar = _is_text_char(text[cursor.line][cc - 1]); + } else { + while (cc > 0) { + bool ischar = _is_text_char(text[cursor.line][cc - 1]); - if (prev_char && !ischar) - break; + if (prev_char && !ischar) + break; - prev_char = ischar; - cc--; + prev_char = ischar; + cc--; + } + cursor_set_column(cc); } - cursor_set_column(cc); - } else if (cursor.column == 0) { if (cursor.line > 0) { @@ -2645,21 +2650,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc == text[cursor.line].length() && cursor.line < text.size() - 1) { cursor_set_line(cursor.line + 1); cursor_set_column(0); - break; - } - - while (cc < text[cursor.line].length()) { - - bool ischar = _is_text_char(text[cursor.line][cc]); + } else { + while (cc < text[cursor.line].length()) { + bool ischar = _is_text_char(text[cursor.line][cc]); - if (prev_char && !ischar) - break; - prev_char = ischar; - cc++; + if (prev_char && !ischar) + break; + prev_char = ischar; + cc++; + } + cursor_set_column(cc); } - cursor_set_column(cc); - } else if (cursor.column == text[cursor.line].length()) { if (cursor.line < text.size() - 1) { @@ -2731,6 +2733,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(); @@ -2739,9 +2743,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(); @@ -3137,6 +3147,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 { @@ -3147,8 +3160,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); } @@ -3156,6 +3173,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 { @@ -3172,8 +3192,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); } @@ -4590,6 +4615,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); @@ -5019,7 +5062,7 @@ void TextEdit::_confirm_completion() { void TextEdit::_cancel_code_hint() { - VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 0); + VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0); raised_from_completion = false; completion_hint = ""; update(); @@ -5027,7 +5070,7 @@ void TextEdit::_cancel_code_hint() { void TextEdit::_cancel_completion() { - VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 0); + VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0); raised_from_completion = false; if (!completion_active) return; @@ -5202,7 +5245,7 @@ void TextEdit::query_code_comple() { void TextEdit::set_code_hint(const String &p_hint) { - VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 1); + VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1); raised_from_completion = true; completion_hint = p_hint; completion_hint_offset = -0xFFFF; @@ -5211,7 +5254,7 @@ void TextEdit::set_code_hint(const String &p_hint) { void TextEdit::code_complete(const Vector<String> &p_strings, bool p_forced) { - VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 1); + VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1); raised_from_completion = true; completion_strings = p_strings; completion_active = true; 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/gui/tree.cpp b/scene/gui/tree.cpp index 08f1bdff3d..b1a421c24f 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1423,17 +1423,33 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 #endif Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; - VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color, line_width); + + if (root_pos.y + line_width >= 0) { + VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color, line_width); + } + + if (htotal < 0) { + return -1; + } } - int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c); + if (htotal >= 0) { + int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c); - if (child_h < 0 && cache.draw_relationship_lines == 0) - return -1; // break, stop drawing, no need to anymore + if (child_h < 0) { + if (cache.draw_relationship_lines == 0) { + return -1; // break, stop drawing, no need to anymore + } else { + htotal = -1; + children_pos.y = cache.offset.y + p_draw_size.height; + } + } else { + htotal += child_h; + children_pos.y += child_h; + } + } - htotal += child_h; - children_pos.y += child_h; c = c->next; } } @@ -2352,8 +2368,6 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { last_keypress = 0; } } break; - - last_keypress = 0; } } 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/register_scene_types.cpp b/scene/register_scene_types.cpp index 4036735807..998c790c94 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -220,31 +220,17 @@ void register_scene_types() { resource_loader_theme = memnew(ResourceFormatLoaderTheme); ResourceLoader::add_resource_format_loader(resource_loader_theme); - bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - String theme_path = GLOBAL_DEF("gui/theme/custom", ""); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - String font_path = GLOBAL_DEF("gui/theme/custom_font", ""); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + resource_saver_text = memnew(ResourceFormatSaverText); + ResourceSaver::add_resource_format_saver(resource_saver_text, true); - bool has_theme = false; - if (theme_path != String()) { - Ref<Theme> theme = ResourceLoader::load(theme_path); - if (theme.is_valid()) { - Theme::set_default(theme); - has_theme = true; - } else { - ERR_PRINTS("Error loading custom theme '" + theme_path + "'"); - } - } + resource_loader_text = memnew(ResourceFormatLoaderText); + ResourceLoader::add_resource_format_loader(resource_loader_text, true); - if (!has_theme) { - Ref<Font> font; - if (font_path != String()) { - font = ResourceLoader::load(font_path); - } - make_default_theme(default_theme_hidpi, font); - } + resource_saver_shader = memnew(ResourceFormatSaverShader); + ResourceSaver::add_resource_format_saver(resource_saver_shader, true); + + resource_loader_shader = memnew(ResourceFormatLoaderShader); + ResourceLoader::add_resource_format_loader(resource_loader_shader, true); OS::get_singleton()->yield(); //may take time to init @@ -604,24 +590,42 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init - resource_saver_text = memnew(ResourceFormatSaverText); - ResourceSaver::add_resource_format_saver(resource_saver_text, true); - - resource_loader_text = memnew(ResourceFormatLoaderText); - ResourceLoader::add_resource_format_loader(resource_loader_text, true); - - resource_saver_shader = memnew(ResourceFormatSaverShader); - ResourceSaver::add_resource_format_saver(resource_saver_shader, true); - - resource_loader_shader = memnew(ResourceFormatLoaderShader); - ResourceLoader::add_resource_format_loader(resource_loader_shader, true); - for (int i = 0; i < 20; i++) { GLOBAL_DEF("layer_names/2d_render/layer_" + itos(i + 1), ""); GLOBAL_DEF("layer_names/2d_physics/layer_" + itos(i + 1), ""); GLOBAL_DEF("layer_names/3d_render/layer_" + itos(i + 1), ""); GLOBAL_DEF("layer_names/3d_physics/layer_" + itos(i + 1), ""); } + + bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + String theme_path = GLOBAL_DEF("gui/theme/custom", ""); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + String font_path = GLOBAL_DEF("gui/theme/custom_font", ""); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + Ref<Font> font; + if (font_path != String()) { + font = ResourceLoader::load(font_path); + if (!font.is_valid()) { + ERR_PRINTS("Error loading custom font '" + font_path + "'"); + } + } + + // Always make the default theme to avoid invalid default font/icon/style in the given theme + make_default_theme(default_theme_hidpi, font); + + if (theme_path != String()) { + Ref<Theme> theme = ResourceLoader::load(theme_path); + if (theme.is_valid()) { + Theme::set_default(theme); + if (font.is_valid()) { + Theme::set_default_font(font); + } + } else { + ERR_PRINTS("Error loading custom theme '" + theme_path + "'"); + } + } } void unregister_scene_types() { 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/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index b18583dfb1..a4049e4461 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -880,7 +880,7 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) { Ref<StyleBox> default_style; Ref<Texture> default_icon; - Ref<BitmapFont> default_font; + Ref<Font> default_font; if (p_font.is_valid()) { default_font = p_font; } else if (p_hidpi) { @@ -888,7 +888,7 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) { } else { default_font = make_font2(_lodpi_font_height, _lodpi_font_ascent, _lodpi_font_charcount, &_lodpi_font_charrects[0][0], _lodpi_font_kerning_pair_count, &_lodpi_font_kerning_pairs[0][0], _lodpi_font_img_width, _lodpi_font_img_height, _lodpi_font_img_data); } - Ref<BitmapFont> large_font = default_font; + Ref<Font> large_font = default_font; fill_default_theme(t, default_font, large_font, default_icon, default_style, p_hidpi ? 2.0 : 1.0); Theme::set_default(t); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 6216893667..b2c91f90eb 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1218,7 +1218,7 @@ Environment::Environment() { ssao_radius2 = 0; ssao_intensity2 = 1; ssao_bias = 0.01; - ssao_direct_light_affect = false; + ssao_direct_light_affect = 0.0; ssao_blur = SSAO_BLUR_3x3; set_ssao_edge_sharpness(4); set_ssao_quality(SSAO_QUALITY_LOW); 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/audio_server.cpp b/servers/audio_server.cpp index 0317fe45ae..f2198bdf2f 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -122,7 +122,6 @@ int AudioDriverManager::get_driver_count() { } void AudioDriverManager::initialize(int p_driver) { - AudioDriver *driver; int failed_driver = -1; // Check if there is a selected driver diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 60530e48e2..b163402a07 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -102,9 +102,9 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor } if (ci->z_relative) - p_z = CLAMP(p_z + ci->z, VS::CANVAS_ITEM_Z_MIN, VS::CANVAS_ITEM_Z_MAX); + p_z = CLAMP(p_z + ci->z_index, VS::CANVAS_ITEM_Z_MIN, VS::CANVAS_ITEM_Z_MAX); else - p_z = ci->z; + p_z = ci->z_index; for (int i = 0; i < child_item_count; i++) { @@ -805,14 +805,14 @@ void VisualServerCanvas::canvas_item_set_sort_children_by_y(RID p_item, bool p_e canvas_item->sort_y = p_enable; } -void VisualServerCanvas::canvas_item_set_z(RID p_item, int p_z) { +void VisualServerCanvas::canvas_item_set_z_index(RID p_item, int p_z) { ERR_FAIL_COND(p_z < VS::CANVAS_ITEM_Z_MIN || p_z > VS::CANVAS_ITEM_Z_MAX); Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - canvas_item->z = p_z; + canvas_item->z_index = p_z; } void VisualServerCanvas::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) { diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index b86dd0316c..320fc2fb0b 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -39,7 +39,7 @@ public: RID parent; // canvas it belongs to List<Item *>::Element *E; - int z; + int z_index; bool z_relative; bool sort_y; Color modulate; @@ -53,7 +53,7 @@ public: Item() { children_order_dirty = true; E = NULL; - z = 0; + z_index = 0; modulate = Color(1, 1, 1, 1); self_modulate = Color(1, 1, 1, 1); sort_y = false; @@ -187,7 +187,7 @@ public: void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform); void canvas_item_add_clip_ignore(RID p_item, bool p_ignore); void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable); - void canvas_item_set_z(RID p_item, int p_z); + void canvas_item_set_z_index(RID p_item, int p_z); void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable); void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 95d7269d7a..864ae81140 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -586,7 +586,7 @@ public: BIND2(canvas_item_add_set_transform, RID, const Transform2D &) BIND2(canvas_item_add_clip_ignore, RID, bool) BIND2(canvas_item_set_sort_children_by_y, RID, bool) - BIND2(canvas_item_set_z, RID, int) + BIND2(canvas_item_set_z_index, RID, int) BIND2(canvas_item_set_z_as_relative_to_parent, RID, bool) BIND3(canvas_item_set_copy_to_backbuffer, RID, bool, const Rect2 &) 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..276e445f4d 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 */ @@ -503,7 +504,7 @@ public: FUNC2(canvas_item_add_set_transform, RID, const Transform2D &) FUNC2(canvas_item_add_clip_ignore, RID, bool) FUNC2(canvas_item_set_sort_children_by_y, RID, bool) - FUNC2(canvas_item_set_z, RID, int) + FUNC2(canvas_item_set_z_index, RID, int) FUNC2(canvas_item_set_z_as_relative_to_parent, RID, bool) FUNC3(canvas_item_set_copy_to_backbuffer, RID, bool, const Rect2 &) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index b4949b6093..bf6d425fb9 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1611,7 +1611,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &VisualServer::canvas_item_add_set_transform); ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &VisualServer::canvas_item_add_clip_ignore); ClassDB::bind_method(D_METHOD("canvas_item_set_sort_children_by_y", "item", "enabled"), &VisualServer::canvas_item_set_sort_children_by_y); - ClassDB::bind_method(D_METHOD("canvas_item_set_z", "item", "z"), &VisualServer::canvas_item_set_z); + ClassDB::bind_method(D_METHOD("canvas_item_set_z_index", "item", "z_index"), &VisualServer::canvas_item_set_z_index); ClassDB::bind_method(D_METHOD("canvas_item_set_z_as_relative_to_parent", "item", "enabled"), &VisualServer::canvas_item_set_z_as_relative_to_parent); ClassDB::bind_method(D_METHOD("canvas_item_set_copy_to_backbuffer", "item", "enabled", "rect"), &VisualServer::canvas_item_set_copy_to_backbuffer); ClassDB::bind_method(D_METHOD("canvas_item_clear", "item"), &VisualServer::canvas_item_clear); diff --git a/servers/visual_server.h b/servers/visual_server.h index e1def0b713..eb2c56cd3a 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -847,7 +847,7 @@ public: virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0; virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0; virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0; - virtual void canvas_item_set_z(RID p_item, int p_z) = 0; + virtual void canvas_item_set_z_index(RID p_item, int p_z) = 0; virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) = 0; virtual void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) = 0; 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); |