summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/image.cpp24
-rw-r--r--core/image.h1
-rw-r--r--core/math/geometry.cpp11
-rw-r--r--core/math/geometry.h3
-rw-r--r--core/math/matrix3.cpp17
-rw-r--r--core/math/matrix3.h3
-rw-r--r--core/os/input.cpp20
-rw-r--r--core/os/input.h25
-rw-r--r--core/os/os.h1
-rw-r--r--core/script_debugger_remote.cpp21
-rw-r--r--core/variant_call.cpp5
-rw-r--r--doc/classes/@GDScript.xml5
-rw-r--r--doc/classes/@GlobalScope.xml60
-rw-r--r--doc/classes/ARVRServer.xml2
-rw-r--r--doc/classes/AStar.xml2
-rw-r--r--doc/classes/BakedLightmap.xml28
-rw-r--r--doc/classes/Basis.xml2
-rw-r--r--doc/classes/Camera.xml3
-rw-r--r--doc/classes/Image.xml78
-rw-r--r--doc/classes/Input.xml39
-rw-r--r--doc/classes/InputEvent.xml15
-rw-r--r--doc/classes/MenuButton.xml8
-rw-r--r--doc/classes/Physics2DServer.xml12
-rw-r--r--doc/classes/SceneTree.xml16
-rw-r--r--doc/classes/ScriptEditor.xml16
-rw-r--r--doc/classes/Spatial.xml76
-rw-r--r--doc/classes/StreamPeer.xml2
-rw-r--r--doc/classes/TextEdit.xml2
-rw-r--r--doc/classes/TileMap.xml2
-rw-r--r--doc/classes/TileSet.xml6
-rw-r--r--doc/classes/Tree.xml2
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp10
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp9
-rw-r--r--drivers/gles3/shaders/canvas.glsl4
-rw-r--r--editor/code_editor.cpp2
-rw-r--r--editor/editor_fonts.cpp17
-rw-r--r--editor/editor_log.cpp2
-rw-r--r--editor/editor_node.cpp3
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--editor/editor_themes.cpp11
-rw-r--r--editor/filesystem_dock.cpp14
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp16
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp69
-rw-r--r--editor/plugins/tile_set_editor_plugin.h1
-rw-r--r--editor/project_manager.cpp138
-rw-r--r--editor/script_editor_debugger.cpp67
-rw-r--r--editor/script_editor_debugger.h10
-rw-r--r--main/input_default.cpp20
-rw-r--r--main/input_default.h2
-rw-r--r--main/main.cpp2
-rw-r--r--modules/gdnative/gdnative.cpp3
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp4
-rw-r--r--modules/gdscript/gdscript_function.cpp2
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml42
-rw-r--r--modules/gridmap/grid_map.cpp80
-rw-r--r--modules/gridmap/grid_map.h16
-rw-r--r--modules/thekla_unwrap/register_types.cpp7
-rw-r--r--modules/theora/video_stream_theora.cpp9
-rw-r--r--platform/android/os_android.cpp3
-rw-r--r--platform/android/os_android.h1
-rw-r--r--platform/haiku/os_haiku.cpp4
-rw-r--r--platform/haiku/os_haiku.h1
-rw-r--r--platform/iphone/os_iphone.cpp2
-rw-r--r--platform/iphone/os_iphone.h1
-rw-r--r--platform/osx/os_osx.h3
-rw-r--r--platform/osx/os_osx.mm97
-rw-r--r--platform/server/os_server.cpp3
-rw-r--r--platform/server/os_server.h1
-rw-r--r--platform/uwp/export/export.cpp11
-rw-r--r--platform/uwp/os_uwp.cpp49
-rw-r--r--platform/uwp/os_uwp.h5
-rw-r--r--platform/windows/os_windows.cpp117
-rw-r--r--platform/windows/os_windows.h3
-rw-r--r--platform/x11/os_x11.cpp92
-rw-r--r--platform/x11/os_x11.h3
-rw-r--r--scene/2d/canvas_item.h1
-rw-r--r--scene/2d/collision_polygon_2d.cpp5
-rw-r--r--scene/2d/collision_polygon_2d.h1
-rw-r--r--scene/2d/collision_shape_2d.cpp8
-rw-r--r--scene/2d/collision_shape_2d.h1
-rw-r--r--scene/2d/line_2d.cpp26
-rw-r--r--scene/2d/line_2d.h3
-rw-r--r--scene/2d/navigation_polygon.cpp60
-rw-r--r--scene/2d/navigation_polygon.h9
-rw-r--r--scene/2d/path_2d.cpp54
-rw-r--r--scene/2d/path_2d.h3
-rw-r--r--scene/2d/polygon_2d.cpp7
-rw-r--r--scene/2d/polygon_2d.h1
-rw-r--r--scene/2d/sprite.cpp93
-rw-r--r--scene/2d/sprite.h3
-rw-r--r--scene/3d/spatial.cpp92
-rw-r--r--scene/3d/spatial.h20
-rw-r--r--scene/animation/animation_player.cpp21
-rw-r--r--scene/animation/animation_player.h1
-rw-r--r--scene/animation/tween.cpp85
-rw-r--r--scene/gui/item_list.cpp9
-rw-r--r--scene/gui/item_list.h4
-rw-r--r--scene/gui/line_edit.cpp12
-rw-r--r--scene/gui/text_edit.cpp95
-rw-r--r--scene/gui/text_edit.h1
-rw-r--r--scene/main/scene_tree.cpp1
-rw-r--r--scene/resources/capsule_shape_2d.cpp29
-rw-r--r--scene/resources/capsule_shape_2d.h3
-rw-r--r--scene/resources/circle_shape_2d.cpp6
-rw-r--r--scene/resources/circle_shape_2d.h2
-rw-r--r--scene/resources/concave_polygon_shape_2d.cpp17
-rw-r--r--scene/resources/concave_polygon_shape_2d.h2
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp5
-rw-r--r--scene/resources/convex_polygon_shape_2d.h2
-rw-r--r--scene/resources/segment_shape_2d.cpp7
-rw-r--r--scene/resources/segment_shape_2d.h2
-rw-r--r--scene/resources/shape_2d.h2
-rw-r--r--scene/resources/shape_line_2d.cpp15
-rw-r--r--scene/resources/shape_line_2d.h2
-rw-r--r--thirdparty/thekla_atlas/godot-changes.patch154
-rw-r--r--thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp6
116 files changed, 1901 insertions, 434 deletions
diff --git a/core/image.cpp b/core/image.cpp
index 11429b8782..2f2d7efd7c 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -47,6 +47,7 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
"RGBA8",
"RGBA4444",
"RGBA5551",
+ "RGB10A2",
"RFloat", //float
"RGFloat",
"RGBFloat",
@@ -112,6 +113,7 @@ int Image::get_format_pixel_size(Format p_format) {
case FORMAT_RGBA8: return 4;
case FORMAT_RGBA4444: return 2;
case FORMAT_RGBA5551: return 2;
+ case FORMAT_RGB10A2: return 4;
case FORMAT_RF:
return 4; //float
case FORMAT_RGF: return 8;
@@ -1978,6 +1980,15 @@ Color Image::get_pixel(int p_x, int p_y) const {
float a = ((u >> 15) & 0x1) / 1.0;
return Color(r, g, b, a);
} break;
+ case FORMAT_RGB10A2: {
+
+ uint32_t u = ((uint32_t *)ptr)[ofs];
+ float r = (u & 0x3FF) / 1023.0;
+ float g = ((u >> 10) & 0x3FF) / 1023.0;
+ float b = ((u >> 20) & 0x3FF) / 1023.0;
+ float a = ((u >> 30) & 0x3) / 3.0;
+ return Color(r, g, b, a);
+ } break;
case FORMAT_RF: {
float r = ((float *)ptr)[ofs];
@@ -2123,6 +2134,18 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
((uint16_t *)ptr)[ofs] = rgba;
} break;
+ case FORMAT_RGB10A2: {
+
+ uint32_t rgba = 0;
+
+ rgba = uint32_t(CLAMP(p_color.r * 1023.0, 0, 1023));
+ rgba |= uint32_t(CLAMP(p_color.g * 1023.0, 0, 1023)) << 10;
+ rgba |= uint32_t(CLAMP(p_color.b * 1023.0, 0, 1023)) << 20;
+ rgba |= uint32_t(CLAMP(p_color.a * 3.0, 0, 3)) << 30;
+
+ ((uint32_t *)ptr)[ofs] = rgba;
+
+ } break;
case FORMAT_RF: {
((float *)ptr)[ofs] = p_color.r;
@@ -2300,6 +2323,7 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(FORMAT_RGBA8);
BIND_ENUM_CONSTANT(FORMAT_RGBA4444);
BIND_ENUM_CONSTANT(FORMAT_RGBA5551);
+ BIND_ENUM_CONSTANT(FORMAT_RGB10A2);
BIND_ENUM_CONSTANT(FORMAT_RF); //float
BIND_ENUM_CONSTANT(FORMAT_RGF);
BIND_ENUM_CONSTANT(FORMAT_RGBF);
diff --git a/core/image.h b/core/image.h
index 767f3c6ac5..efb62a6a29 100644
--- a/core/image.h
+++ b/core/image.h
@@ -68,6 +68,7 @@ public:
FORMAT_RGBA8,
FORMAT_RGBA4444,
FORMAT_RGBA5551,
+ FORMAT_RGB10A2,
FORMAT_RF, //float
FORMAT_RGF,
FORMAT_RGBF,
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index b2145eca85..a3b48320b1 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -30,6 +30,17 @@
#include "geometry.h"
#include "print_string.h"
+bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) {
+
+ Vector<int> indices = Geometry::triangulate_polygon(p_polygon);
+ for (int j = 0; j + 3 <= indices.size(); j += 3) {
+ int i1 = indices[j], i2 = indices[j + 1], i3 = indices[j + 2];
+ if (Geometry::is_point_in_triangle(p_point, p_polygon[i1], p_polygon[i2], p_polygon[i3]))
+ return true;
+ }
+ return false;
+}
+
void Geometry::MeshData::optimize_vertices() {
Map<int, int> vtx_remap;
diff --git a/core/math/geometry.h b/core/math/geometry.h
index ac1a22289c..fefdd88794 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -512,6 +512,9 @@ public:
return true;
}
+
+ static bool is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon);
+
static Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2 &p_point, const Vector2 *p_segment) {
Vector2 p = p_point - p_segment[0];
diff --git a/core/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/input.cpp b/core/os/input.cpp
index 2795b11243..a44adde425 100644
--- a/core/os/input.cpp
+++ b/core/os/input.cpp
@@ -84,7 +84,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press);
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
- ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(Vector2()));
+ ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
@@ -92,6 +92,24 @@ void Input::_bind_methods() {
BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
+ BIND_ENUM_CONSTANT(CURSOR_ARROW);
+ BIND_ENUM_CONSTANT(CURSOR_IBEAM);
+ BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
+ BIND_ENUM_CONSTANT(CURSOR_CROSS);
+ BIND_ENUM_CONSTANT(CURSOR_WAIT);
+ BIND_ENUM_CONSTANT(CURSOR_BUSY);
+ BIND_ENUM_CONSTANT(CURSOR_DRAG);
+ BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
+ BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
+ BIND_ENUM_CONSTANT(CURSOR_VSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_HSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_MOVE);
+ BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
+ BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
+ BIND_ENUM_CONSTANT(CURSOR_HELP);
+
ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")));
}
diff --git a/core/os/input.h b/core/os/input.h
index 608484ccd0..140d11de4d 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -51,6 +51,28 @@ public:
MOUSE_MODE_CONFINED
};
+#undef CursorShape
+ enum CursorShape {
+ CURSOR_ARROW,
+ CURSOR_IBEAM,
+ CURSOR_POINTING_HAND,
+ CURSOR_CROSS,
+ CURSOR_WAIT,
+ CURSOR_BUSY,
+ CURSOR_DRAG,
+ CURSOR_CAN_DROP,
+ CURSOR_FORBIDDEN,
+ CURSOR_VSIZE,
+ CURSOR_HSIZE,
+ CURSOR_BDIAGSIZE,
+ CURSOR_FDIAGSIZE,
+ CURSOR_MOVE,
+ CURSOR_VSPLIT,
+ CURSOR_HSPLIT,
+ CURSOR_HELP,
+ CURSOR_MAX
+ };
+
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
@@ -96,7 +118,7 @@ public:
virtual bool is_emulating_touchscreen() const = 0;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot = Vector2()) = 0;
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;
virtual void set_mouse_in_window(bool p_in_window) = 0;
virtual String get_joy_button_string(int p_button) = 0;
@@ -110,5 +132,6 @@ public:
};
VARIANT_ENUM_CAST(Input::MouseMode);
+VARIANT_ENUM_CAST(Input::CursorShape);
#endif // INPUT_H
diff --git a/core/os/os.h b/core/os/os.h
index 5dc39b52d6..c9c228cfaf 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -325,6 +325,7 @@ public:
virtual int get_virtual_keyboard_height() const;
virtual void set_cursor_shape(CursorShape p_shape) = 0;
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) = 0;
virtual bool get_swap_ok_cancel() { return false; }
virtual void dump_memory_to_file(const char *p_file);
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp
index 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..230978950b 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -314,6 +314,22 @@
Loads an image from file [code]path[/code].
</description>
</method>
+ <method name="load_jpg_from_buffer">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="buffer" type="PoolByteArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="load_png_from_buffer">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="buffer" type="PoolByteArray">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="lock">
<return type="void">
</return>
@@ -430,65 +446,67 @@
</constant>
<constant name="FORMAT_RGBA5551" value="7" enum="Format">
</constant>
- <constant name="FORMAT_RF" value="8" enum="Format">
+ <constant name="FORMAT_RGB10A2" value="8" enum="Format">
+ </constant>
+ <constant name="FORMAT_RF" value="9" enum="Format">
</constant>
- <constant name="FORMAT_RGF" value="9" enum="Format">
+ <constant name="FORMAT_RGF" value="10" enum="Format">
</constant>
- <constant name="FORMAT_RGBF" value="10" enum="Format">
+ <constant name="FORMAT_RGBF" value="11" enum="Format">
</constant>
- <constant name="FORMAT_RGBAF" value="11" enum="Format">
+ <constant name="FORMAT_RGBAF" value="12" enum="Format">
</constant>
- <constant name="FORMAT_RH" value="12" enum="Format">
+ <constant name="FORMAT_RH" value="13" enum="Format">
</constant>
- <constant name="FORMAT_RGH" value="13" enum="Format">
+ <constant name="FORMAT_RGH" value="14" enum="Format">
</constant>
- <constant name="FORMAT_RGBH" value="14" enum="Format">
+ <constant name="FORMAT_RGBH" value="15" enum="Format">
</constant>
- <constant name="FORMAT_RGBAH" value="15" enum="Format">
+ <constant name="FORMAT_RGBAH" value="16" enum="Format">
</constant>
- <constant name="FORMAT_RGBE9995" value="16" enum="Format">
+ <constant name="FORMAT_RGBE9995" value="17" enum="Format">
</constant>
- <constant name="FORMAT_DXT1" value="17" enum="Format">
+ <constant name="FORMAT_DXT1" value="18" enum="Format">
</constant>
- <constant name="FORMAT_DXT3" value="18" enum="Format">
+ <constant name="FORMAT_DXT3" value="19" enum="Format">
</constant>
- <constant name="FORMAT_DXT5" value="19" enum="Format">
+ <constant name="FORMAT_DXT5" value="20" enum="Format">
</constant>
- <constant name="FORMAT_RGTC_R" value="20" enum="Format">
+ <constant name="FORMAT_RGTC_R" value="21" enum="Format">
</constant>
- <constant name="FORMAT_RGTC_RG" value="21" enum="Format">
+ <constant name="FORMAT_RGTC_RG" value="22" enum="Format">
</constant>
- <constant name="FORMAT_BPTC_RGBA" value="22" enum="Format">
+ <constant name="FORMAT_BPTC_RGBA" value="23" enum="Format">
</constant>
- <constant name="FORMAT_BPTC_RGBF" value="23" enum="Format">
+ <constant name="FORMAT_BPTC_RGBF" value="24" enum="Format">
</constant>
- <constant name="FORMAT_BPTC_RGBFU" value="24" enum="Format">
+ <constant name="FORMAT_BPTC_RGBFU" value="25" enum="Format">
</constant>
- <constant name="FORMAT_PVRTC2" value="25" enum="Format">
+ <constant name="FORMAT_PVRTC2" value="26" enum="Format">
</constant>
- <constant name="FORMAT_PVRTC2A" value="26" enum="Format">
+ <constant name="FORMAT_PVRTC2A" value="27" enum="Format">
</constant>
- <constant name="FORMAT_PVRTC4" value="27" enum="Format">
+ <constant name="FORMAT_PVRTC4" value="28" enum="Format">
</constant>
- <constant name="FORMAT_PVRTC4A" value="28" enum="Format">
+ <constant name="FORMAT_PVRTC4A" value="29" enum="Format">
</constant>
- <constant name="FORMAT_ETC" value="29" enum="Format">
+ <constant name="FORMAT_ETC" value="30" enum="Format">
</constant>
- <constant name="FORMAT_ETC2_R11" value="30" enum="Format">
+ <constant name="FORMAT_ETC2_R11" value="31" enum="Format">
</constant>
- <constant name="FORMAT_ETC2_R11S" value="31" enum="Format">
+ <constant name="FORMAT_ETC2_R11S" value="32" enum="Format">
</constant>
- <constant name="FORMAT_ETC2_RG11" value="32" enum="Format">
+ <constant name="FORMAT_ETC2_RG11" value="33" enum="Format">
</constant>
- <constant name="FORMAT_ETC2_RG11S" value="33" enum="Format">
+ <constant name="FORMAT_ETC2_RG11S" value="34" enum="Format">
</constant>
- <constant name="FORMAT_ETC2_RGB8" value="34" enum="Format">
+ <constant name="FORMAT_ETC2_RGB8" value="35" enum="Format">
</constant>
- <constant name="FORMAT_ETC2_RGBA8" value="35" enum="Format">
+ <constant name="FORMAT_ETC2_RGBA8" value="36" enum="Format">
</constant>
- <constant name="FORMAT_ETC2_RGB8A1" value="36" enum="Format">
+ <constant name="FORMAT_ETC2_RGB8A1" value="37" enum="Format">
</constant>
- <constant name="FORMAT_MAX" value="37" enum="Format">
+ <constant name="FORMAT_MAX" value="38" enum="Format">
</constant>
<constant name="INTERPOLATE_NEAREST" value="0" enum="Interpolation">
</constant>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 1200ac5170..79dc45fa1f 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -275,9 +275,12 @@
</return>
<argument index="0" name="image" type="Resource">
</argument>
- <argument index="1" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
+ <argument index="1" name="shape" type="int" enum="Input.CursorShape" default="0">
+ </argument>
+ <argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
+ Set a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified. See enum [code]CURSOR_*[/code] for the list of shapes.
</description>
</method>
<method name="set_mouse_mode">
@@ -347,5 +350,39 @@
</constant>
<constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode">
</constant>
+ <constant name="CURSOR_ARROW" value="0" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_IBEAM" value="1" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_POINTING_HAND" value="2" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_CROSS" value="3" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_WAIT" value="4" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_BUSY" value="5" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_DRAG" value="6" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_CAN_DROP" value="7" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_FORBIDDEN" value="8" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_VSIZE" value="9" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_HSIZE" value="10" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_BDIAGSIZE" value="11" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_FDIAGSIZE" value="12" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_MOVE" value="13" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_VSPLIT" value="14" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_HSPLIT" value="15" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_HELP" value="16" enum="CursorShape">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml
index cc31da0627..a8abe60f78 100644
--- a/doc/classes/InputEvent.xml
+++ b/doc/classes/InputEvent.xml
@@ -28,13 +28,6 @@
Returns a [String] representation of the event.
</description>
</method>
- <method name="get_id" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the event's ID.
- </description>
- </method>
<method name="is_action" qualifiers="const">
<return type="bool">
</return>
@@ -83,14 +76,6 @@
Returns [code]true[/code] if this input event is pressed. Not relevant for the event types [code]MOUSE_MOTION[/code], [code]SCREEN_DRAG[/code] or [code]NONE[/code].
</description>
</method>
- <method name="set_id">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
<method name="shortcut_match" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml
index 22231cfdf3..af681c9456 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -18,6 +18,14 @@
Return the [PopupMenu] contained in this button.
</description>
</method>
+ <method name="set_disable_shortcuts">
+ <return type="void">
+ </return>
+ <argument index="0" name="disabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="about_to_show">
diff --git a/doc/classes/Physics2DServer.xml b/doc/classes/Physics2DServer.xml
index 67f5f84a49..8bad396b84 100644
--- a/doc/classes/Physics2DServer.xml
+++ b/doc/classes/Physics2DServer.xml
@@ -216,7 +216,7 @@
<argument index="2" name="disable" type="bool">
</argument>
<description>
- Disables a given shape in this area if [code]disable is true[/code]
+ Disables a given shape in an area.
</description>
</method>
<method name="area_set_shape_transform">
@@ -638,7 +638,7 @@
<argument index="2" name="enable" type="bool">
</argument>
<description>
- Enables one way collision on body if [code]enable is true[/code].
+ Enables one way collision on body if [code]enable[/code] is [code]true[/code].
</description>
</method>
<method name="body_set_shape_disabled">
@@ -651,7 +651,7 @@
<argument index="2" name="disable" type="bool">
</argument>
<description>
- Disables shape in body if [code]disable is true[/code].
+ Disables shape in body if [code]disable[/code] is [code]true[/code].
</description>
</method>
<method name="body_set_shape_metadata">
@@ -1135,6 +1135,12 @@
<constant name="JOINT_DAMPED_SPRING" value="2" enum="JointType">
Constant to create damped spring joints.
</constant>
+ <constant name="JOINT_PARAM_BIAS" value="0" enum="JointParam">
+ </constant>
+ <constant name="JOINT_PARAM_MAX_BIAS" value="1" enum="JointParam">
+ </constant>
+ <constant name="JOINT_PARAM_MAX_FORCE" value="2" enum="JointParam">
+ </constant>
<constant name="DAMPED_STRING_REST_LENGTH" value="0" enum="DampedStringParam">
Set the resting length of the spring joint. The joint will always try to go to back this length when pulled apart.
</constant>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index a78fe03cab..3a4b843b06 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -302,6 +302,14 @@
<description>
</description>
</method>
+ <method name="set_quit_on_go_back">
+ <return type="void">
+ </return>
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_refuse_new_network_connections">
<return type="void">
</return>
@@ -402,13 +410,13 @@
</signal>
</signals>
<constants>
- <constant name="GROUP_CALL_DEFAULT" value="0" enum="CallGroupFlags">
+ <constant name="GROUP_CALL_DEFAULT" value="0" enum="GroupCallFlags">
</constant>
- <constant name="GROUP_CALL_REVERSE" value="1" enum="CallGroupFlags">
+ <constant name="GROUP_CALL_REVERSE" value="1" enum="GroupCallFlags">
</constant>
- <constant name="GROUP_CALL_REALTIME" value="2" enum="CallGroupFlags">
+ <constant name="GROUP_CALL_REALTIME" value="2" enum="GroupCallFlags">
</constant>
- <constant name="GROUP_CALL_UNIQUE" value="4" enum="CallGroupFlags">
+ <constant name="GROUP_CALL_UNIQUE" value="4" enum="GroupCallFlags">
</constant>
<constant name="STRETCH_MODE_DISABLED" value="0" enum="StretchMode">
</constant>
diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml
index 81b0b3d0c3..1e1a8d516e 100644
--- a/doc/classes/ScriptEditor.xml
+++ b/doc/classes/ScriptEditor.xml
@@ -12,11 +12,11 @@
<method name="can_drop_data_fw" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="arg0" type="Vector2">
+ <argument index="0" name="point" type="Vector2">
</argument>
- <argument index="1" name="arg1" type="Variant">
+ <argument index="1" name="data" type="Variant">
</argument>
- <argument index="2" name="arg2" type="Control">
+ <argument index="2" name="from" type="Control">
</argument>
<description>
</description>
@@ -24,11 +24,11 @@
<method name="drop_data_fw">
<return type="void">
</return>
- <argument index="0" name="arg0" type="Vector2">
+ <argument index="0" name="point" type="Vector2">
</argument>
- <argument index="1" name="arg1" type="Variant">
+ <argument index="1" name="data" type="Variant">
</argument>
- <argument index="2" name="arg2" type="Control">
+ <argument index="2" name="from" type="Control">
</argument>
<description>
</description>
@@ -43,9 +43,9 @@
<method name="get_drag_data_fw">
<return type="Variant">
</return>
- <argument index="0" name="arg0" type="Vector2">
+ <argument index="0" name="point" type="Vector2">
</argument>
- <argument index="1" name="arg1" type="Control">
+ <argument index="1" name="from" type="Control">
</argument>
<description>
</description>
diff --git a/doc/classes/Spatial.xml b/doc/classes/Spatial.xml
index 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/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..365840b2d8 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -193,6 +193,13 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_
r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1;
} break;
+ case Image::FORMAT_RGB10A2: {
+
+ r_gl_internal_format = GL_RGB10_A2;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_UNSIGNED_INT_2_10_10_10_REV;
+
+ } break;
case Image::FORMAT_RF: {
r_gl_internal_format = GL_R32F;
@@ -6090,7 +6097,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) {
color_internal_format = GL_RGB10_A2;
color_format = GL_RGBA;
color_type = GL_UNSIGNED_INT_2_10_10_10_REV;
- image_format = Image::FORMAT_RGBA8;
+ image_format = Image::FORMAT_RGB10A2;
} else {
color_internal_format = GL_RGBA8;
diff --git a/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/editor/code_editor.cpp b/editor/code_editor.cpp
index 256fe302d7..4b59656903 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1251,7 +1251,7 @@ CodeTextEditor::CodeTextEditor() {
error = memnew(Label);
status_bar->add_child(error);
- error->set_clip_text(true); //do not change, or else very long errors can push the whole container to the right
+ error->set_autowrap(true);
error->set_valign(Label::VALIGN_CENTER);
error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
error->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index f2882561aa..c50995fc2b 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -77,12 +77,27 @@ static Ref<BitmapFont> make_font(int p_height, int p_ascent, int p_valign, int p
Ref<DynamicFont> m_name; \
m_name.instance(); \
m_name->set_size(m_size); \
- m_name->set_font_data(DefaultFont); \
+ if (CustomFont.is_valid()) { \
+ m_name->set_font_data(CustomFont); \
+ m_name->add_fallback(DefaultFont); \
+ } else { \
+ m_name->set_font_data(DefaultFont); \
+ } \
m_name->set_spacing(DynamicFont::SPACING_TOP, -EDSCALE); \
m_name->set_spacing(DynamicFont::SPACING_BOTTOM, -EDSCALE); \
MAKE_FALLBACKS(m_name);
void editor_register_fonts(Ref<Theme> p_theme) {
+ /* Custom font */
+
+ String custom_font = EditorSettings::get_singleton()->get("interface/editor/custom_font");
+ Ref<DynamicFontData> CustomFont;
+ if (custom_font.length() > 0) {
+ CustomFont.instance();
+ CustomFont->set_font_path(custom_font);
+ CustomFont->set_force_autohinter(true); //just looks better..i think?
+ }
+
/* Droid Sans */
Ref<DynamicFontData> DefaultFont;
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index cf19af7ef6..1b885adf37 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "editor_log.h"
+#include "core/os/keyboard.h"
#include "editor_node.h"
#include "scene/gui/center_container.h"
#include "scene/resources/dynamic_font.h"
@@ -154,6 +155,7 @@ EditorLog::EditorLog() {
clearbutton = memnew(Button);
hb->add_child(clearbutton);
clearbutton->set_text(TTR("Clear"));
+ clearbutton->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_K));
clearbutton->connect("pressed", this, "_clear_request");
log = memnew(RichTextLabel);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index bd37e7d0be..b308d28dba 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -4419,10 +4419,11 @@ void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) {
String to_path = ProjectSettings::get_singleton()->globalize_path(get_filesystem_dock()->get_current_path());
DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Vector<String> just_copy = String("ttf,otf").split(",");
for (int i = 0; i < p_files.size(); i++) {
String from = p_files[i];
- if (!ResourceFormatImporter::get_singleton()->can_be_imported(from)) {
+ if (!ResourceFormatImporter::get_singleton()->can_be_imported(from) && (just_copy.find(from.get_extension().to_lower()) < 0)) {
continue;
}
String to = to_path.plus_file(from.get_file());
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 5a16ec7eab..dc82a02f46 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -277,7 +277,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/source_font_size", 14);
hints["interface/editor/source_font_size"] = PropertyInfo(Variant::INT, "interface/editor/source_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/custom_font", "");
- hints["interface/editor/custom_font"] = PropertyInfo(Variant::STRING, "interface/editor/custom_font", PROPERTY_HINT_GLOBAL_FILE, "*.font,*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ hints["interface/editor/custom_font"] = PropertyInfo(Variant::STRING, "interface/editor/custom_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/dim_editor_on_dialog_popup", true);
_initial_set("interface/editor/dim_amount", 0.6f);
hints["interface/editor/dim_amount"] = PropertyInfo(Variant::REAL, "interface/editor/dim_amount", PROPERTY_HINT_RANGE, "0,1,0.01", PROPERTY_USAGE_DEFAULT);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 3644893663..b19d015455 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1135,16 +1135,5 @@ Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) {
theme = create_editor_theme(p_theme);
}
- String global_font = EditorSettings::get_singleton()->get("interface/editor/custom_font");
- if (global_font != "") {
- Ref<Font> fnt = ResourceLoader::load(global_font);
- if (fnt.is_valid()) {
- if (!theme.is_valid()) {
- theme.instance();
- }
- theme->set_default_theme_font(fnt);
- }
- }
-
return theme;
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 949455ff98..b18cd6b747 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -819,7 +819,7 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
print_line("Duplicating " + old_path + " -> " + new_path);
- Error err = da->copy(old_path, new_path);
+ Error err = p_item.is_file ? da->copy(old_path, new_path) : da->copy_dir(old_path, new_path);
if (err == OK) {
//Move/Rename any corresponding import settings too
if (p_item.is_file && FileAccess::exists(old_path + ".import")) {
@@ -980,10 +980,12 @@ void FileSystemDock::_duplicate_operation_confirm() {
return;
}
- String old_path = to_duplicate.path.ends_with("/") ? to_duplicate.path.substr(0, to_duplicate.path.length() - 1) : to_rename.path;
- String new_path = old_path.get_base_dir().plus_file(new_name);
- if (old_path == new_path) {
- return;
+ String new_path;
+ String base_dir = to_duplicate.path.get_base_dir();
+ if (to_duplicate.is_file) {
+ new_path = base_dir.plus_file(new_name);
+ } else {
+ new_path = base_dir.substr(0, base_dir.find_last("/")) + "/" + new_name;
}
//Present a more user friendly warning for name conflict
@@ -995,7 +997,7 @@ void FileSystemDock::_duplicate_operation_confirm() {
}
memdelete(da);
- _try_duplicate_item(to_duplicate, new_name);
+ _try_duplicate_item(to_duplicate, new_path);
//Rescan everything
print_line("call rescan!");
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 53b52c5f1b..052817f40a 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -612,6 +612,7 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
if (Object::cast_to<Viewport>(p_node))
return;
+ const real_t grab_distance = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
CanvasItem *c = Object::cast_to<CanvasItem>(p_node);
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
@@ -630,9 +631,12 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !Object::cast_to<CanvasLayer>(c)) {
Rect2 rect = c->_edit_get_rect();
- Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos);
+ Transform2D to_local = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse();
+ Point2 local_pos = to_local.xform(p_pos);
+ const real_t local_grab_distance = (to_local.xform(p_pos + Vector2(grab_distance, 0)) - local_pos).length();
+ Rect2 local_pos_rect = Rect2(local_pos, Vector2(0, 0)).grow(local_grab_distance);
- if (rect.has_point(local_pos)) {
+ if (rect.intersects(local_pos_rect) && c->_edit_is_selected_on_click(local_pos, local_grab_distance)) {
Node2D *node = Object::cast_to<Node2D>(c);
_SelectResult res;
@@ -3464,7 +3468,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
- if (!canvas_item || !canvas_item->is_visible_in_tree())
+ if (!canvas_item || !canvas_item->is_inside_tree())
continue;
if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
@@ -3482,7 +3486,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
- if (!canvas_item || !canvas_item->is_visible_in_tree())
+ if (!canvas_item || !canvas_item->is_inside_tree())
continue;
if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
@@ -3502,7 +3506,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
- if (!canvas_item || !canvas_item->is_visible_in_tree())
+ if (!canvas_item || !canvas_item->is_inside_tree())
continue;
if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
@@ -3520,7 +3524,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
- if (!canvas_item || !canvas_item->is_visible_in_tree())
+ if (!canvas_item || !canvas_item->is_inside_tree())
continue;
if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index da507db5da..eccb11ba12 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -333,7 +333,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) {
autotile_list = memnew(ItemList);
autotile_list->set_v_size_flags(SIZE_EXPAND_FILL);
autotile_list->set_h_size_flags(SIZE_EXPAND_FILL);
- autotile_list->set_custom_minimum_size(Size2(02, 200));
+ autotile_list->set_custom_minimum_size(Size2(10, 200));
autotile_list->connect("item_selected", this, "_on_autotile_selected");
split->add_child(autotile_list);
@@ -531,7 +531,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) {
main_vb->add_child(toolbar);
- ScrollContainer *scroll = memnew(ScrollContainer);
+ scroll = memnew(ScrollContainer);
main_vb->add_child(scroll);
scroll->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -619,6 +619,7 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) {
tool_containers[TOOLBAR_BITMASK]->hide();
tool_containers[TOOLBAR_SHAPE]->show();
tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile."));
+ current_shape = PoolVector2Array();
spin_priority->hide();
} break;
default: {
@@ -1061,20 +1062,43 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
} else {
int t_id = get_current_tile();
if (t_id >= 0) {
- Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(t_id);
- for (int i = 0; i < sd.size(); i++) {
- if (sd[i].autotile_coord == edited_shape_coord) {
- Ref<ConvexPolygonShape2D> shape = sd[i].shape;
+ if (edit_mode == EDITMODE_COLLISION) {
+ Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(t_id);
+ for (int i = 0; i < sd.size(); i++) {
+ if (sd[i].autotile_coord == edited_shape_coord) {
+ Ref<ConvexPolygonShape2D> shape = sd[i].shape;
+
+ if (!shape.is_null()) {
+ sd.remove(i);
+ tile_set->tile_set_shapes(get_current_tile(), sd);
+ edited_collision_shape = Ref<Shape2D>();
+ workspace->update();
+ }
+ break;
+ }
+ }
+ } else if (edit_mode == EDITMODE_OCCLUSION) {
+ Map<Vector2, Ref<OccluderPolygon2D> > map = tile_set->autotile_get_light_oclusion_map(t_id);
+ for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) {
+ if (E->key() == edited_shape_coord) {
+ tile_set->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord);
+ break;
+ }
+ }
- if (!shape.is_null()) {
- sd.remove(i);
- tile_set->tile_set_shapes(get_current_tile(), sd);
- edited_collision_shape = Ref<Shape2D>();
- current_shape.resize(0);
- workspace->update();
+ edited_occlusion_shape = Ref<OccluderPolygon2D>();
+ workspace->update();
+ } else if (edit_mode == EDITMODE_NAVIGATION) {
+ Map<Vector2, Ref<NavigationPolygon> > map = tile_set->autotile_get_navigation_map(t_id);
+ for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) {
+ if (E->key() == edited_shape_coord) {
+ tile_set->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord);
+ break;
}
- break;
}
+
+ edited_navigation_shape = Ref<NavigationPolygon>();
+ workspace->update();
}
}
@@ -1095,6 +1119,16 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
} break;
}
+
+ //Drag Middle Mouse
+ if (mm.is_valid()) {
+ if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+
+ Vector2 dragged(mm->get_relative().x, mm->get_relative().y);
+ scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x);
+ scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x);
+ }
+ }
}
}
@@ -1453,11 +1487,20 @@ void AutotileEditor::close_shape(const Vector2 &shape_anchor) {
Ref<ConvexPolygonShape2D> shape = memnew(ConvexPolygonShape2D);
Vector<Vector2> segments;
+ float p_total = 0;
for (int i = 0; i < current_shape.size(); i++) {
segments.push_back(current_shape[i] - shape_anchor);
+
+ if (i != current_shape.size() - 1)
+ p_total += ((current_shape[i + 1].x - current_shape[i].x) * (-current_shape[i + 1].y + (-current_shape[i].y)));
+ else
+ p_total += ((current_shape[0].x - current_shape[i].x) * (-current_shape[0].y + (-current_shape[i].y)));
}
+ if (p_total < 0)
+ segments.invert();
+
shape->set_points(segments);
tile_set->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord);
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 7d9558d4e7..0f66f04cb1 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -86,6 +86,7 @@ class AutotileEditor : public Control {
int current_item_index;
Sprite *preview;
+ ScrollContainer *scroll;
Control *workspace_container;
Control *workspace;
Button *tool_editmode[EDITMODE_MAX];
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 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/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index 4fe7bef9f7..f1a5aa4654 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -1686,6 +1686,45 @@ void ScriptEditorDebugger::_clear_remote_objects() {
remote_objects.clear();
}
+void ScriptEditorDebugger::_clear_errors_list() {
+
+ error_list->clear();
+ error_count = 0;
+ _notification(NOTIFICATION_PROCESS);
+}
+
+// Right click on specific file(s) or folder(s).
+void ScriptEditorDebugger::_error_list_item_rmb_selected(int p_item, const Vector2 &p_pos) {
+
+ item_menu->clear();
+ item_menu->set_size(Size2(1, 1));
+
+ // Allow specific actions only on one item.
+ bool single_item_selected = error_list->get_selected_items().size() == 1;
+
+ if (single_item_selected) {
+ item_menu->add_icon_item(get_icon("CopyNodePath", "EditorIcons"), TTR("Copy Error"), ITEM_MENU_COPY_ERROR);
+ }
+
+ if (item_menu->get_item_count() > 0) {
+ item_menu->set_position(error_list->get_global_position() + p_pos);
+ item_menu->popup();
+ }
+}
+
+void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
+
+ switch (p_option) {
+
+ case ITEM_MENU_COPY_ERROR: {
+ String title = error_list->get_item_text(error_list->get_current());
+ String desc = error_list->get_item_tooltip(error_list->get_current());
+
+ OS::get_singleton()->set_clipboard(title + "\n----------\n" + desc);
+ } break;
+ }
+}
+
void ScriptEditorDebugger::_bind_methods() {
ClassDB::bind_method(D_METHOD("_stack_dump_frame_selected"), &ScriptEditorDebugger::_stack_dump_frame_selected);
@@ -1705,6 +1744,10 @@ void ScriptEditorDebugger::_bind_methods() {
ClassDB::bind_method(D_METHOD("_error_stack_selected"), &ScriptEditorDebugger::_error_stack_selected);
ClassDB::bind_method(D_METHOD("_profiler_activate"), &ScriptEditorDebugger::_profiler_activate);
ClassDB::bind_method(D_METHOD("_profiler_seeked"), &ScriptEditorDebugger::_profiler_seeked);
+ ClassDB::bind_method(D_METHOD("_clear_errors_list"), &ScriptEditorDebugger::_clear_errors_list);
+
+ ClassDB::bind_method(D_METHOD("_error_list_item_rmb_selected"), &ScriptEditorDebugger::_error_list_item_rmb_selected);
+ ClassDB::bind_method(D_METHOD("_item_menu_id_pressed"), &ScriptEditorDebugger::_item_menu_id_pressed);
ClassDB::bind_method(D_METHOD("_paused"), &ScriptEditorDebugger::_paused);
@@ -1829,9 +1872,31 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
error_split = memnew(HSplitContainer);
VBoxContainer *errvb = memnew(VBoxContainer);
+ HBoxContainer *errhb = memnew(HBoxContainer);
errvb->set_h_size_flags(SIZE_EXPAND_FILL);
+ Label *velb = memnew(Label(TTR("Errors:")));
+ velb->set_h_size_flags(SIZE_EXPAND_FILL);
+ errhb->add_child(velb);
+
+ clearbutton = memnew(Button);
+ clearbutton->set_text(TTR("Clear"));
+ clearbutton->connect("pressed", this, "_clear_errors_list");
+ errhb->add_child(clearbutton);
+ errvb->add_child(errhb);
+
error_list = memnew(ItemList);
- errvb->add_margin_child(TTR("Errors:"), error_list, true);
+ error_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ error_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ error_list->connect("item_rmb_selected", this, "_error_list_item_rmb_selected");
+ error_list->set_allow_rmb_select(true);
+ error_list->set_autoscroll_to_bottom(true);
+
+ item_menu = memnew(PopupMenu);
+ item_menu->connect("id_pressed", this, "_item_menu_id_pressed");
+ error_list->add_child(item_menu);
+
+ errvb->add_child(error_list);
+
error_split->add_child(errvb);
errvb = memnew(VBoxContainer);
diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h
index e380a56b18..7f8348d82f 100644
--- a/editor/script_editor_debugger.h
+++ b/editor/script_editor_debugger.h
@@ -62,6 +62,10 @@ class ScriptEditorDebugger : public Control {
MESSAGE_SUCCESS,
};
+ enum ItemMenu {
+ ITEM_MENU_COPY_ERROR,
+ };
+
AcceptDialog *msgdialog;
Button *debugger_button;
@@ -85,6 +89,8 @@ class ScriptEditorDebugger : public Control {
ItemList *error_list;
ItemList *error_stack;
Tree *inspect_scene_tree;
+ Button *clearbutton;
+ PopupMenu *item_menu;
int error_count;
int last_error_count;
@@ -175,6 +181,10 @@ class ScriptEditorDebugger : public Control {
void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj);
void _clear_remote_objects();
+ void _clear_errors_list();
+
+ void _error_list_item_rmb_selected(int p_item, const Vector2 &p_pos);
+ void _item_menu_id_pressed(int p_option);
protected:
void _notification(int p_what);
diff --git a/main/input_default.cpp b/main/input_default.cpp
index 5026b8bb39..c3454d86f3 100644
--- a/main/input_default.cpp
+++ b/main/input_default.cpp
@@ -497,26 +497,16 @@ bool InputDefault::is_emulating_touchscreen() const {
return emulate_touch;
}
-void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot) {
- /* no longer supported, leaving this for reference to anyone who might want to implement hardware cursors
+void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ if (Engine::get_singleton()->is_editor_hint())
+ return;
+
if (custom_cursor == p_cursor)
return;
custom_cursor = p_cursor;
- if (p_cursor.is_null()) {
- set_mouse_mode(MOUSE_MODE_VISIBLE);
- //removed, please insist us to implement hardare cursors
- //VisualServer::get_singleton()->cursor_set_visible(false);
- } else {
- Ref<AtlasTexture> atex = custom_cursor;
- Rect2 region = atex.is_valid() ? atex->get_region() : Rect2();
- set_mouse_mode(MOUSE_MODE_HIDDEN);
- VisualServer::get_singleton()->cursor_set_visible(true);
- VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(), p_hotspot, 0, region);
- VisualServer::get_singleton()->cursor_set_pos(get_mouse_position());
- }
- */
+ OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);
}
void InputDefault::set_mouse_in_window(bool p_in_window) {
diff --git a/main/input_default.h b/main/input_default.h
index 62ba0b0c32..3d9a809325 100644
--- a/main/input_default.h
+++ b/main/input_default.h
@@ -225,7 +225,7 @@ public:
void set_emulate_touch(bool p_emulate);
virtual bool is_emulating_touchscreen() const;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot = Vector2());
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
virtual void set_mouse_in_window(bool p_in_window);
void parse_mapping(String p_mapping);
diff --git a/main/main.cpp b/main/main.cpp
index 5936a323d4..ac68fe1296 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1107,7 +1107,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
if (cursor.is_valid()) {
//print_line("loaded ok");
Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot");
- Input::get_singleton()->set_custom_mouse_cursor(cursor, hotspot);
+ Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);
}
}
#ifdef TOOLS_ENABLED
diff --git a/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/os_android.cpp b/platform/android/os_android.cpp
index dd23a81977..97e81874c9 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -248,6 +248,9 @@ void OS_Android::set_cursor_shape(CursorShape p_shape) {
//android really really really has no mouse.. how amazing..
}
+void OS_Android::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+}
+
void OS_Android::main_loop_begin() {
if (main_loop)
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 744dce7ff1..adfd88b59b 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -182,6 +182,7 @@ public:
virtual bool can_draw() const;
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void main_loop_begin();
bool main_loop_iterate();
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
index 3324b33e95..65a220f8ca 100644
--- a/platform/haiku/os_haiku.cpp
+++ b/platform/haiku/os_haiku.cpp
@@ -200,6 +200,10 @@ void OS_Haiku::set_cursor_shape(CursorShape p_shape) {
//ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED");
}
+void OS_Haiku::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ // TODO
+}
+
int OS_Haiku::get_screen_count() const {
// TODO: implement get_screen_count()
return 1;
diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h
index b4d0add04b..6d69c1997f 100644
--- a/platform/haiku/os_haiku.h
+++ b/platform/haiku/os_haiku.h
@@ -87,6 +87,7 @@ public:
virtual Point2 get_mouse_position() const;
virtual int get_mouse_button_state() const;
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual int get_screen_count() const;
virtual int get_current_screen() const;
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index dcb7b8b1f4..507d4f22db 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -490,6 +490,8 @@ String OSIPhone::get_user_data_dir() const {
return data_dir;
};
+void OSIPhone::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot){};
+
String OSIPhone::get_name() {
return "iOS";
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 7e310e3a03..8e701a7fab 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -173,6 +173,7 @@ public:
virtual int get_virtual_keyboard_height() const;
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual Size2 get_window_size() const;
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index a24bf6c0bc..0411b4e72b 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -41,6 +41,7 @@
#include "servers/visual/rasterizer.h"
#include "servers/visual/visual_server_wrap_mt.h"
#include "servers/visual_server.h"
+#include <AppKit/NSCursor.h>
#include <ApplicationServices/ApplicationServices.h>
#undef CursorShape
@@ -86,6 +87,7 @@ public:
id context;
CursorShape cursor_shape;
+ NSCursor *cursors[CURSOR_MAX] = { NULL };
MouseMode mouse_mode;
String title;
@@ -137,6 +139,7 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual void set_mouse_show(bool p_show);
virtual void set_mouse_grab(bool p_grab);
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 0cd02663da..99c5995d7a 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -577,8 +577,11 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
return;
if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
- if (OS_OSX::singleton->input)
+ if (OS_OSX::singleton->input) {
OS_OSX::singleton->input->set_mouse_in_window(true);
+ OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX;
+ OS_OSX::singleton->set_cursor_shape(OS::CURSOR_ARROW);
+ }
}
- (void)magnifyWithEvent:(NSEvent *)event {
@@ -1240,30 +1243,84 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) {
if (cursor_shape == p_shape)
return;
- switch (p_shape) {
- case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
- case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
- case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
- case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
- case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
- case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
- case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
- case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
- case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break;
- case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break;
- case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break;
- case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break;
- case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break;
- case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
- case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
- case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
- case CURSOR_HELP: [[NSCursor arrowCursor] set]; break;
- default: {};
+ if (cursors[p_shape] != NULL) {
+ [cursors[p_shape] set];
+ } else {
+ switch (p_shape) {
+ case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
+ case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
+ case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
+ case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
+ case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
+ case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break;
+ case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break;
+ case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
+ case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
+ case CURSOR_HELP: [[NSCursor arrowCursor] set]; break;
+ default: {};
+ }
}
cursor_shape = p_shape;
}
+void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ if (p_cursor.is_valid()) {
+ Ref<Texture> texture = p_cursor;
+ Ref<Image> image = texture->get_data();
+
+ int image_size = 32 * 32;
+
+ ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
+
+ NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:NULL
+ pixelsWide:image->get_width()
+ pixelsHigh:image->get_height()
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:image->get_width() * 4
+ bitsPerPixel:32] autorelease];
+
+ ERR_FAIL_COND(imgrep == nil);
+ uint8_t *pixels = [imgrep bitmapData];
+
+ int len = image->get_width() * image->get_height();
+ PoolVector<uint8_t> data = image->get_data();
+ PoolVector<uint8_t>::Read r = data.read();
+
+ /* Premultiply the alpha channel */
+ for (int i = 0; i < len; i++) {
+ uint8_t alpha = r[i * 4 + 3];
+ pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
+ pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
+ pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
+ pixels[i * 4 + 3] = alpha;
+ }
+
+ NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(image->get_width(), image->get_height())] autorelease];
+ [nsimage addRepresentation:imgrep];
+
+ NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];
+
+ cursors[p_shape] = cursor;
+
+ if (p_shape == CURSOR_ARROW) {
+ [cursor set];
+ }
+ }
+}
+
void OS_OSX::set_mouse_show(bool p_show) {
}
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index c34567aaab..13264ed46e 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -179,6 +179,9 @@ void OS_Server::move_window_to_foreground() {
void OS_Server::set_cursor_shape(CursorShape p_shape) {
}
+void OS_Server::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+}
+
OS::PowerState OS_Server::get_power_state() {
return power_manager->get_power_state();
}
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index c58c48500e..7b7d4a38a8 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -75,6 +75,7 @@ public:
virtual String get_name();
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual void set_mouse_show(bool p_show);
virtual void set_mouse_grab(bool p_grab);
diff --git a/platform/uwp/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..603a918cca 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -651,6 +651,10 @@ void OSUWP::set_cursor_shape(CursorShape p_shape) {
cursor_shape = p_shape;
}
+void OSUWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ // TODO
+}
+
Error OSUWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
return FAILED;
@@ -745,6 +749,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..976eda1fe1 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -218,6 +218,7 @@ public:
virtual String get_clipboard() const;
void set_cursor_shape(CursorShape p_shape);
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void set_icon(const Ref<Image> &p_icon);
virtual String get_executable_path() const;
@@ -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..e3af82b629 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -1844,10 +1844,125 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) {
IDC_HELP
};
- SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
+ if (cursors[p_shape] != NULL) {
+ SetCursor(cursors[p_shape]);
+ } else {
+ SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
+ }
cursor_shape = p_shape;
}
+void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ if (p_cursor.is_valid()) {
+ Ref<Texture> texture = p_cursor;
+ Ref<Image> image = texture->get_data();
+
+ UINT image_size = 32 * 32;
+ UINT size = sizeof(UINT) * image_size;
+
+ ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
+
+ // Create the BITMAP with alpha channel
+ COLORREF *buffer = (COLORREF *)malloc(sizeof(COLORREF) * image_size);
+
+ image->lock();
+ for (UINT index = 0; index < image_size; index++) {
+ int column_index = floor(index / 32);
+ int row_index = index % 32;
+
+ Color pcColor = image->get_pixel(row_index, column_index);
+ *(buffer + index) = image->get_pixel(row_index, column_index).to_argb32();
+ }
+ image->unlock();
+
+ // Using 4 channels, so 4 * 8 bits
+ HBITMAP bitmap = CreateBitmap(32, 32, 1, 4 * 8, buffer);
+ COLORREF clrTransparent = -1;
+
+ // Create the AND and XOR masks for the bitmap
+ HBITMAP hAndMask = NULL;
+ HBITMAP hXorMask = NULL;
+
+ GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask);
+
+ if (NULL == hAndMask || NULL == hXorMask) {
+ return;
+ }
+
+ // Finally, create the icon
+ ICONINFO iconinfo = { 0 };
+ iconinfo.fIcon = FALSE;
+ iconinfo.xHotspot = p_hotspot.x;
+ iconinfo.yHotspot = p_hotspot.y;
+ iconinfo.hbmMask = hAndMask;
+ iconinfo.hbmColor = hXorMask;
+
+ cursors[p_shape] = CreateIconIndirect(&iconinfo);
+
+ if (p_shape == CURSOR_ARROW) {
+ SetCursor(cursors[p_shape]);
+ }
+
+ if (hAndMask != NULL) {
+ DeleteObject(hAndMask);
+ }
+
+ if (hXorMask != NULL) {
+ DeleteObject(hXorMask);
+ }
+ }
+}
+
+void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
+
+ // Get the system display DC
+ HDC hDC = GetDC(NULL);
+
+ // Create helper DC
+ HDC hMainDC = CreateCompatibleDC(hDC);
+ HDC hAndMaskDC = CreateCompatibleDC(hDC);
+ HDC hXorMaskDC = CreateCompatibleDC(hDC);
+
+ // Get the dimensions of the source bitmap
+ BITMAP bm;
+ GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
+
+ // Create the mask bitmaps
+ hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
+ hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
+
+ // Release the system display DC
+ ReleaseDC(NULL, hDC);
+
+ // Select the bitmaps to helper DC
+ HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
+ HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
+ HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
+
+ // Assign the monochrome AND mask bitmap pixels so that a pixels of the source bitmap
+ // with 'clrTransparent' will be white pixels of the monochrome bitmap
+ SetBkColor(hMainDC, clrTransparent);
+ BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
+
+ // Assign the color XOR mask bitmap pixels so that a pixels of the source bitmap
+ // with 'clrTransparent' will be black and rest the pixels same as corresponding
+ // pixels of the source bitmap
+ SetBkColor(hXorMaskDC, RGB(0, 0, 0));
+ SetTextColor(hXorMaskDC, RGB(255, 255, 255));
+ BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
+ BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
+
+ // Deselect bitmaps from the helper DC
+ SelectObject(hMainDC, hOldMainBitmap);
+ SelectObject(hAndMaskDC, hOldAndMaskBitmap);
+ SelectObject(hXorMaskDC, hOldXorMaskBitmap);
+
+ // Delete the helper DC
+ DeleteDC(hXorMaskDC);
+ DeleteDC(hAndMaskDC);
+ DeleteDC(hMainDC);
+}
+
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
if (p_blocking && r_pipe) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index d709fb3fe5..9d254ccf27 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -113,6 +113,7 @@ class OS_Windows : public OS {
bool window_has_focus;
uint32_t last_button_state;
+ HCURSOR cursors[CURSOR_MAX] = { NULL };
CursorShape cursor_shape;
InputDefault *input;
@@ -244,6 +245,8 @@ public:
virtual String get_clipboard() const;
void set_cursor_shape(CursorShape p_shape);
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
+ void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
void set_icon(const Ref<Image> &p_icon);
virtual String get_executable_path() const;
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 240d6638a9..e9920b18a4 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -1050,13 +1050,59 @@ void OS_X11::set_window_maximized(bool p_enabled) {
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
- while (p_enabled && !is_window_maximized()) {
- // Wait for effective resizing (so the GLX context is too).
+ if (is_window_maximize_allowed()) {
+ while (p_enabled && !is_window_maximized()) {
+ // Wait for effective resizing (so the GLX context is too).
+ }
}
maximized = p_enabled;
}
+bool OS_X11::is_window_maximize_allowed() {
+ Atom property = XInternAtom(x11_display, "_NET_WM_ALLOWED_ACTIONS", False);
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = NULL;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ x11_window,
+ property,
+ 0,
+ 1024,
+ False,
+ XA_ATOM,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data);
+
+ if (result == Success) {
+ Atom *atoms = (Atom *)data;
+ Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
+ Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
+ bool found_wm_act_max_horz = false;
+ bool found_wm_act_max_vert = false;
+
+ for (unsigned int i = 0; i < len; i++) {
+ if (atoms[i] == wm_act_max_horz)
+ found_wm_act_max_horz = true;
+ if (atoms[i] == wm_act_max_vert)
+ found_wm_act_max_vert = true;
+
+ if (found_wm_act_max_horz || found_wm_act_max_vert)
+ return true;
+ }
+ XFree(atoms);
+ }
+
+ return false;
+}
+
bool OS_X11::is_window_maximized() const {
// Using EWMH -- Extended Window Manager Hints
Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False);
@@ -2205,6 +2251,48 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) {
current_cursor = p_shape;
}
+void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ if (p_cursor.is_valid()) {
+ Ref<Texture> texture = p_cursor;
+ Ref<Image> image = texture->get_data();
+
+ ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
+
+ // Create the cursor structure
+ XcursorImage *cursor_image = XcursorImageCreate(texture->get_width(), texture->get_height());
+ XcursorUInt image_size = 32 * 32;
+ XcursorDim size = sizeof(XcursorPixel) * image_size;
+
+ cursor_image->version = 1;
+ cursor_image->size = size;
+ cursor_image->xhot = p_hotspot.x;
+ cursor_image->yhot = p_hotspot.y;
+
+ // allocate memory to contain the whole file
+ cursor_image->pixels = (XcursorPixel *)malloc(size);
+
+ image->lock();
+
+ for (XcursorPixel index = 0; index < image_size; index++) {
+ int column_index = floor(index / 32);
+ int row_index = index % 32;
+
+ *(cursor_image->pixels + index) = image->get_pixel(row_index, column_index).to_argb32();
+ }
+
+ image->unlock();
+
+ ERR_FAIL_COND(cursor_image->pixels == NULL);
+
+ // Save it for a further usage
+ cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image);
+
+ if (p_shape == CURSOR_ARROW) {
+ XDefineCursor(x11_display, x11_window, cursors[p_shape]);
+ }
+ }
+}
+
void OS_X11::release_rendering_thread() {
context_gl->release_current();
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 59b9c8caa8..04243a9b36 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -200,10 +200,13 @@ protected:
void _window_changed(XEvent *xevent);
+ bool is_window_maximize_allowed();
+
public:
virtual String get_name();
virtual void set_cursor_shape(CursorShape p_shape);
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index e994ebb5aa..1db9e4902a 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -229,6 +229,7 @@ public:
// Used to resize/move/select the node
virtual void _edit_set_rect(const Rect2 &p_rect){};
virtual Rect2 _edit_get_rect() const { return Rect2(-32, -32, 64, 64); };
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return true; }
Rect2 _edit_get_item_and_children_rect() const;
virtual bool _edit_use_rect() const { return false; };
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index eaa650b140..e46bf3c77d 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -248,6 +248,11 @@ Rect2 CollisionPolygon2D::_edit_get_rect() const {
return aabb;
}
+bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, Variant(polygon));
+}
+
String CollisionPolygon2D::get_configuration_warning() const {
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index 4c8b55a9ee..fa7e5e1046 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -70,6 +70,7 @@ public:
Vector<Point2> get_polygon() const;
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
virtual String get_configuration_warning() const;
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 1cadbe83d0..135ede829d 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -163,6 +163,14 @@ Rect2 CollisionShape2D::_edit_get_rect() const {
return rect;
}
+bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ if (!shape.is_valid())
+ return false;
+
+ return shape->_edit_is_selected_on_click(p_point, p_tolerance);
+}
+
String CollisionShape2D::get_configuration_warning() const {
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index 833d9ae5cb..921066c5c8 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -52,6 +52,7 @@ protected:
public:
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
void set_shape(const Ref<Shape2D> &p_shape);
Ref<Shape2D> get_shape() const;
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index f108df140f..abc80216d4 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -48,6 +48,32 @@ Line2D::Line2D() :
_round_precision = 8;
}
+Rect2 Line2D::_edit_get_rect() const {
+
+ if (_points.size() == 0)
+ return Rect2(0, 0, 0, 0);
+ Vector2 d = Vector2(_width, _width);
+ Rect2 aabb = Rect2(_points[0] - d, 2 * d);
+ for (int i = 1; i < _points.size(); i++) {
+ aabb.expand_to(_points[i] - d);
+ aabb.expand_to(_points[i] + d);
+ }
+ return aabb;
+}
+
+bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ const real_t d = _width / 2 + p_tolerance;
+ PoolVector<Vector2>::Read points = _points.read();
+ for (int i = 0; i < _points.size() - 1; i++) {
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, &points[i]);
+ if (p.distance_to(p_point) <= d)
+ return true;
+ }
+
+ return false;
+}
+
void Line2D::set_points(const PoolVector<Vector2> &p_points) {
_points = p_points;
update();
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index 123728ab39..54a4683dc7 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -57,6 +57,9 @@ public:
Line2D();
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_points(const PoolVector<Vector2> &p_points);
PoolVector<Vector2> get_points() const;
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index 9c297db52b..dde41dbf3f 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -35,9 +35,50 @@
#include "thirdparty/misc/triangulator.h"
+Rect2 NavigationPolygon::_edit_get_rect() const {
+
+ if (rect_cache_dirty) {
+ item_rect = Rect2();
+ bool first = true;
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const PoolVector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3)
+ continue;
+ PoolVector<Vector2>::Read p = outline.read();
+ for (int j = 0; j < outline_size; j++) {
+ if (first) {
+ item_rect = Rect2(p[j], Vector2(0, 0));
+ first = false;
+ } else {
+ item_rect.expand_to(p[j]);
+ }
+ }
+ }
+
+ rect_cache_dirty = false;
+ }
+ return item_rect;
+}
+
+bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const PoolVector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3)
+ continue;
+ if (Geometry::is_point_in_polygon(p_point, Variant(outline)))
+ return true;
+ }
+ return false;
+}
+
void NavigationPolygon::set_vertices(const PoolVector<Vector2> &p_vertices) {
vertices = p_vertices;
+ rect_cache_dirty = true;
}
PoolVector<Vector2> NavigationPolygon::get_vertices() const {
@@ -70,6 +111,7 @@ void NavigationPolygon::_set_outlines(const Array &p_array) {
for (int i = 0; i < p_array.size(); i++) {
outlines[i] = p_array[i];
}
+ rect_cache_dirty = true;
}
Array NavigationPolygon::_get_outlines() const {
@@ -93,6 +135,7 @@ void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
void NavigationPolygon::add_outline_at_index(const PoolVector<Vector2> &p_outline, int p_index) {
outlines.insert(p_index, p_outline);
+ rect_cache_dirty = true;
}
int NavigationPolygon::get_polygon_count() const {
@@ -112,6 +155,7 @@ void NavigationPolygon::clear_polygons() {
void NavigationPolygon::add_outline(const PoolVector<Vector2> &p_outline) {
outlines.push_back(p_outline);
+ rect_cache_dirty = true;
}
int NavigationPolygon::get_outline_count() const {
@@ -122,12 +166,14 @@ int NavigationPolygon::get_outline_count() const {
void NavigationPolygon::set_outline(int p_idx, const PoolVector<Vector2> &p_outline) {
ERR_FAIL_INDEX(p_idx, outlines.size());
outlines[p_idx] = p_outline;
+ rect_cache_dirty = true;
}
void NavigationPolygon::remove_outline(int p_idx) {
ERR_FAIL_INDEX(p_idx, outlines.size());
outlines.remove(p_idx);
+ rect_cache_dirty = true;
}
PoolVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
@@ -138,6 +184,7 @@ PoolVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
void NavigationPolygon::clear_outlines() {
outlines.clear();
+ rect_cache_dirty = true;
}
void NavigationPolygon::make_polygons_from_outlines() {
@@ -269,7 +316,8 @@ void NavigationPolygon::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_outlines", "_get_outlines");
}
-NavigationPolygon::NavigationPolygon() {
+NavigationPolygon::NavigationPolygon() :
+ rect_cache_dirty(true) {
}
void NavigationPolygonInstance::set_enabled(bool p_enabled) {
@@ -311,6 +359,16 @@ bool NavigationPolygonInstance::is_enabled() const {
/////////////////////////////
+Rect2 NavigationPolygonInstance::_edit_get_rect() const {
+
+ return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
+}
+
+bool NavigationPolygonInstance::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false;
+}
+
void NavigationPolygonInstance::_notification(int p_what) {
switch (p_what) {
diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h
index febdcf2ca6..7b5220f92d 100644
--- a/scene/2d/navigation_polygon.h
+++ b/scene/2d/navigation_polygon.h
@@ -43,6 +43,9 @@ class NavigationPolygon : public Resource {
Vector<Polygon> polygons;
Vector<PoolVector<Vector2> > outlines;
+ mutable Rect2 item_rect;
+ mutable bool rect_cache_dirty;
+
protected:
static void _bind_methods();
@@ -53,6 +56,9 @@ protected:
Array _get_outlines() const;
public:
+ Rect2 _edit_get_rect() const;
+ bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_vertices(const PoolVector<Vector2> &p_vertices);
PoolVector<Vector2> get_vertices() const;
@@ -93,6 +99,9 @@ protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 06bd55858c..d2a307a9ed 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -32,6 +32,51 @@
#include "engine.h"
#include "scene/scene_string_names.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_scale.h"
+#endif
+
+Rect2 Path2D::_edit_get_rect() const {
+
+ if (curve->get_point_count() == 0)
+ return Rect2(0, 0, 0, 0);
+
+ Rect2 aabb = Rect2(curve->get_point_position(0), Vector2(0, 0));
+
+ for (int i = 0; i < curve->get_point_count(); i++) {
+
+ for (int j = 0; j <= 8; j++) {
+
+ real_t frac = j / 8.0;
+ Vector2 p = curve->interpolate(i, frac);
+ aabb.expand_to(p);
+ }
+ }
+
+ return aabb;
+}
+
+bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ for (int i = 0; i < curve->get_point_count(); i++) {
+ Vector2 s[2];
+ s[0] = curve->get_point_position(i);
+
+ for (int j = 1; j <= 8; j++) {
+ real_t frac = j / 8.0;
+ s[1] = curve->interpolate(i, frac);
+
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, s);
+ if (p.distance_to(p_point) <= p_tolerance)
+ return true;
+
+ s[0] = s[1];
+ }
+ }
+
+ return false;
+}
+
void Path2D::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW && curve.is_valid()) {
@@ -41,6 +86,13 @@ void Path2D::_notification(int p_what) {
return;
}
+#if TOOLS_ENABLED
+ const float line_width = 2 * EDSCALE;
+#else
+ const float line_width = 2;
+#endif
+ const Color color = Color(0.5, 0.6, 1.0, 0.7);
+
for (int i = 0; i < curve->get_point_count(); i++) {
Vector2 prev_p = curve->get_point_position(i);
@@ -49,7 +101,7 @@ void Path2D::_notification(int p_what) {
real_t frac = j / 8.0;
Vector2 p = curve->interpolate(i, frac);
- draw_line(prev_p, p, Color(0.5, 0.6, 1.0, 0.7), 2);
+ draw_line(prev_p, p, color, line_width);
prev_p = p;
}
}
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index ebfa77d605..7f53821c7e 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -46,6 +46,9 @@ protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_curve(const Ref<Curve2D> &p_curve);
Ref<Curve2D> get_curve() const;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index a2f49d938b..f9951cdd08 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "polygon_2d.h"
+#include "core/math/geometry.h"
Rect2 Polygon2D::_edit_get_rect() const {
@@ -42,13 +43,17 @@ Rect2 Polygon2D::_edit_get_rect() const {
else
item_rect.expand_to(pos);
}
- item_rect = item_rect.grow(20);
rect_cache_dirty = false;
}
return item_rect;
}
+bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, Variant(polygon));
+}
+
void Polygon2D::_edit_set_pivot(const Point2 &p_pivot) {
set_offset(p_pivot);
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index a23e223e6e..5014cbc6e9 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -104,6 +104,7 @@ public:
virtual bool _edit_use_pivot() const;
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
Polygon2D();
};
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index c4a7e5aebd..68df95c042 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -47,6 +47,40 @@ bool Sprite::_edit_use_pivot() const {
return true;
}
+void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
+
+ Size2 s;
+ r_filter_clip = false;
+
+ if (region) {
+
+ s = region_rect.size;
+ r_src_rect = region_rect;
+ r_filter_clip = region_filter_clip;
+ } else {
+ s = Size2(texture->get_size());
+ s = s / Size2(hframes, vframes);
+
+ r_src_rect.size = s;
+ r_src_rect.position.x += float(frame % hframes) * s.x;
+ r_src_rect.position.y += float(frame / hframes) * s.y;
+ }
+
+ Point2 ofs = offset;
+ if (centered)
+ ofs -= s / 2;
+ if (Engine::get_singleton()->get_use_pixel_snap()) {
+ ofs = ofs.floor();
+ }
+
+ r_dst_rect = Rect2(ofs, s);
+
+ if (hflip)
+ r_dst_rect.size.x = -r_dst_rect.size.x;
+ if (vflip)
+ r_dst_rect.size.y = -r_dst_rect.size.y;
+}
+
void Sprite::_notification(int p_what) {
switch (p_what) {
@@ -63,38 +97,9 @@ void Sprite::_notification(int p_what) {
break;
*/
- Size2 s;
- Rect2 src_rect;
- bool filter_clip = false;
-
- if (region) {
-
- s = region_rect.size;
- src_rect = region_rect;
- filter_clip = region_filter_clip;
- } else {
- s = Size2(texture->get_size());
- s = s / Size2(hframes, vframes);
-
- src_rect.size = s;
- src_rect.position.x += float(frame % hframes) * s.x;
- src_rect.position.y += float(frame / hframes) * s.y;
- }
-
- Point2 ofs = offset;
- if (centered)
- ofs -= s / 2;
- if (Engine::get_singleton()->get_use_pixel_snap()) {
- ofs = ofs.floor();
- }
-
- Rect2 dst_rect(ofs, s);
-
- if (hflip)
- dst_rect.size.x = -dst_rect.size.x;
- if (vflip)
- dst_rect.size.y = -dst_rect.size.y;
-
+ Rect2 src_rect, dst_rect;
+ bool filter_clip;
+ _get_rects(src_rect, dst_rect, filter_clip);
texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, filter_clip);
} break;
@@ -257,6 +262,30 @@ int Sprite::get_hframes() const {
return hframes;
}
+bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ if (texture.is_null())
+ return false;
+
+ Rect2 src_rect, dst_rect;
+ bool filter_clip;
+ _get_rects(src_rect, dst_rect, filter_clip);
+
+ if (!dst_rect.has_point(p_point))
+ return false;
+
+ Vector2 q = ((p_point - dst_rect.position) / dst_rect.size) * src_rect.size + src_rect.position;
+
+ Ref<Image> image = texture->get_data();
+ ERR_FAIL_COND_V(image.is_null(), false);
+
+ image->lock();
+ const Color c = image->get_pixel((int)q.x, (int)q.y);
+ image->unlock();
+
+ return c.a > 0.01;
+}
+
Rect2 Sprite::_edit_get_rect() const {
if (texture.is_null())
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
index c437f6d404..7d9b2cf457 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -54,6 +54,8 @@ class Sprite : public Node2D {
int vframes;
int hframes;
+ void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const;
+
protected:
void _notification(int p_what);
@@ -65,6 +67,7 @@ public:
virtual void _edit_set_pivot(const Point2 &p_pivot);
virtual Point2 _edit_get_pivot() const;
virtual bool _edit_use_pivot() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
virtual Rect2 _edit_get_rect() const;
void set_texture(const Ref<Texture> &p_texture);
diff --git a/scene/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/item_list.cpp b/scene/gui/item_list.cpp
index b1c862d1d1..5a4a0b2106 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -930,6 +930,9 @@ void ItemList::_notification(int p_what) {
scroll_bar->hide();
} else {
scroll_bar->show();
+
+ if (do_autoscroll_to_bottom)
+ scroll_bar->set_value(max);
}
break;
}
@@ -1313,6 +1316,11 @@ Size2 ItemList::get_minimum_size() const {
return Size2();
}
+void ItemList::set_autoscroll_to_bottom(const bool p_enable) {
+
+ do_autoscroll_to_bottom = p_enable;
+}
+
void ItemList::set_auto_height(bool p_enable) {
auto_height = p_enable;
@@ -1466,6 +1474,7 @@ ItemList::ItemList() {
ensure_selected_visible = false;
defer_select_single = -1;
allow_rmb_select = false;
+ do_autoscroll_to_bottom = false;
icon_scale = 1.0f;
set_clip_contents(true);
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index df751d8b9d..e56d5e5224 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -107,6 +107,8 @@ private:
real_t icon_scale;
+ bool do_autoscroll_to_bottom;
+
Array _get_items() const;
void _set_items(const Array &p_items);
@@ -212,6 +214,8 @@ public:
Size2 get_minimum_size() const;
+ void set_autoscroll_to_bottom(const bool p_enable);
+
VScrollBar *get_v_scroll() { return scroll_bar; }
ItemList();
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 34abb1fbcc..dff7722a9e 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -368,6 +368,18 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
shift_selection_check_post(k->get_shift());
} break;
+ case KEY_UP: {
+
+ shift_selection_check_pre(k->get_shift());
+ set_cursor_position(0);
+ shift_selection_check_post(k->get_shift());
+ } break;
+ case KEY_DOWN: {
+
+ shift_selection_check_pre(k->get_shift());
+ set_cursor_position(text.length());
+ shift_selection_check_post(k->get_shift());
+ } break;
case KEY_DELETE: {
if (!editable)
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 46ad956b68..5fbc0c9064 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -2581,22 +2581,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 +2642,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 +2725,8 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_scroll_lines_down();
break;
}
+
+ {
#else
if (k->get_command() && k->get_alt()) {
_scroll_lines_down();
@@ -2739,9 +2735,15 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_command())
cursor_set_line(text.size() - 1, true, false);
- else
+ else {
#endif
- cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false);
+ if (!is_last_visible_line(cursor.line)) {
+ cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false);
+ } else {
+ cursor_set_line(text.size() - 1);
+ cursor_set_column(get_line(cursor.line).length(), true);
+ }
+ }
if (k->get_shift())
_post_shift_selection();
@@ -3137,6 +3139,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
void TextEdit::_scroll_up(real_t p_delta) {
+ if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(-p_delta))
+ scrolling = false;
+
if (scrolling) {
target_v_scroll = (target_v_scroll - p_delta);
} else {
@@ -3147,8 +3152,12 @@ void TextEdit::_scroll_up(real_t p_delta) {
if (target_v_scroll <= 0) {
target_v_scroll = 0;
}
- scrolling = true;
- set_physics_process(true);
+ if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
+ v_scroll->set_value(target_v_scroll);
+ } else {
+ scrolling = true;
+ set_physics_process(true);
+ }
} else {
v_scroll->set_value(target_v_scroll);
}
@@ -3156,6 +3165,9 @@ void TextEdit::_scroll_up(real_t p_delta) {
void TextEdit::_scroll_down(real_t p_delta) {
+ if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(p_delta))
+ scrolling = false;
+
if (scrolling) {
target_v_scroll = (target_v_scroll + p_delta);
} else {
@@ -3172,8 +3184,13 @@ void TextEdit::_scroll_down(real_t p_delta) {
if (target_v_scroll > max_v_scroll) {
target_v_scroll = max_v_scroll;
}
- scrolling = true;
- set_physics_process(true);
+
+ if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
+ v_scroll->set_value(target_v_scroll);
+ } else {
+ scrolling = true;
+ set_physics_process(true);
+ }
} else {
v_scroll->set_value(target_v_scroll);
}
@@ -4590,6 +4607,24 @@ int TextEdit::num_lines_from(int p_line_from, int unhidden_amount) const {
return num_total;
}
+bool TextEdit::is_last_visible_line(int p_line) const {
+
+ ERR_FAIL_INDEX_V(p_line, text.size(), false);
+
+ if (p_line == text.size() - 1)
+ return true;
+
+ if (!is_hiding_enabled())
+ return false;
+
+ for (int i = p_line + 1; i < text.size(); i++) {
+ if (!is_line_hidden(i))
+ return false;
+ }
+
+ return true;
+}
+
int TextEdit::get_indent_level(int p_line) const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 320bb6d9fd..ccd7ba8278 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -433,6 +433,7 @@ public:
void fold_all_lines();
void unhide_all_lines();
int num_lines_from(int p_line_from, int unhidden_amount) const;
+ bool is_last_visible_line(int p_line) const;
bool can_fold(int p_line) const;
bool is_folded(int p_line) const;
void fold_line(int p_line);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 07f93fa52b..632d912e43 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -2126,6 +2126,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);
ClassDB::bind_method(D_METHOD("set_auto_accept_quit", "enabled"), &SceneTree::set_auto_accept_quit);
+ ClassDB::bind_method(D_METHOD("set_quit_on_go_back", "enabled"), &SceneTree::set_quit_on_go_back);
ClassDB::bind_method(D_METHOD("set_debug_collisions_hint", "enable"), &SceneTree::set_debug_collisions_hint);
ClassDB::bind_method(D_METHOD("is_debugging_collisions_hint"), &SceneTree::is_debugging_collisions_hint);
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index 7b2dbf8e8c..2722ff7207 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -32,6 +32,25 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+Vector<Vector2> CapsuleShape2D::_get_points() const {
+
+ Vector<Vector2> points;
+ for (int i = 0; i < 24; i++) {
+ Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5);
+
+ points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs);
+ if (i == 6 || i == 18)
+ points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs);
+ }
+
+ return points;
+}
+
+bool CapsuleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, _get_points());
+}
+
void CapsuleShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), Vector2(radius, height));
@@ -62,15 +81,7 @@ real_t CapsuleShape2D::get_height() const {
void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- Vector<Vector2> points;
- for (int i = 0; i < 24; i++) {
- Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5);
-
- points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs);
- if (i == 6 || i == 18)
- points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs);
- }
-
+ Vector<Vector2> points = _get_points();
Vector<Color> col;
col.push_back(p_color);
VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h
index 7ce6a4ed63..784f2c02c8 100644
--- a/scene/resources/capsule_shape_2d.h
+++ b/scene/resources/capsule_shape_2d.h
@@ -39,11 +39,14 @@ class CapsuleShape2D : public Shape2D {
real_t radius;
void _update_shape();
+ Vector<Vector2> _get_points() const;
protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_height(real_t p_height);
real_t get_height() const;
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index d9d0ddbe8f..669b1d8e7d 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -31,6 +31,12 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+
+bool CircleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return p_point.length() < get_radius() + p_tolerance;
+}
+
void CircleShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), radius);
diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h
index f14f8f6776..3668521a55 100644
--- a/scene/resources/circle_shape_2d.h
+++ b/scene/resources/circle_shape_2d.h
@@ -42,6 +42,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_radius(real_t p_radius);
real_t get_radius() const;
diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp
index 19985d4acf..69765796f6 100644
--- a/scene/resources/concave_polygon_shape_2d.cpp
+++ b/scene/resources/concave_polygon_shape_2d.cpp
@@ -32,6 +32,23 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool ConcavePolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ PoolVector<Vector2> s = get_segments();
+ int len = s.size();
+ if (len == 0 || (len % 2) == 1)
+ return false;
+
+ PoolVector<Vector2>::Read r = s.read();
+ for (int i = 0; i < len; i += 2) {
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, &r[i]);
+ if (p_point.distance_to(closest) < p_tolerance)
+ return true;
+ }
+
+ return false;
+}
+
void ConcavePolygonShape2D::set_segments(const PoolVector<Vector2> &p_segments) {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), p_segments);
diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h
index 4a5defe72c..7ca14d4d66 100644
--- a/scene/resources/concave_polygon_shape_2d.h
+++ b/scene/resources/concave_polygon_shape_2d.h
@@ -39,6 +39,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_segments(const PoolVector<Vector2> &p_segments);
PoolVector<Vector2> get_segments() const;
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index 98ef2ca7c6..0402a70898 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -33,6 +33,11 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, points);
+}
+
void ConvexPolygonShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), points);
diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h
index f492b7651b..320cf94a5e 100644
--- a/scene/resources/convex_polygon_shape_2d.h
+++ b/scene/resources/convex_polygon_shape_2d.h
@@ -42,6 +42,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_point_cloud(const Vector<Vector2> &p_points);
void set_points(const Vector<Vector2> &p_points);
Vector<Vector2> get_points() const;
diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp
index 4682ef5cb3..346599b25a 100644
--- a/scene/resources/segment_shape_2d.cpp
+++ b/scene/resources/segment_shape_2d.cpp
@@ -32,6 +32,13 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool SegmentShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ Vector2 l[2] = { a, b };
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l);
+ return p_point.distance_to(closest) < p_tolerance;
+}
+
void SegmentShape2D::_update_shape() {
Rect2 r;
diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h
index 1285ae4f82..39a71f61d5 100644
--- a/scene/resources/segment_shape_2d.h
+++ b/scene/resources/segment_shape_2d.h
@@ -44,6 +44,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_a(const Vector2 &p_a);
void set_b(const Vector2 &p_b);
diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h
index 5c2c24ed74..877a159aee 100644
--- a/scene/resources/shape_2d.h
+++ b/scene/resources/shape_2d.h
@@ -44,6 +44,8 @@ protected:
Shape2D(const RID &p_rid);
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return true; }
+
void set_custom_solver_bias(real_t p_bias);
real_t get_custom_solver_bias() const;
diff --git a/scene/resources/shape_line_2d.cpp b/scene/resources/shape_line_2d.cpp
index c6cc3659f6..9548d35370 100644
--- a/scene/resources/shape_line_2d.cpp
+++ b/scene/resources/shape_line_2d.cpp
@@ -30,6 +30,21 @@
#include "shape_line_2d.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+
+bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ Vector2 point = get_d() * get_normal();
+ Vector2 l[2][2] = { { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }, { point, point + get_normal() * 30 } };
+
+ for (int i = 0; i < 2; i++) {
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l[i]);
+ if (p_point.distance_to(closest) < p_tolerance)
+ return true;
+ }
+
+ return false;
+}
+
void LineShape2D::_update_shape() {
Array arr;
diff --git a/scene/resources/shape_line_2d.h b/scene/resources/shape_line_2d.h
index 747500b0ac..fe6f2d675e 100644
--- a/scene/resources/shape_line_2d.h
+++ b/scene/resources/shape_line_2d.h
@@ -44,6 +44,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_normal(const Vector2 &p_normal);
void set_d(real_t p_d);
diff --git a/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);