diff options
304 files changed, 4077 insertions, 1541 deletions
diff --git a/.editorconfig b/.editorconfig index ab03b8421c..56cc2e9c2d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ insert_final_newline = true [*.{cpp,hpp,c,h,mm}] trim_trailing_whitespace = true -[{*.{py,cs},SCsub}] +[{*.{py,cs},SConstruct,SCsub}] indent_style = space indent_size = 4 diff --git a/.gitattributes b/.gitattributes index 47ba2b45bb..40a5e6183f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,12 +1,15 @@ # Properly detect languages on Github *.h linguist-language=cpp *.inc linguist-language=cpp -drivers/* linguist-vendored +thirdparty/* linguist-vendored -*.cpp eol=lf -*.mm eol=lf -*.h eol=lf -*.py eol=lf -*.hpp eol=lf -*.xml eol=lf -*.natvis eol=lf +# Normalize EOL for all files that Git considers text files +* text=auto eol=lf + +# The above only works properly for Git 2.10+, so for older versions +# we need to manually list the binary files we don't want modified. +*.icns binary +*.ico binary +*.jar binary +*.png binary +*.ttf binary diff --git a/.gitignore b/.gitignore index cd6785a8ec..4ef5603f52 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ platform/android/java/local.properties platform/android/java/project.properties platform/android/java/libs/* platform/android/java/assets -platform/android/java/.idea/* platform/android/java/*.iml # General c++ generated files @@ -52,13 +51,19 @@ gmon.out # Eclipse CDT files .cproject .settings/ +*.pydevproject +*.launch # Geany/geany-plugins files *.geany .geanyprj +# Jetbrains IDEs +.idea/ + # Misc .DS_Store +__MACOSX logs/ # for projects that use SCons for building: http://http://www.scons.org/ @@ -66,7 +71,6 @@ logs/ .sconsign.dblite *.pyc - # https://github.com/github/gitignore/blob/master/VisualStudio.gitignore ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. @@ -123,6 +127,7 @@ TestResult.xml *.tlh *.tmp *.tmp_proj +*.bak *.log *.vspscc *.vssscc @@ -130,6 +135,7 @@ TestResult.xml *.pidb *.svclog *.scc +*.nib # Chutzpah Test files _Chutzpah* @@ -245,8 +251,11 @@ __pycache__/ #Kdevelop project files *.kdev4 -# xCode -xcuserdata +# Xcode +xcuserdata/ +*.xcscmblueprint +*.xccheckout +*.xcodeproj/* # RIA/Silverlight projects Generated_Code/ @@ -275,11 +284,19 @@ FakesAssemblies/ # ========================= # Windows image file caches -Thumbs.db +[Tt]humbs.db +[Tt]humbs.db:encryptable ehthumbs.db +ehthumbs_vista.db + +# Windows stackdumps +*.stackdump + +# Windows shortcuts +*.lnk # Folder config file -Desktop.ini +[Dd]esktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ diff --git a/SConstruct b/SConstruct index 88bb43fbc7..17cf779d4a 100644 --- a/SConstruct +++ b/SConstruct @@ -149,7 +149,7 @@ opts.Add(BoolVariable('builtin_libwebsockets', "Use the built-in libwebsockets l opts.Add(BoolVariable('builtin_mbedtls', "Use the built-in mbedTLS library", True)) opts.Add(BoolVariable('builtin_miniupnpc', "Use the built-in miniupnpc library", True)) opts.Add(BoolVariable('builtin_opus', "Use the built-in Opus library", True)) -opts.Add(BoolVariable('builtin_pcre2', "Use the built-in PCRE2 library)", True)) +opts.Add(BoolVariable('builtin_pcre2', "Use the built-in PCRE2 library", True)) opts.Add(BoolVariable('builtin_recast', "Use the built-in Recast library", True)) opts.Add(BoolVariable('builtin_squish', "Use the built-in squish library", True)) opts.Add(BoolVariable('builtin_xatlas', "Use the built-in xatlas library", True)) @@ -226,6 +226,23 @@ if env_base['platform'] != "": elif env_base['p'] != "": selected_platform = env_base['p'] env_base["platform"] = selected_platform +else: + # Missing `platform` argument, try to detect platform automatically + if sys.platform.startswith('linux'): + selected_platform = 'x11' + elif sys.platform == 'darwin': + selected_platform = 'osx' + elif sys.platform == 'win32': + selected_platform = 'windows' + else: + print("Could not detect platform automatically. Supported platforms:") + for x in platform_list: + print("\t" + x) + print("\nPlease run SCons again and select a valid platform: platform=<string>") + + if selected_platform != "": + print("Automatically detected platform: " + selected_platform) + env_base["platform"] = selected_platform if selected_platform in platform_list: tmppath = "./platform/" + selected_platform @@ -492,13 +509,13 @@ if selected_platform in platform_list: if (conf.CheckCHeader(header[0])): env.AppendUnique(CPPDEFINES=[header[1]]) -else: +elif selected_platform != "": - print("No valid target platform selected.") + print("Invalid target platform: " + selected_platform) print("The following platforms were detected:") for x in platform_list: print("\t" + x) - print("\nPlease run SCons again with the argument: platform=<string>") + print("\nPlease run SCons again and select a valid platform: platform=<string>") # The following only makes sense when the env is defined, and assumes it is if 'env' in locals(): diff --git a/core/SCsub b/core/SCsub index 06efc8408d..166b7083e4 100644 --- a/core/SCsub +++ b/core/SCsub @@ -58,6 +58,7 @@ thirdparty_misc_sources = [ "md5.cpp", "pcg.cpp", "triangulator.cpp", + "clipper.cpp", ] thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources] env_thirdparty.add_source_files(env.core_sources, thirdparty_misc_sources) diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index ba595b9627..dbfa04be4d 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -442,14 +442,14 @@ Error _OS::shell_open(String p_uri) { return OS::get_singleton()->shell_open(p_uri); }; -int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output) { +int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr) { OS::ProcessID pid = -2; List<String> args; for (int i = 0; i < p_arguments.size(); i++) args.push_back(p_arguments[i]); String pipe; - Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe); + Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, NULL, p_read_stderr); p_output.clear(); p_output.push_back(pipe); if (err != OK) @@ -611,6 +611,11 @@ uint64_t _OS::get_dynamic_memory_usage() const { return OS::get_singleton()->get_dynamic_memory_usage(); } +void _OS::set_native_icon(const String &p_filename) { + + OS::get_singleton()->set_native_icon(p_filename); +} + void _OS::set_icon(const Ref<Image> &p_icon) { OS::get_singleton()->set_icon(p_icon); @@ -1178,7 +1183,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_processor_count"), &_OS::get_processor_count); ClassDB::bind_method(D_METHOD("get_executable_path"), &_OS::get_executable_path); - ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output"), &_OS::execute, DEFVAL(Array())); + ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output", "read_stderr"), &_OS::execute, DEFVAL(Array()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("kill", "pid"), &_OS::kill); ClassDB::bind_method(D_METHOD("shell_open", "uri"), &_OS::shell_open); ClassDB::bind_method(D_METHOD("get_process_id"), &_OS::get_process_id); @@ -1199,6 +1204,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_system_time_secs"), &_OS::get_system_time_secs); ClassDB::bind_method(D_METHOD("get_system_time_msecs"), &_OS::get_system_time_msecs); + ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &_OS::set_native_icon); ClassDB::bind_method(D_METHOD("set_icon", "icon"), &_OS::set_icon); ClassDB::bind_method(D_METHOD("get_exit_code"), &_OS::get_exit_code); @@ -1491,11 +1497,21 @@ PoolVector<Vector3> _Geometry::segment_intersects_convex(const Vector3 &p_from, return r; } +bool _Geometry::is_polygon_clockwise(const Vector<Vector2> &p_polygon) { + + return Geometry::is_polygon_clockwise(p_polygon); +} + Vector<int> _Geometry::triangulate_polygon(const Vector<Vector2> &p_polygon) { return Geometry::triangulate_polygon(p_polygon); } +Vector<int> _Geometry::triangulate_delaunay_2d(const Vector<Vector2> &p_points) { + + return Geometry::triangulate_delaunay_2d(p_points); +} + Vector<Point2> _Geometry::convex_hull_2d(const Vector<Point2> &p_points) { return Geometry::convex_hull_2d(p_points); @@ -1506,6 +1522,107 @@ Vector<Vector3> _Geometry::clip_polygon(const Vector<Vector3> &p_points, const P return Geometry::clip_polygon(p_points, p_plane); } +Array _Geometry::merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { + + Vector<Vector<Point2> > polys = Geometry::merge_polygons_2d(p_polygon_a, p_polygon_b); + + Array ret; + + for (int i = 0; i < polys.size(); ++i) { + ret.push_back(polys[i]); + } + return ret; +} + +Array _Geometry::clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { + + Vector<Vector<Point2> > polys = Geometry::clip_polygons_2d(p_polygon_a, p_polygon_b); + + Array ret; + + for (int i = 0; i < polys.size(); ++i) { + ret.push_back(polys[i]); + } + return ret; +} + +Array _Geometry::intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { + + Vector<Vector<Point2> > polys = Geometry::intersect_polygons_2d(p_polygon_a, p_polygon_b); + + Array ret; + + for (int i = 0; i < polys.size(); ++i) { + ret.push_back(polys[i]); + } + return ret; +} + +Array _Geometry::exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { + + Vector<Vector<Point2> > polys = Geometry::exclude_polygons_2d(p_polygon_a, p_polygon_b); + + Array ret; + + for (int i = 0; i < polys.size(); ++i) { + ret.push_back(polys[i]); + } + return ret; +} + +Array _Geometry::clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { + + Vector<Vector<Point2> > polys = Geometry::clip_polyline_with_polygon_2d(p_polyline, p_polygon); + + Array ret; + + for (int i = 0; i < polys.size(); ++i) { + ret.push_back(polys[i]); + } + return ret; +} + +Array _Geometry::intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { + + Vector<Vector<Point2> > polys = Geometry::intersect_polyline_with_polygon_2d(p_polyline, p_polygon); + + Array ret; + + for (int i = 0; i < polys.size(); ++i) { + ret.push_back(polys[i]); + } + return ret; +} + +Array _Geometry::offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) { + + Vector<Vector<Point2> > polys = Geometry::offset_polygon_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type)); + + Array ret; + + for (int i = 0; i < polys.size(); ++i) { + ret.push_back(polys[i]); + } + return ret; +} + +Array _Geometry::offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { + + Vector<Vector<Point2> > polys = Geometry::offset_polyline_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type), Geometry::PolyEndType(p_end_type)); + + Array ret; + + for (int i = 0; i < polys.size(); ++i) { + ret.push_back(polys[i]); + } + return ret; +} + +Vector<Point2> _Geometry::transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat) { + + return Geometry::transform_points_2d(p_points, p_mat); +} + Dictionary _Geometry::make_atlas(const Vector<Size2> &p_rects) { Dictionary ret; @@ -1566,11 +1683,41 @@ void _Geometry::_bind_methods() { ClassDB::bind_method(D_METHOD("segment_intersects_convex", "from", "to", "planes"), &_Geometry::segment_intersects_convex); ClassDB::bind_method(D_METHOD("point_is_inside_triangle", "point", "a", "b", "c"), &_Geometry::point_is_inside_triangle); + ClassDB::bind_method(D_METHOD("is_polygon_clockwise", "polygon"), &_Geometry::is_polygon_clockwise); ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &_Geometry::triangulate_polygon); + ClassDB::bind_method(D_METHOD("triangulate_delaunay_2d", "points"), &_Geometry::triangulate_delaunay_2d); ClassDB::bind_method(D_METHOD("convex_hull_2d", "points"), &_Geometry::convex_hull_2d); ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &_Geometry::clip_polygon); + ClassDB::bind_method(D_METHOD("merge_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::merge_polygons_2d); + ClassDB::bind_method(D_METHOD("clip_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::clip_polygons_2d); + ClassDB::bind_method(D_METHOD("intersect_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::intersect_polygons_2d); + ClassDB::bind_method(D_METHOD("exclude_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::exclude_polygons_2d); + + ClassDB::bind_method(D_METHOD("clip_polyline_with_polygon_2d", "polyline", "polygon"), &_Geometry::clip_polyline_with_polygon_2d); + ClassDB::bind_method(D_METHOD("intersect_polyline_with_polygon_2d", "polyline", "polygon"), &_Geometry::intersect_polyline_with_polygon_2d); + + ClassDB::bind_method(D_METHOD("offset_polygon_2d", "polygon", "delta", "join_type"), &_Geometry::offset_polygon_2d, DEFVAL(JOIN_SQUARE)); + ClassDB::bind_method(D_METHOD("offset_polyline_2d", "polyline", "delta", "join_type", "end_type"), &_Geometry::offset_polyline_2d, DEFVAL(JOIN_SQUARE), DEFVAL(END_SQUARE)); + + ClassDB::bind_method(D_METHOD("transform_points_2d", "points", "transform"), &_Geometry::transform_points_2d); + ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &_Geometry::make_atlas); + + BIND_ENUM_CONSTANT(OPERATION_UNION); + BIND_ENUM_CONSTANT(OPERATION_DIFFERENCE); + BIND_ENUM_CONSTANT(OPERATION_INTERSECTION); + BIND_ENUM_CONSTANT(OPERATION_XOR); + + BIND_ENUM_CONSTANT(JOIN_SQUARE); + BIND_ENUM_CONSTANT(JOIN_ROUND); + BIND_ENUM_CONSTANT(JOIN_MITER); + + BIND_ENUM_CONSTANT(END_POLYGON); + BIND_ENUM_CONSTANT(END_JOINED); + BIND_ENUM_CONSTANT(END_BUTT); + BIND_ENUM_CONSTANT(END_SQUARE); + BIND_ENUM_CONSTANT(END_ROUND); } _Geometry::_Geometry() { diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 2906de4a4a..8f74d88be5 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -214,7 +214,7 @@ public: bool is_in_low_processor_usage_mode() const; String get_executable_path() const; - int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output = Array()); + int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output = Array(), bool p_read_stderr = false); Error kill(int p_pid); Error shell_open(String p_uri); @@ -275,6 +275,7 @@ public: void set_use_file_access_save_and_swap(bool p_enable); + void set_native_icon(const String &p_filename); void set_icon(const Ref<Image> &p_icon); int get_exit_code() const; @@ -402,15 +403,55 @@ public: real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius); int get_uv84_normal_bit(const Vector3 &p_vector); + bool is_polygon_clockwise(const Vector<Vector2> &p_polygon); Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon); + Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points); Vector<Point2> convex_hull_2d(const Vector<Point2> &p_points); Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane); + enum PolyBooleanOperation { + OPERATION_UNION, + OPERATION_DIFFERENCE, + OPERATION_INTERSECTION, + OPERATION_XOR + }; + // 2D polygon boolean operations + Array merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // union (add) + Array clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // difference (subtract) + Array intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // common area (multiply) + Array exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // all but common area (xor) + + // 2D polyline vs polygon operations + Array clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // cut + Array intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // chop + + // 2D offset polygons/polylines + enum PolyJoinType { + JOIN_SQUARE, + JOIN_ROUND, + JOIN_MITER + }; + enum PolyEndType { + END_POLYGON, + END_JOINED, + END_BUTT, + END_SQUARE, + END_ROUND + }; + Array offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE); + Array offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE); + + Vector<Point2> transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat); + Dictionary make_atlas(const Vector<Size2> &p_rects); _Geometry(); }; +VARIANT_ENUM_CAST(_Geometry::PolyBooleanOperation); +VARIANT_ENUM_CAST(_Geometry::PolyJoinType); +VARIANT_ENUM_CAST(_Geometry::PolyEndType); + class _File : public Reference { GDCLASS(_File, Reference); diff --git a/core/color_names.inc b/core/color_names.inc index e126bfe0f8..b0ef507d92 100644 --- a/core/color_names.inc +++ b/core/color_names.inc @@ -143,6 +143,7 @@ static void _populate_named_colors() { _named_colors.insert("thistle", Color(0.85, 0.75, 0.85)); _named_colors.insert("tomato", Color(1.00, 0.39, 0.28)); _named_colors.insert("turquoise", Color(0.25, 0.88, 0.82)); + _named_colors.insert("transparent", Color(1.00, 1.00, 1.00, 0.00)); _named_colors.insert("violet", Color(0.93, 0.51, 0.93)); _named_colors.insert("wheat", Color(0.96, 0.87, 0.70)); _named_colors.insert("white", Color(1.00, 1.00, 1.00)); diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 3cf6908961..3ff9fa569c 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -100,6 +100,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8 MD5Update(&md5, (uint8_t *)data.ptr(), data.size()); MD5Final(&md5); + ERR_EXPLAIN("The MD5 sum of the decrypted file does not match the expected value. It could be that the file is corrupt, or that the provided decryption key is invalid."); ERR_FAIL_COND_V(String::md5(md5.digest) != String::md5(md5d), ERR_FILE_CORRUPT); file = p_base; diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 9fcecd1ba6..1540bc8fe1 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -813,21 +813,28 @@ void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) { ERR_FAIL_COND(!p_axis.is_normalized()); #endif Vector3 axis_sq(p_axis.x * p_axis.x, p_axis.y * p_axis.y, p_axis.z * p_axis.z); - real_t cosine = Math::cos(p_phi); - real_t sine = Math::sin(p_phi); - elements[0][0] = axis_sq.x + cosine * (1.0 - axis_sq.x); - elements[0][1] = p_axis.x * p_axis.y * (1.0 - cosine) - p_axis.z * sine; - elements[0][2] = p_axis.z * p_axis.x * (1.0 - cosine) + p_axis.y * sine; - - elements[1][0] = p_axis.x * p_axis.y * (1.0 - cosine) + p_axis.z * sine; elements[1][1] = axis_sq.y + cosine * (1.0 - axis_sq.y); - elements[1][2] = p_axis.y * p_axis.z * (1.0 - cosine) - p_axis.x * sine; - - elements[2][0] = p_axis.z * p_axis.x * (1.0 - cosine) - p_axis.y * sine; - elements[2][1] = p_axis.y * p_axis.z * (1.0 - cosine) + p_axis.x * sine; elements[2][2] = axis_sq.z + cosine * (1.0 - axis_sq.z); + + real_t sine = Math::sin(p_phi); + real_t t = 1 - cosine; + + real_t xyzt = p_axis.x * p_axis.y * t; + real_t zyxs = p_axis.z * sine; + elements[0][1] = xyzt - zyxs; + elements[1][0] = xyzt + zyxs; + + xyzt = p_axis.x * p_axis.z * t; + zyxs = p_axis.y * sine; + elements[0][2] = xyzt + zyxs; + elements[2][0] = xyzt - zyxs; + + xyzt = p_axis.y * p_axis.z * t; + zyxs = p_axis.x * sine; + elements[1][2] = xyzt - zyxs; + elements[2][1] = xyzt + zyxs; } void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index 0ab8707d3a..8314cb827c 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -31,8 +31,11 @@ #include "geometry.h" #include "core/print_string.h" +#include "thirdparty/misc/clipper.hpp" #include "thirdparty/misc/triangulator.h" +#define SCALE_FACTOR 100000.0 // based on CMP_EPSILON + /* this implementation is very inefficient, commenting unless bugs happen. See the other one. bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) { @@ -1134,3 +1137,106 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu r_size = Size2(results[best].max_w, results[best].max_h); } + +Vector<Vector<Point2> > Geometry::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) { + + using namespace ClipperLib; + + ClipType op = ctUnion; + + switch (p_op) { + case OPERATION_UNION: op = ctUnion; break; + case OPERATION_DIFFERENCE: op = ctDifference; break; + case OPERATION_INTERSECTION: op = ctIntersection; break; + case OPERATION_XOR: op = ctXor; break; + } + Path path_a, path_b; + + // Need to scale points (Clipper's requirement for robust computation) + for (int i = 0; i != p_polypath_a.size(); ++i) { + path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR); + } + for (int i = 0; i != p_polypath_b.size(); ++i) { + path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR); + } + Clipper clp; + clp.AddPath(path_a, ptSubject, !is_a_open); // forward compatible with Clipper 10.0.0 + clp.AddPath(path_b, ptClip, true); // polylines cannot be set as clip + + Paths paths; + + if (is_a_open) { + PolyTree tree; // needed to populate polylines + clp.Execute(op, tree); + OpenPathsFromPolyTree(tree, paths); + } else { + clp.Execute(op, paths); // works on closed polygons only + } + // Have to scale points down now + Vector<Vector<Point2> > polypaths; + + for (Paths::size_type i = 0; i < paths.size(); ++i) { + Vector<Vector2> polypath; + + const Path &scaled_path = paths[i]; + + for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { + polypath.push_back(Point2( + static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR, + static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR)); + } + polypaths.push_back(polypath); + } + return polypaths; +} + +Vector<Vector<Point2> > Geometry::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { + + using namespace ClipperLib; + + JoinType jt = jtSquare; + + switch (p_join_type) { + case JOIN_SQUARE: jt = jtSquare; break; + case JOIN_ROUND: jt = jtRound; break; + case JOIN_MITER: jt = jtMiter; break; + } + + EndType et = etClosedPolygon; + + switch (p_end_type) { + case END_POLYGON: et = etClosedPolygon; break; + case END_JOINED: et = etClosedLine; break; + case END_BUTT: et = etOpenButt; break; + case END_SQUARE: et = etOpenSquare; break; + case END_ROUND: et = etOpenRound; break; + } + ClipperOffset co; + Path path; + + // Need to scale points (Clipper's requirement for robust computation) + for (int i = 0; i != p_polypath.size(); ++i) { + path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR); + } + co.AddPath(path, jt, et); + + Paths paths; + co.Execute(paths, p_delta * SCALE_FACTOR); // inflate/deflate + + // Have to scale points down now + Vector<Vector<Point2> > polypaths; + + for (Paths::size_type i = 0; i < paths.size(); ++i) { + Vector<Vector2> polypath; + + const Path &scaled_path = paths[i]; + + for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { + polypath.push_back(Point2( + static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR, + static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR)); + } + polypaths.push_back(polypath); + } + return polypaths; +} diff --git a/core/math/geometry.h b/core/math/geometry.h index 0b2adf9513..0e144e491f 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -31,6 +31,7 @@ #ifndef GEOMETRY_H #define GEOMETRY_H +#include "core/math/delaunay.h" #include "core/math/face3.h" #include "core/math/rect2.h" #include "core/math/triangulate.h" @@ -785,6 +786,91 @@ public: return clipped; } + enum PolyBooleanOperation { + OPERATION_UNION, + OPERATION_DIFFERENCE, + OPERATION_INTERSECTION, + OPERATION_XOR + }; + enum PolyJoinType { + JOIN_SQUARE, + JOIN_ROUND, + JOIN_MITER + }; + enum PolyEndType { + END_POLYGON, + END_JOINED, + END_BUTT, + END_SQUARE, + END_ROUND + }; + + static Vector<Vector<Point2> > merge_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { + + return _polypaths_do_operation(OPERATION_UNION, p_polygon_a, p_polygon_b); + } + + static Vector<Vector<Point2> > clip_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { + + return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polygon_a, p_polygon_b); + } + + static Vector<Vector<Point2> > intersect_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { + + return _polypaths_do_operation(OPERATION_INTERSECTION, p_polygon_a, p_polygon_b); + } + + static Vector<Vector<Point2> > exclude_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) { + + return _polypaths_do_operation(OPERATION_XOR, p_polygon_a, p_polygon_b); + } + + static Vector<Vector<Point2> > clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { + + return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polyline, p_polygon, true); + } + + static Vector<Vector<Point2> > intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { + + return _polypaths_do_operation(OPERATION_INTERSECTION, p_polyline, p_polygon, true); + } + + static Vector<Vector<Point2> > offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) { + + return _polypath_offset(p_polygon, p_delta, p_join_type, END_POLYGON); + } + + static Vector<Vector<Point2> > offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { + + ERR_EXPLAIN("Attempt to offset a polyline like a polygon (use offset_polygon_2d instead)."); + ERR_FAIL_COND_V(p_end_type == END_POLYGON, Vector<Vector<Point2> >()); + + return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type); + } + + static Vector<Point2> transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat) { + + Vector<Point2> points; + + for (int i = 0; i < p_points.size(); ++i) { + points.push_back(p_mat.xform(p_points[i])); + } + return points; + } + + static Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points) { + + Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(p_points); + Vector<int> triangles; + + for (int i = 0; i < tr.size(); i++) { + triangles.push_back(tr[i].points[0]); + triangles.push_back(tr[i].points[1]); + triangles.push_back(tr[i].points[2]); + } + return triangles; + } + static Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon) { Vector<int> triangles; @@ -951,7 +1037,6 @@ public: H.resize(k); return H; } - static Vector<Vector<Vector2> > decompose_polygon_in_convex(Vector<Point2> polygon); static MeshData build_convex_mesh(const PoolVector<Plane> &p_planes); @@ -961,6 +1046,10 @@ public: static PoolVector<Plane> build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z); static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size); + +private: + static Vector<Vector<Point2> > _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false); + static Vector<Vector<Point2> > _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type); }; #endif diff --git a/core/message_queue.cpp b/core/message_queue.cpp index 1d661f25f9..32d2b805f6 100644 --- a/core/message_queue.cpp +++ b/core/message_queue.cpp @@ -302,10 +302,6 @@ void MessageQueue::flush() { _call_function(target, message->target, args, message->args, message->type & FLAG_SHOW_ERROR); - for (int i = 0; i < message->args; i++) { - args[i].~Variant(); - } - } break; case TYPE_NOTIFICATION: { @@ -319,11 +315,17 @@ void MessageQueue::flush() { // messages don't expect a return value target->set(message->target, *arg); - arg->~Variant(); } break; } } + if ((message->type & FLAG_MASK) != TYPE_NOTIFICATION) { + Variant *args = (Variant *)(message + 1); + for (int i = 0; i < message->args; i++) { + args[i].~Variant(); + } + } + message->~Message(); _THREAD_SAFE_LOCK_ diff --git a/core/os/os.cpp b/core/os/os.cpp index ea378c9e83..1a3c9ac5f8 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -465,6 +465,9 @@ void OS::_ensure_user_data_dir() { memdelete(da); } +void OS::set_native_icon(const String &p_filename) { +} + void OS::set_icon(const Ref<Image> &p_icon) { } diff --git a/core/os/os.h b/core/os/os.h index 07865b636e..4f6a539e78 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -451,6 +451,7 @@ public: virtual void make_rendering_thread(); virtual void swap_buffers(); + virtual void set_native_icon(const String &p_filename); virtual void set_icon(const Ref<Image> &p_icon); virtual int get_exit_code() const; diff --git a/core/project_settings.cpp b/core/project_settings.cpp index c86d1567dd..2fd22d4789 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -1007,6 +1007,15 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("audio/default_bus_layout", "res://default_bus_layout.tres"); custom_prop_info["audio/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/default_bus_layout", PROPERTY_HINT_FILE, "*.tres"); + PoolStringArray extensions = PoolStringArray(); + extensions.push_back("gd"); + if (Engine::get_singleton()->has_singleton("GodotSharp")) + extensions.push_back("cs"); + extensions.push_back("shader"); + + GLOBAL_DEF("editor/search_in_file_extensions", extensions); + custom_prop_info["editor/search_in_file_extensions"] = PropertyInfo(Variant::POOL_STRING_ARRAY, "editor/search_in_file_extensions"); + action = Dictionary(); action["deadzone"] = Variant(0.5f); events = Array(); diff --git a/core/ustring.cpp b/core/ustring.cpp index 78feddb229..954c39c150 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -1725,6 +1725,45 @@ int64_t String::hex_to_int64(bool p_with_prefix) const { return hex * sign; } +int64_t String::bin_to_int64(bool p_with_prefix) const { + + if (p_with_prefix && length() < 3) + return 0; + + const CharType *s = ptr(); + + int64_t sign = s[0] == '-' ? -1 : 1; + + if (sign < 0) { + s++; + } + + if (p_with_prefix) { + if (s[0] != '0' || s[1] != 'b') + return 0; + s += 2; + } + + int64_t binary = 0; + + while (*s) { + + CharType c = LOWERCASE(*s); + int64_t n; + if (c == '0' || c == '1') { + n = c - '0'; + } else { + return 0; + } + + binary *= 2; + binary += n; + s++; + } + + return binary * sign; +} + int String::to_int() const { if (length() == 0) diff --git a/core/ustring.h b/core/ustring.h index e2e62874d6..be6300ac5b 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -251,6 +251,7 @@ public: int to_int() const; int64_t hex_to_int64(bool p_with_prefix = true) const; + int64_t bin_to_int64(bool p_with_prefix = true) const; int64_t to_int64() const; static int to_int(const char *p_str, int p_len = -1); static double to_double(const char *p_str); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index d1e2a9c910..760287e1b8 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -45,6 +45,8 @@ <member name="Marshalls" type="Reference" setter="" getter=""> [Marshalls] singleton </member> + <member name="NavigationMeshGenerator" type="EditorNavigationMeshGenerator" setter="" getter=""> + </member> <member name="OS" type="OS" setter="" getter=""> [OS] singleton </member> diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml index 4adf515abc..db35b2f352 100644 --- a/doc/classes/AcceptDialog.xml +++ b/doc/classes/AcceptDialog.xml @@ -36,14 +36,14 @@ <return type="Label"> </return> <description> - Return the label used for built-in text. + Returns the label used for built-in text. </description> </method> <method name="get_ok"> <return type="Button"> </return> <description> - Return the OK Button. + Returns the OK Button. </description> </method> <method name="register_text_enter"> diff --git a/doc/classes/AnimatedSprite.xml b/doc/classes/AnimatedSprite.xml index 5e63f8aec0..da85f91367 100644 --- a/doc/classes/AnimatedSprite.xml +++ b/doc/classes/AnimatedSprite.xml @@ -13,7 +13,7 @@ <return type="bool"> </return> <description> - Return [code]true[/code] if an animation if currently being played. + Returns [code]true[/code] if an animation if currently being played. </description> </method> <method name="play"> diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml index 4c6868d807..96196f7601 100644 --- a/doc/classes/AnimatedSprite3D.xml +++ b/doc/classes/AnimatedSprite3D.xml @@ -13,7 +13,7 @@ <return type="bool"> </return> <description> - Return [code]true[/code] if an animation if currently being played. + Returns [code]true[/code] if an animation if currently being played. </description> </method> <method name="play"> diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index af3abed256..9885f30883 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -263,14 +263,14 @@ <argument index="0" name="path" type="NodePath"> </argument> <description> - Return the index of the specified track. If the track is not found, return -1. + Returns the index of the specified track. If the track is not found, return -1. </description> </method> <method name="get_track_count" qualifiers="const"> <return type="int"> </return> <description> - Return the amount of tracks in the animation. + Returns the amount of tracks in the animation. </description> </method> <method name="method_track_get_key_indices" qualifiers="const"> @@ -283,7 +283,7 @@ <argument index="2" name="delta" type="float"> </argument> <description> - Return all the key indices of a method track, given a position and delta time. + Returns all the key indices of a method track, given a position and delta time. </description> </method> <method name="method_track_get_name" qualifiers="const"> @@ -294,7 +294,7 @@ <argument index="1" name="key_idx" type="int"> </argument> <description> - Return the method name of a method track. + Returns the method name of a method track. </description> </method> <method name="method_track_get_params" qualifiers="const"> @@ -305,7 +305,7 @@ <argument index="1" name="key_idx" type="int"> </argument> <description> - Return the arguments values to be called on a method track for a given key in a given track. + Returns the arguments values to be called on a method track for a given key in a given track. </description> </method> <method name="remove_track"> @@ -345,7 +345,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the interpolation type of a given track, from the INTERPOLATION_* enum. + Returns the interpolation type of a given track, from the INTERPOLATION_* enum. </description> </method> <method name="track_get_key_count" qualifiers="const"> @@ -354,7 +354,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the amount of keys in a given track. + Returns the amount of keys in a given track. </description> </method> <method name="track_get_key_time" qualifiers="const"> @@ -365,7 +365,7 @@ <argument index="1" name="key_idx" type="int"> </argument> <description> - Return the time at which the key is located. + Returns the time at which the key is located. </description> </method> <method name="track_get_key_transition" qualifiers="const"> @@ -376,7 +376,7 @@ <argument index="1" name="key_idx" type="int"> </argument> <description> - Return the transition curve (easing) for a specific key (see built-in math function "ease"). + Returns the transition curve (easing) for a specific key (see built-in math function "ease"). </description> </method> <method name="track_get_key_value" qualifiers="const"> @@ -387,7 +387,7 @@ <argument index="1" name="key_idx" type="int"> </argument> <description> - Return the value of a given key in a given track. + Returns the value of a given key in a given track. </description> </method> <method name="track_get_path" qualifiers="const"> @@ -438,7 +438,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return [code]true[/code] if the given track is imported. Else, return [code]false[/code]. + Returns [code]true[/code] if the given track is imported. Else, return [code]false[/code]. </description> </method> <method name="track_move_down"> @@ -450,6 +450,17 @@ Move a track down. </description> </method> + <method name="track_move_to"> + <return type="void"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <argument index="1" name="to_idx" type="int"> + </argument> + <description> + Changes the index position of track [code]idx[/code] to the one defined in [code]to_idx[/code]. + </description> + </method> <method name="track_move_up"> <return type="void"> </return> @@ -571,6 +582,7 @@ <argument index="1" name="with_idx" type="int"> </argument> <description> + Swaps the track [code]idx[/code]'s index position with the track [code]with_idx[/code]. </description> </method> <method name="transform_track_insert_key"> @@ -598,7 +610,7 @@ <argument index="1" name="time_sec" type="float"> </argument> <description> - Return the interpolated value of a transform track at a given time (in seconds). An array consisting of 3 elements: position ([Vector3]), rotation ([Quat]) and scale ([Vector3]). + Returns the interpolated value of a transform track at a given time (in seconds). An array consisting of 3 elements: position ([Vector3]), rotation ([Quat]) and scale ([Vector3]). </description> </method> <method name="value_track_get_key_indices" qualifiers="const"> @@ -611,7 +623,7 @@ <argument index="2" name="delta" type="float"> </argument> <description> - Return all the key indices of a value track, given a position and delta time. + Returns all the key indices of a value track, given a position and delta time. </description> </method> <method name="value_track_get_update_mode" qualifiers="const"> @@ -620,7 +632,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the update mode of a value track. + Returns the update mode of a value track. </description> </method> <method name="value_track_set_update_mode"> diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index c1307be924..9854d4c27e 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -144,7 +144,7 @@ <return type="String"> </return> <description> - Return [code]true[/code] whether you want the blend tree editor to display filter editing on this node. + Returns [code]true[/code] whether you want the blend tree editor to display filter editing on this node. </description> </method> <method name="is_path_filtered" qualifiers="const"> @@ -153,7 +153,7 @@ <argument index="0" name="path" type="NodePath"> </argument> <description> - Return [code]true[/code] whether a given path is filtered. + Returns [code]true[/code] whether a given path is filtered. </description> </method> <method name="process" qualifiers="virtual"> @@ -204,7 +204,7 @@ </methods> <members> <member name="filter_enabled" type="bool" setter="set_filter_enabled" getter="is_filter_enabled"> - Return whether filtering is enabled. + Returns whether filtering is enabled. </member> </members> <signals> diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml index 8f4e6dff69..2834f83d2f 100644 --- a/doc/classes/AnimationNodeStateMachine.xml +++ b/doc/classes/AnimationNodeStateMachine.xml @@ -1,12 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AnimationNodeStateMachine" inherits="AnimationRootNode" category="Core" version="3.2"> <brief_description> + State machine for control of animations. </brief_description> <description> - Contains multiple root nodes as children in a graph. Each node is used as a state, and provides multiple functions to alternate between states. Retrieve the AnimationNodeStateMachinePlayback object from the [AnimationTree] node to control it programmatically. + Contains multiple nodes representing animation states, connected in a graph. Nodes transitions can be configured to happen automatically or via code, using a shortest-path algorithm. Retrieve the AnimationNodeStateMachinePlayback object from the [AnimationTree] node to control it programatically. Example: [codeblock] - var state_machine = anim_tree["parameters/StateMachine/playback"] - state_machine.travel("SomeState") + var state_machine = $AnimationTree.get("parameters/playback") + state_machine.travel("some_state") [/codeblock] </description> <tutorials> @@ -22,6 +23,7 @@ <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )"> </argument> <description> + Adds a new node to the graph. The [code]position[/code] is used for display in the editor. </description> </method> <method name="add_transition"> @@ -34,18 +36,21 @@ <argument index="2" name="transition" type="AnimationNodeStateMachineTransition"> </argument> <description> + Adds a transition between the given nodes. </description> </method> <method name="get_end_node" qualifiers="const"> <return type="String"> </return> <description> + Returns the graph's end node. </description> </method> <method name="get_graph_offset" qualifiers="const"> <return type="Vector2"> </return> <description> + Returns the draw offset of the graph. Used for display in the editor. </description> </method> <method name="get_node" qualifiers="const"> @@ -54,6 +59,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns the animation node with the given name. </description> </method> <method name="get_node_name" qualifiers="const"> @@ -62,6 +68,7 @@ <argument index="0" name="node" type="AnimationNode"> </argument> <description> + Returns the given animation node's name. </description> </method> <method name="get_node_position" qualifiers="const"> @@ -70,12 +77,14 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns the given node's coordinates. Used for display in the editor. </description> </method> <method name="get_start_node" qualifiers="const"> <return type="String"> </return> <description> + Returns the graph's end node. </description> </method> <method name="get_transition" qualifiers="const"> @@ -84,12 +93,14 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the given transition. </description> </method> <method name="get_transition_count" qualifiers="const"> <return type="int"> </return> <description> + Returns the number of connections in the graph. </description> </method> <method name="get_transition_from" qualifiers="const"> @@ -98,6 +109,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the given transition's start node. </description> </method> <method name="get_transition_to" qualifiers="const"> @@ -106,6 +118,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the given transition's end node. </description> </method> <method name="has_node" qualifiers="const"> @@ -114,6 +127,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if the graph contains the given node. </description> </method> <method name="has_transition" qualifiers="const"> @@ -124,6 +138,7 @@ <argument index="1" name="to" type="String"> </argument> <description> + Returns [code]true[/code] if there is a transition between the given nodes. </description> </method> <method name="remove_node"> @@ -132,6 +147,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Deletes the given node from the graph. </description> </method> <method name="remove_transition"> @@ -142,6 +158,7 @@ <argument index="1" name="to" type="String"> </argument> <description> + Deletes the given transition. </description> </method> <method name="remove_transition_by_index"> @@ -150,6 +167,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Deletes the given transition. </description> </method> <method name="rename_node"> @@ -160,6 +178,7 @@ <argument index="1" name="new_name" type="String"> </argument> <description> + Renames the given node. </description> </method> <method name="set_end_node"> @@ -168,6 +187,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Sets the given node as the graph end point. </description> </method> <method name="set_graph_offset"> @@ -176,6 +196,7 @@ <argument index="0" name="offset" type="Vector2"> </argument> <description> + Sets the draw offset of the graph. Used for display in the editor. </description> </method> <method name="set_node_position"> @@ -186,6 +207,7 @@ <argument index="1" name="position" type="Vector2"> </argument> <description> + Sets the node's coordinates. Used for display in the editor. </description> </method> <method name="set_start_node"> @@ -194,6 +216,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Sets the given node as the graph start point. </description> </method> </methods> diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml index fd38c28b16..796d92d7d6 100644 --- a/doc/classes/AnimationNodeStateMachinePlayback.xml +++ b/doc/classes/AnimationNodeStateMachinePlayback.xml @@ -1,8 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AnimationNodeStateMachinePlayback" inherits="Resource" category="Core" version="3.2"> <brief_description> + Playback control for AnimationNodeStateMachine. </brief_description> <description> + Allows control of [AnimationTree] state machines created with [AnimationNodeStateMachine]. Retrieve with [code]$AnimationTree.get("parameters/playback")[/code]. Example: + [codeblock] + var state_machine = $AnimationTree.get("parameters/playback") + state_machine.travel("some_state") + [/codeblock] </description> <tutorials> </tutorials> @@ -11,6 +17,7 @@ <return type="String"> </return> <description> + Returns the currently playing animation state. </description> </method> <method name="get_travel_path" qualifiers="const"> @@ -23,6 +30,7 @@ <return type="bool"> </return> <description> + Returns [code]true[/code] if an animation is playing. </description> </method> <method name="start"> @@ -31,12 +39,14 @@ <argument index="0" name="node" type="String"> </argument> <description> + Starts playing the given animation. </description> </method> <method name="stop"> <return type="void"> </return> <description> + Stops the currently playing animation. </description> </method> <method name="travel"> @@ -45,7 +55,7 @@ <argument index="0" name="to_node" type="String"> </argument> <description> - Transition from the current state to another one, while visiting all the intermediate ones. This is done via the A* algorithm. + Transitions from the current state to another one, following the shortest path. </description> </method> </methods> diff --git a/doc/classes/AnimationTreePlayer.xml b/doc/classes/AnimationTreePlayer.xml index 6160b44076..818565e0dc 100644 --- a/doc/classes/AnimationTreePlayer.xml +++ b/doc/classes/AnimationTreePlayer.xml @@ -256,7 +256,7 @@ <argument index="0" name="id" type="String"> </argument> <description> - Return the input count for a given node. Different types of nodes have different amount of inputs. + Returns the input count for a given node. Different types of nodes have different amount of inputs. </description> </method> <method name="node_get_input_source" qualifiers="const"> @@ -267,7 +267,7 @@ <argument index="1" name="idx" type="int"> </argument> <description> - Return the input source for a given node input. + Returns the input source for a given node input. </description> </method> <method name="node_get_position" qualifiers="const"> diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml index 2400efe0d3..8d28ddc889 100644 --- a/doc/classes/Area2D.xml +++ b/doc/classes/Area2D.xml @@ -15,7 +15,7 @@ <argument index="0" name="bit" type="int"> </argument> <description> - Return an individual bit on the layer mask. Describes whether other areas will collide with this one on the given layer. + Returns an individual bit on the layer mask. Describes whether other areas will collide with this one on the given layer. </description> </method> <method name="get_collision_mask_bit" qualifiers="const"> @@ -24,7 +24,7 @@ <argument index="0" name="bit" type="int"> </argument> <description> - Return an individual bit on the collision mask. Describes whether this area will collide with others on the given layer. + Returns an individual bit on the collision mask. Describes whether this area will collide with others on the given layer. </description> </method> <method name="get_overlapping_areas" qualifiers="const"> diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index db0fc77b25..1707ea07e0 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -98,7 +98,7 @@ <argument index="0" name="name" type="String"> </argument> <description> - Return the index of the first surface with this name held within this [ArrayMesh]. If none are found -1 is returned. + Returns the index of the first surface with this name held within this [ArrayMesh]. If none are found -1 is returned. </description> </method> <method name="surface_get_array_index_len" qualifiers="const"> @@ -107,7 +107,7 @@ <argument index="0" name="surf_idx" type="int"> </argument> <description> - Return the length in indices of the index array in the requested surface (see [method add_surface_from_arrays]). + Returns the length in indices of the index array in the requested surface (see [method add_surface_from_arrays]). </description> </method> <method name="surface_get_array_len" qualifiers="const"> @@ -116,7 +116,7 @@ <argument index="0" name="surf_idx" type="int"> </argument> <description> - Return the length in vertices of the vertex array in the requested surface (see [method add_surface_from_arrays]). + Returns the length in vertices of the vertex array in the requested surface (see [method add_surface_from_arrays]). </description> </method> <method name="surface_get_format" qualifiers="const"> @@ -125,7 +125,7 @@ <argument index="0" name="surf_idx" type="int"> </argument> <description> - Return the format mask of the requested surface (see [method add_surface_from_arrays]). + Returns the format mask of the requested surface (see [method add_surface_from_arrays]). </description> </method> <method name="surface_get_name" qualifiers="const"> @@ -143,7 +143,7 @@ <argument index="0" name="surf_idx" type="int"> </argument> <description> - Return the primitive type of the requested surface (see [method add_surface_from_arrays]). + Returns the primitive type of the requested surface (see [method add_surface_from_arrays]). </description> </method> <method name="surface_remove"> diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml index 7bd346ed5a..6d1a7a8f87 100644 --- a/doc/classes/BaseButton.xml +++ b/doc/classes/BaseButton.xml @@ -29,14 +29,14 @@ <return type="int" enum="BaseButton.DrawMode"> </return> <description> - Return the visual state used to draw the button. This is useful mainly when implementing your own draw code by either overriding _draw() or connecting to "draw" signal. The visual state of the button is defined by the DRAW_* enum. + Returns the visual state used to draw the button. This is useful mainly when implementing your own draw code by either overriding _draw() or connecting to "draw" signal. The visual state of the button is defined by the DRAW_* enum. </description> </method> <method name="is_hovered" qualifiers="const"> <return type="bool"> </return> <description> - Return [code]true[/code] if the mouse has entered the button and has not left it yet. + Returns [code]true[/code] if the mouse has entered the button and has not left it yet. </description> </method> </methods> diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index cee3035eab..ae7a3ff323 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -57,7 +57,7 @@ <return type="float"> </return> <description> - Return the determinant of the matrix. + Returns the determinant of the matrix. </description> </method> <method name="get_euler"> @@ -91,7 +91,7 @@ <return type="Basis"> </return> <description> - Return the inverse of the matrix. + Returns the inverse of the matrix. </description> </method> <method name="is_equal_approx"> @@ -108,7 +108,7 @@ <return type="Basis"> </return> <description> - Return the orthonormalized version of the matrix (useful to call from time to time to avoid rounding error for orthogonal matrices). This performs a Gram-Schmidt orthonormalization on the basis of the matrix. + Returns the orthonormalized version of the matrix (useful to call from time to time to avoid rounding error for orthogonal matrices). This performs a Gram-Schmidt orthonormalization on the basis of the matrix. </description> </method> <method name="rotated"> @@ -173,7 +173,7 @@ <return type="Basis"> </return> <description> - Return the transposed version of the matrix. + Returns the transposed version of the matrix. </description> </method> <method name="xform"> @@ -182,7 +182,7 @@ <argument index="0" name="v" type="Vector3"> </argument> <description> - Return a vector transformed (multiplied) by the matrix. + Returns a vector transformed (multiplied) by the matrix. </description> </method> <method name="xform_inv"> @@ -191,7 +191,7 @@ <argument index="0" name="v" type="Vector3"> </argument> <description> - Return a vector transformed (multiplied) by the transposed matrix. Note that this results in a multiplication by the inverse of the matrix only if it represents a rotation-reflection. + Returns a vector transformed (multiplied) by the transposed matrix. Note that this results in a multiplication by the inverse of the matrix only if it represents a rotation-reflection. </description> </method> </methods> diff --git a/doc/classes/Camera.xml b/doc/classes/Camera.xml index 05858e8bc6..cc869d28a2 100644 --- a/doc/classes/Camera.xml +++ b/doc/classes/Camera.xml @@ -18,6 +18,13 @@ If this is the current Camera, remove it from being current. If [code]enable_next[/code] is [code]true[/code], request to make the next Camera current, if any. </description> </method> + <method name="get_camera_rid" qualifiers="const"> + <return type="RID"> + </return> + <description> + Returns the camera's RID from the [VisualServer]. + </description> + </method> <method name="get_camera_transform" qualifiers="const"> <return type="Transform"> </return> @@ -69,8 +76,10 @@ </return> <argument index="0" name="screen_point" type="Vector2"> </argument> + <argument index="1" name="z_depth" type="float" default="0"> + </argument> <description> - Returns the 3D point in worldspace that maps to the given 2D coordinate in the [Viewport] rectangle. + Returns the 3D point in worldspace that maps to the given 2D coordinate in the [Viewport] rectangle on a plane that is the given distance into the scene away from the camera. </description> </method> <method name="project_ray_normal" qualifiers="const"> diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml index e5d1649c29..fcc99123d2 100644 --- a/doc/classes/Camera2D.xml +++ b/doc/classes/Camera2D.xml @@ -35,7 +35,7 @@ <return type="Vector2"> </return> <description> - Return the camera position. + Returns the camera position. </description> </method> <method name="get_camera_screen_center" qualifiers="const"> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 8ba3990933..2426471a49 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -342,14 +342,14 @@ <return type="RID"> </return> <description> - Return the [RID] of the [World2D] canvas where this item is in. + Returns the [RID] of the [World2D] canvas where this item is in. </description> </method> <method name="get_canvas_item" qualifiers="const"> <return type="RID"> </return> <description> - Return the canvas item RID used by [VisualServer] for this item. + Returns the canvas item RID used by [VisualServer] for this item. </description> </method> <method name="get_canvas_transform" qualifiers="const"> diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml index b029c85409..ddbe66380a 100644 --- a/doc/classes/ClassDB.xml +++ b/doc/classes/ClassDB.xml @@ -121,7 +121,7 @@ <argument index="1" name="name" type="String"> </argument> <description> - Return whether 'class' or its ancestry has an integer constant called 'name' or not. + Returns whether 'class' or its ancestry has an integer constant called 'name' or not. </description> </method> <method name="class_has_method" qualifiers="const"> @@ -134,7 +134,7 @@ <argument index="2" name="no_inheritance" type="bool" default="false"> </argument> <description> - Return whether 'class' (or its ancestry if 'no_inheritance' is false) has a method called 'method' or not. + Returns whether 'class' (or its ancestry if 'no_inheritance' is false) has a method called 'method' or not. </description> </method> <method name="class_has_signal" qualifiers="const"> @@ -145,7 +145,7 @@ <argument index="1" name="signal" type="String"> </argument> <description> - Return whether 'class' or its ancestry has a signal called 'signal' or not. + Returns whether 'class' or its ancestry has a signal called 'signal' or not. </description> </method> <method name="class_set_property" qualifiers="const"> diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index 9f48f6e018..ab5d7a0a5d 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -566,6 +566,8 @@ </constant> <constant name="tomato" value="Color( 1, 0.39, 0.28, 1 )"> </constant> + <constant name="transparent" value="Color( 1, 1, 1, 0 )"> + </constant> <constant name="turquoise" value="Color( 0.25, 0.88, 0.82, 1 )"> </constant> <constant name="violet" value="Color( 0.93, 0.51, 0.93, 1 )"> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index a58edb5ca8..32e6014c75 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -31,7 +31,7 @@ <return type="PoolColorArray"> </return> <description> - Return the list of colors in the presets of the color picker. + Returns the list of colors in the presets of the color picker. </description> </method> </methods> diff --git a/doc/classes/ConcavePolygonShape.xml b/doc/classes/ConcavePolygonShape.xml index afc6ce74a5..62d42f4eb4 100644 --- a/doc/classes/ConcavePolygonShape.xml +++ b/doc/classes/ConcavePolygonShape.xml @@ -13,7 +13,7 @@ <return type="PoolVector3Array"> </return> <description> - Return the faces (an array of triangles). + Returns the faces (an array of triangles). </description> </method> <method name="set_faces"> diff --git a/doc/classes/ConfirmationDialog.xml b/doc/classes/ConfirmationDialog.xml index f39915f4b7..6124bc29b0 100644 --- a/doc/classes/ConfirmationDialog.xml +++ b/doc/classes/ConfirmationDialog.xml @@ -13,7 +13,7 @@ <return type="Button"> </return> <description> - Return the cancel button. + Returns the cancel button. </description> </method> </methods> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index f888e1ee09..22061322c8 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -221,7 +221,7 @@ <argument index="0" name="position" type="Vector2"> </argument> <description> - Godot calls this method to get data that can be dragged and dropped onto controls that expect drop data. Return null if there is no data to drag. Controls that want to receive drop data should implement [method can_drop_data] and [method drop_data]. [code]position[/code] is local to this control. Drag may be forced with [method force_drag]. + Godot calls this method to get data that can be dragged and dropped onto controls that expect drop data. Returns null if there is no data to drag. Controls that want to receive drop data should implement [method can_drop_data] and [method drop_data]. [code]position[/code] is local to this control. Drag may be forced with [method force_drag]. A preview that will follow the mouse that should represent the data can be set with [method set_drag_preview]. A good time to set the preview is in this method. [codeblock] extends Control diff --git a/doc/classes/CubeMesh.xml b/doc/classes/CubeMesh.xml index 814c2f21c1..6162474ed1 100644 --- a/doc/classes/CubeMesh.xml +++ b/doc/classes/CubeMesh.xml @@ -5,6 +5,7 @@ </brief_description> <description> Generate an axis-aligned cuboid [PrimitiveMesh]. + The cube's UV layout is arranged in a 3×2 layout that allows texturing each face individually. To apply the same texture on all faces, change the material's UV property to [code]Vector3(3, 2, 1)[/code]. </description> <tutorials> </tutorials> diff --git a/doc/classes/CylinderMesh.xml b/doc/classes/CylinderMesh.xml index fa0a3bf412..dbdc7aeb92 100644 --- a/doc/classes/CylinderMesh.xml +++ b/doc/classes/CylinderMesh.xml @@ -4,7 +4,7 @@ Class representing a cylindrical [PrimitiveMesh]. </brief_description> <description> - Class representing a cylindrical [PrimitiveMesh]. + Class representing a cylindrical [PrimitiveMesh]. This class can be used to create cones by setting either the [member top_radius] or [member bottom_radius] properties to 0.0. </description> <tutorials> </tutorials> diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml index b6b17d03fb..ec70fd311b 100644 --- a/doc/classes/Dictionary.xml +++ b/doc/classes/Dictionary.xml @@ -38,7 +38,7 @@ <return type="bool"> </return> <description> - Return [code]true[/code] if the dictionary is empty. + Returns [code]true[/code] if the dictionary is empty. </description> </method> <method name="erase"> @@ -67,7 +67,7 @@ <argument index="0" name="key" type="Variant"> </argument> <description> - Return [code]true[/code] if the dictionary has a given key. + Returns [code]true[/code] if the dictionary has a given key. </description> </method> <method name="has_all"> @@ -76,35 +76,35 @@ <argument index="0" name="keys" type="Array"> </argument> <description> - Return [code]true[/code] if the dictionary has all of the keys in the given array. + Returns [code]true[/code] if the dictionary has all of the keys in the given array. </description> </method> <method name="hash"> <return type="int"> </return> <description> - Return a hashed integer value representing the dictionary contents. + Returns a hashed integer value representing the dictionary contents. </description> </method> <method name="keys"> <return type="Array"> </return> <description> - Return the list of keys in the [Dictionary]. + Returns the list of keys in the [Dictionary]. </description> </method> <method name="size"> <return type="int"> </return> <description> - Return the size of the dictionary (in pairs). + Returns the size of the dictionary (in pairs). </description> </method> <method name="values"> <return type="Array"> </return> <description> - Return the list of values in the [Dictionary]. + Returns the list of values in the [Dictionary]. </description> </method> </methods> diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml index 8a81695198..54aac33652 100644 --- a/doc/classes/Directory.xml +++ b/doc/classes/Directory.xml @@ -52,7 +52,7 @@ <return type="bool"> </return> <description> - Return whether the current item processed with the last [method get_next] call is a directory ([code].[/code] and [code]..[/code] are considered directories). + Returns whether the current item processed with the last [method get_next] call is a directory ([code].[/code] and [code]..[/code] are considered directories). </description> </method> <method name="dir_exists"> @@ -61,7 +61,7 @@ <argument index="0" name="path" type="String"> </argument> <description> - Return whether the target directory exists. The argument can be relative to the current directory, or an absolute path. + Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path. </description> </method> <method name="file_exists"> @@ -70,14 +70,14 @@ <argument index="0" name="path" type="String"> </argument> <description> - Return whether the target file exists. The argument can be relative to the current directory, or an absolute path. + Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path. </description> </method> <method name="get_current_dir"> <return type="String"> </return> <description> - Return the absolute path to the currently opened directory (e.g. [code]res://folder[/code] or [code]C:\tmp\folder[/code]). + Returns the absolute path to the currently opened directory (e.g. [code]res://folder[/code] or [code]C:\tmp\folder[/code]). </description> </method> <method name="get_current_drive"> @@ -107,7 +107,7 @@ <return type="String"> </return> <description> - Return the next element (file or directory) in the current directory (including [code].[/code] and [code]..[/code], unless [code]skip_navigational[/code] was given to [method list_dir_begin]). + Returns the next element (file or directory) in the current directory (including [code].[/code] and [code]..[/code], unless [code]skip_navigational[/code] was given to [method list_dir_begin]). The name of the file or directory is returned (and not its full path). Once the stream has been fully processed, the method returns an empty String and closes the stream automatically (i.e. [method list_dir_end] would not be mandatory in such a case). </description> </method> @@ -155,7 +155,7 @@ </argument> <description> Create a target directory and all necessary intermediate directories in its path, by calling [method make_dir] recursively. The argument can be relative to the current directory, or an absolute path. - Return one of the error code constants defined in [@GlobalScope] (OK, FAILED or ERR_*). + Returns one of the error code constants defined in [@GlobalScope] (OK, FAILED or ERR_*). </description> </method> <method name="open"> @@ -175,7 +175,7 @@ </argument> <description> Delete the target file or an empty directory. The argument can be relative to the current directory, or an absolute path. If the target directory is not empty, the operation will fail. - Return one of the error code constants defined in [@GlobalScope] (OK or FAILED). + Returns one of the error code constants defined in [@GlobalScope] (OK or FAILED). </description> </method> <method name="rename"> @@ -187,7 +187,7 @@ </argument> <description> Rename (move) the [i]from[/i] file to the [i]to[/i] destination. Both arguments should be paths to files, either relative or absolute. If the destination file exists and is not access-protected, it will be overwritten. - Return one of the error code constants defined in [@GlobalScope] (OK or FAILED). + Returns one of the error code constants defined in [@GlobalScope] (OK or FAILED). </description> </method> </methods> diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml index 998b05d495..4e4e29dc4e 100644 --- a/doc/classes/EditorExportPlugin.xml +++ b/doc/classes/EditorExportPlugin.xml @@ -21,6 +21,12 @@ <description> </description> </method> + <method name="_export_end" qualifiers="virtual"> + <return type="void"> + </return> + <description> + </description> + </method> <method name="_export_file" qualifiers="virtual"> <return type="void"> </return> diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml index 531af4c4e0..1c7a68fc0b 100644 --- a/doc/classes/EditorFileSystem.xml +++ b/doc/classes/EditorFileSystem.xml @@ -38,14 +38,14 @@ <return type="float"> </return> <description> - Return the scan progress for 0 to 1 if the FS is being scanned. + Returns the scan progress for 0 to 1 if the FS is being scanned. </description> </method> <method name="is_scanning" qualifiers="const"> <return type="bool"> </return> <description> - Return [code]true[/code] of the filesystem is being scanned. + Returns [code]true[/code] of the filesystem is being scanned. </description> </method> <method name="scan"> diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml index da23218bdc..c2b13ff89e 100644 --- a/doc/classes/EditorInspectorPlugin.xml +++ b/doc/classes/EditorInspectorPlugin.xml @@ -54,7 +54,7 @@ <argument index="0" name="object" type="Object"> </argument> <description> - Return true if this object can be handled by this plugin. + Returns true if this object can be handled by this plugin. </description> </method> <method name="parse_begin" qualifiers="virtual"> diff --git a/doc/classes/EditorNavigationMeshGenerator.xml b/doc/classes/EditorNavigationMeshGenerator.xml new file mode 100644 index 0000000000..3956e12509 --- /dev/null +++ b/doc/classes/EditorNavigationMeshGenerator.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorNavigationMeshGenerator" inherits="Object" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="bake"> + <return type="void"> + </return> + <argument index="0" name="nav_mesh" type="NavigationMesh"> + </argument> + <argument index="1" name="root_node" type="Node"> + </argument> + <description> + </description> + </method> + <method name="clear"> + <return type="void"> + </return> + <argument index="0" name="nav_mesh" type="NavigationMesh"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 5763d26561..97ad4f6829 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -241,7 +241,7 @@ <return type="EditorInterface"> </return> <description> - Return the [EditorInterface] object that gives you control over Godot editor's window and its functionalities. + Returns the [EditorInterface] object that gives you control over Godot editor's window and its functionalities. </description> </method> <method name="get_plugin_icon" qualifiers="virtual"> @@ -299,7 +299,7 @@ <return type="bool"> </return> <description> - Return [code]true[/code] if this is a main screen editor plugin (it goes in the workspaces selector together with '2D', '3D', and 'Script'). + Returns [code]true[/code] if this is a main screen editor plugin (it goes in the workspaces selector together with '2D', '3D', and 'Script'). </description> </method> <method name="hide_bottom_panel"> diff --git a/doc/classes/EditorResourcePreviewGenerator.xml b/doc/classes/EditorResourcePreviewGenerator.xml index 6592ffd1a8..156cc62941 100644 --- a/doc/classes/EditorResourcePreviewGenerator.xml +++ b/doc/classes/EditorResourcePreviewGenerator.xml @@ -9,6 +9,14 @@ <tutorials> </tutorials> <methods> + <method name="can_generate_small_preview" qualifiers="virtual"> + <return type="bool"> + </return> + <description> + If this function returns true the generator will call [method generate] or [method generate_from_path] for small previews too. + By default it returns false. + </description> + </method> <method name="generate" qualifiers="virtual"> <return type="Texture"> </return> @@ -35,13 +43,21 @@ Care must be taken because this function is always called from a thread (not the main thread). </description> </method> + <method name="generate_small_preview_automatically" qualifiers="virtual"> + <return type="bool"> + </return> + <description> + If this function returns true the generator will automatically generate the small previews from the normal preview texture generated by the methods [method generate] or [method generate_from_path]. + By default it returns false. + </description> + </method> <method name="handles" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="type" type="String"> </argument> <description> - Return if your generator supports this resource type. + Returns if your generator supports this resource type. </description> </method> </methods> diff --git a/doc/classes/EditorSpatialGizmo.xml b/doc/classes/EditorSpatialGizmo.xml index da7fee1cf7..5d5c37b212 100644 --- a/doc/classes/EditorSpatialGizmo.xml +++ b/doc/classes/EditorSpatialGizmo.xml @@ -123,7 +123,7 @@ <return type="EditorSpatialGizmoPlugin"> </return> <description> - Return the [EditorSpatialGizmoPlugin] that owns this gizmo. It's useful to retrieve materials using [method EditorSpatialGizmoPlugin.get_material]. + Returns the [EditorSpatialGizmoPlugin] that owns this gizmo. It's useful to retrieve materials using [method EditorSpatialGizmoPlugin.get_material]. </description> </method> <method name="get_spatial_node" qualifiers="const"> diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index 66e6fa5314..953f364bdb 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -43,7 +43,7 @@ <return type="VBoxContainer"> </return> <description> - Return the vertical box container of the dialog, custom controls can be added to it. + Returns the vertical box container of the dialog, custom controls can be added to it. </description> </method> <method name="invalidate"> diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml index 5792b539e0..d65dad9fe1 100644 --- a/doc/classes/Font.xml +++ b/doc/classes/Font.xml @@ -51,21 +51,21 @@ <return type="float"> </return> <description> - Return the font ascent (number of pixels above the baseline). + Returns the font ascent (number of pixels above the baseline). </description> </method> <method name="get_descent" qualifiers="const"> <return type="float"> </return> <description> - Return the font descent (number of pixels below the baseline). + Returns the font descent (number of pixels below the baseline). </description> </method> <method name="get_height" qualifiers="const"> <return type="float"> </return> <description> - Return the total font height (ascent plus descent) in pixels. + Returns the total font height (ascent plus descent) in pixels. </description> </method> <method name="get_string_size" qualifiers="const"> @@ -74,7 +74,7 @@ <argument index="0" name="string" type="String"> </argument> <description> - Return the size of a string, taking kerning and advance into account. + Returns the size of a string, taking kerning and advance into account. </description> </method> <method name="get_wordwrap_string_size" qualifiers="const"> diff --git a/doc/classes/Geometry.xml b/doc/classes/Geometry.xml index 68539d7ecb..e2ba3fb7b0 100644 --- a/doc/classes/Geometry.xml +++ b/doc/classes/Geometry.xml @@ -59,6 +59,29 @@ Clips the polygon defined by the points in [code]points[/code] against the [code]plane[/code] and returns the points of the clipped polygon. </description> </method> + <method name="clip_polygons_2d"> + <return type="Array"> + </return> + <argument index="0" name="polygon_a" type="PoolVector2Array"> + </argument> + <argument index="1" name="polygon_b" type="PoolVector2Array"> + </argument> + <description> + Clips [code]polygon_a[/code] against [code]polygon_b[/code] and returns an array of clipped polygons. This performs [code]OPERATION_DIFFERENCE[/code] between polygons. Returns an empty array if [code]polygon_b[/code] completely overlaps [code]polygon_a[/code]. + If [code]polygon_b[/code] is enclosed by [code]polygon_a[/code], returns an outer polygon (boundary) and inner polygon (hole) which could be distiguished by calling [method is_polygon_clockwise]. + </description> + </method> + <method name="clip_polyline_with_polygon_2d"> + <return type="Array"> + </return> + <argument index="0" name="polyline" type="PoolVector2Array"> + </argument> + <argument index="1" name="polygon" type="PoolVector2Array"> + </argument> + <description> + Clips [code]polyline[/code] against [code]polygon[/code] and returns an array of clipped polylines. This performs [code]OPERATION_DIFFERENCE[/code] between the polyline and the polygon. This operation can be thought of as cutting a line with a closed shape. + </description> + </method> <method name="convex_hull_2d"> <return type="PoolVector2Array"> </return> @@ -68,6 +91,18 @@ Given an array of [Vector2]s, returns the convex hull as a list of points in counter-clockwise order. The last point is the same as the first one. </description> </method> + <method name="exclude_polygons_2d"> + <return type="Array"> + </return> + <argument index="0" name="polygon_a" type="PoolVector2Array"> + </argument> + <argument index="1" name="polygon_b" type="PoolVector2Array"> + </argument> + <description> + Mutually excludes common area defined by intersection of [code]polygon_a[/code] and [code]polygon_b[/code] (see [method intersect_polygons_2d]) and returns an array of excluded polygons. This performs [code]OPERATION_XOR[/code] between polygons. In other words, returns all but common area between polygons. + The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distiguished by calling [method is_polygon_clockwise]. + </description> + </method> <method name="get_closest_point_to_segment"> <return type="Vector3"> </return> @@ -158,6 +193,38 @@ <description> </description> </method> + <method name="intersect_polygons_2d"> + <return type="Array"> + </return> + <argument index="0" name="polygon_a" type="PoolVector2Array"> + </argument> + <argument index="1" name="polygon_b" type="PoolVector2Array"> + </argument> + <description> + Intersects [code]polygon_a[/code] with [code]polygon_b[/code] and returns an array of intersected polygons. This performs [code]OPERATION_INTERSECTION[/code] between polygons. In other words, returns common area shared by polygons. Returns an empty array if no intersection occurs. + The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distiguished by calling [method is_polygon_clockwise]. + </description> + </method> + <method name="intersect_polyline_with_polygon_2d"> + <return type="Array"> + </return> + <argument index="0" name="polyline" type="PoolVector2Array"> + </argument> + <argument index="1" name="polygon" type="PoolVector2Array"> + </argument> + <description> + Intersects [code]polyline[/code] with [code]polygon[/code] and returns an array of intersected polylines. This performs [code]OPERATION_INTERSECTION[/code] between the polyline and the polygon. This operation can be thought of as chopping a line with a closed shape. + </description> + </method> + <method name="is_polygon_clockwise"> + <return type="bool"> + </return> + <argument index="0" name="polygon" type="PoolVector2Array"> + </argument> + <description> + Returns [code]true[/code] if [code]polygon[/code]'s vertices are ordered in clockwise order, otherwise returns [code]false[/code]. + </description> + </method> <method name="line_intersects_line_2d"> <return type="Variant"> </return> @@ -182,6 +249,51 @@ Given an array of [Vector2]s representing tiles, builds an atlas. The returned dictionary has two keys: [code]points[/code] is a vector of [Vector2] that specifies the positions of each tile, [code]size[/code] contains the overall size of the whole atlas as [Vector2]. </description> </method> + <method name="merge_polygons_2d"> + <return type="Array"> + </return> + <argument index="0" name="polygon_a" type="PoolVector2Array"> + </argument> + <argument index="1" name="polygon_b" type="PoolVector2Array"> + </argument> + <description> + Merges (combines) [code]polygon_a[/code] and [code]polygon_b[/code] and returns an array of merged polygons. This performs [code]OPERATION_UNION[/code] between polygons. + The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distiguished by calling [method is_polygon_clockwise]. + </description> + </method> + <method name="offset_polygon_2d"> + <return type="Array"> + </return> + <argument index="0" name="polygon" type="PoolVector2Array"> + </argument> + <argument index="1" name="delta" type="float"> + </argument> + <argument index="2" name="join_type" type="int" enum="Geometry.PolyJoinType" default="0"> + </argument> + <description> + Inflates or deflates [code]polygon[/code] by [code]delta[/code] units (pixels). If [code]delta[/code] is positive, makes the polygon grow outward. If [code]delta[/code] is negative, shrinks the polygon inward. Returns an array of polygons because inflating/deflating may result in multiple discrete polygons. Returns an empty array if [code]delta[/code] is negative and the absolute value of it approximately exceeds the minimum bounding rectangle dimensions of the polygon. + Each polygon's vertices will be rounded as determined by [code]join_type[/code], see [enum Geometry.PolyJoinType]. + The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distiguished by calling [method is_polygon_clockwise]. + </description> + </method> + <method name="offset_polyline_2d"> + <return type="Array"> + </return> + <argument index="0" name="polyline" type="PoolVector2Array"> + </argument> + <argument index="1" name="delta" type="float"> + </argument> + <argument index="2" name="join_type" type="int" enum="Geometry.PolyJoinType" default="0"> + </argument> + <argument index="3" name="end_type" type="int" enum="Geometry.PolyEndType" default="3"> + </argument> + <description> + Inflates or deflates [code]polyline[/code] by [code]delta[/code] units (pixels), producing polygons. If [code]delta[/code] is positive, makes the polyline grow outward. Returns an array of polygons because inflating/deflating may result in multiple discrete polygons. If [code]delta[/code] is negative, returns an empty array. + Each polygon's vertices will be rounded as determined by [code]join_type[/code], see [enum Geometry.PolyJoinType]. + Each polygon's endpoints will be rounded as determined by [code]end_type[/code], see [enum Geometry.PolyEndType]. + The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distiguished by calling [method is_polygon_clockwise]. + </description> + </method> <method name="point_is_inside_triangle" qualifiers="const"> <return type="bool"> </return> @@ -304,6 +416,27 @@ Tests if the segment ([code]from[/code], [code]to[/code]) intersects the triangle [code]a[/code], [code]b[/code], [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, an empty [Variant] is returned. </description> </method> + <method name="transform_points_2d"> + <return type="PoolVector2Array"> + </return> + <argument index="0" name="points" type="PoolVector2Array"> + </argument> + <argument index="1" name="transform" type="Transform2D"> + </argument> + <description> + Transforms an array of points by [code]transform[/code] and returns the result. + Can be useful in conjuction with performing polygon boolean operations in CSG manner, see [method merge_polygons_2d], [method clip_polygons_2d], [method intersect_polygons_2d], [method exclude_polygons_2d]. + </description> + </method> + <method name="triangulate_delaunay_2d"> + <return type="PoolIntArray"> + </return> + <argument index="0" name="points" type="PoolVector2Array"> + </argument> + <description> + Triangulates the area specified by discrete set of [code]points[/code] such that no point is inside the circumcircle of any resulting triangle. Returns a [PoolIntArray] where each triangle consists of three consecutive point indices into [code]points[/code] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). If the triangulation did not succeed, an empty [PoolIntArray] is returned. + </description> + </method> <method name="triangulate_polygon"> <return type="PoolIntArray"> </return> @@ -315,5 +448,41 @@ </method> </methods> <constants> + <constant name="OPERATION_UNION" value="0" enum="PolyBooleanOperation"> + Create regions where either subject or clip polygons (or both) are filled. + </constant> + <constant name="OPERATION_DIFFERENCE" value="1" enum="PolyBooleanOperation"> + Create regions where subject polygons are filled except where clip polygons are filled. + </constant> + <constant name="OPERATION_INTERSECTION" value="2" enum="PolyBooleanOperation"> + Create regions where both subject and clip polygons are filled. + </constant> + <constant name="OPERATION_XOR" value="3" enum="PolyBooleanOperation"> + Create regions where either subject or clip polygons are filled but not where both are filled. + </constant> + <constant name="JOIN_SQUARE" value="0" enum="PolyJoinType"> + Squaring is applied uniformally at all convex edge joins at [code]1 * delta[/code]. + </constant> + <constant name="JOIN_ROUND" value="1" enum="PolyJoinType"> + While flattened paths can never perfectly trace an arc, they are approximated by a series of arc chords. + </constant> + <constant name="JOIN_MITER" value="2" enum="PolyJoinType"> + There's a necessary limit to mitered joins since offsetting edges that join at very acute angles will produce excessively long and narrow 'spikes'. For any given edge join, when miter offsetting would exceed that maximum distance, 'square' joining is applied. + </constant> + <constant name="END_POLYGON" value="0" enum="PolyEndType"> + Endpoints are joined using the [enum PolyJoinType] value and the path filled as a polygon. + </constant> + <constant name="END_JOINED" value="1" enum="PolyEndType"> + Endpoints are joined using the [enum PolyJoinType] value and the path filled as a polyline. + </constant> + <constant name="END_BUTT" value="2" enum="PolyEndType"> + Endpoints are squared off with no extension. + </constant> + <constant name="END_SQUARE" value="3" enum="PolyEndType"> + Endpoints are squared off and extended by [code]delta[/code] units. + </constant> + <constant name="END_ROUND" value="4" enum="PolyEndType"> + Endpoints are rounded off and extended by [code]delta[/code] units. + </constant> </constants> </class> diff --git a/doc/classes/GeometryInstance.xml b/doc/classes/GeometryInstance.xml index 6a89d81aa0..674f786149 100644 --- a/doc/classes/GeometryInstance.xml +++ b/doc/classes/GeometryInstance.xml @@ -9,6 +9,15 @@ <tutorials> </tutorials> <methods> + <method name="set_custom_aabb"> + <return type="void"> + </return> + <argument index="0" name="aabb" type="AABB"> + </argument> + <description> + Overrides the bounding box of this node with a custom one. To remove it, set an AABB with all fields set to zero. + </description> + </method> </methods> <members> <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" enum="GeometryInstance.ShadowCastingSetting"> diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 145cd243bc..db186eab35 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -80,7 +80,7 @@ <return type="Array"> </return> <description> - Return an Array containing the list of connections. A connection consists in a structure of the form {from_port: 0, from: "GraphNode name 0", to_port: 1, to: "GraphNode name 1" } + Returns an Array containing the list of connections. A connection consists in a structure of the form {from_port: 0, from: "GraphNode name 0", to_port: 1, to: "GraphNode name 1" } </description> </method> <method name="get_zoom_hbox"> @@ -101,7 +101,7 @@ <argument index="3" name="to_port" type="int"> </argument> <description> - Return [code]true[/code] if the 'from_port' slot of 'from' GraphNode is connected to the 'to_port' slot of 'to' GraphNode. + Returns [code]true[/code] if the 'from_port' slot of 'from' GraphNode is connected to the 'to_port' slot of 'to' GraphNode. </description> </method> <method name="is_valid_connection_type" qualifiers="const"> diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml index 4d6f3180d0..a19676798b 100644 --- a/doc/classes/GraphNode.xml +++ b/doc/classes/GraphNode.xml @@ -31,14 +31,14 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the color of the input connection 'idx'. + Returns the color of the input connection 'idx'. </description> </method> <method name="get_connection_input_count"> <return type="int"> </return> <description> - Return the number of enabled input slots (connections) to the GraphNode. + Returns the number of enabled input slots (connections) to the GraphNode. </description> </method> <method name="get_connection_input_position"> @@ -47,7 +47,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the position of the input connection 'idx'. + Returns the position of the input connection 'idx'. </description> </method> <method name="get_connection_input_type"> @@ -56,7 +56,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the type of the input connection 'idx'. + Returns the type of the input connection 'idx'. </description> </method> <method name="get_connection_output_color"> @@ -65,14 +65,14 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the color of the output connection 'idx'. + Returns the color of the output connection 'idx'. </description> </method> <method name="get_connection_output_count"> <return type="int"> </return> <description> - Return the number of enabled output slots (connections) of the GraphNode. + Returns the number of enabled output slots (connections) of the GraphNode. </description> </method> <method name="get_connection_output_position"> @@ -81,7 +81,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the position of the output connection 'idx'. + Returns the position of the output connection 'idx'. </description> </method> <method name="get_connection_output_type"> @@ -90,7 +90,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the type of the output connection 'idx'. + Returns the type of the output connection 'idx'. </description> </method> <method name="get_slot_color_left" qualifiers="const"> @@ -99,7 +99,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the color set to 'idx' left (input) slot. + Returns the color set to 'idx' left (input) slot. </description> </method> <method name="get_slot_color_right" qualifiers="const"> @@ -108,7 +108,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the color set to 'idx' right (output) slot. + Returns the color set to 'idx' right (output) slot. </description> </method> <method name="get_slot_type_left" qualifiers="const"> @@ -117,7 +117,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the (integer) type of left (input) 'idx' slot. + Returns the (integer) type of left (input) 'idx' slot. </description> </method> <method name="get_slot_type_right" qualifiers="const"> @@ -126,7 +126,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the (integer) type of right (output) 'idx' slot. + Returns the (integer) type of right (output) 'idx' slot. </description> </method> <method name="is_slot_enabled_left" qualifiers="const"> @@ -135,7 +135,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return [code]true[/code] if left (input) slot 'idx' is enabled, [code]false[/code] otherwise. + Returns [code]true[/code] if left (input) slot 'idx' is enabled, [code]false[/code] otherwise. </description> </method> <method name="is_slot_enabled_right" qualifiers="const"> @@ -144,7 +144,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return [code]true[/code] if right (output) slot 'idx' is enabled, [code]false[/code] otherwise. + Returns [code]true[/code] if right (output) slot 'idx' is enabled, [code]false[/code] otherwise. </description> </method> <method name="set_slot"> diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml index 15ecd4ee6d..e5a8fee767 100644 --- a/doc/classes/ImageTexture.xml +++ b/doc/classes/ImageTexture.xml @@ -40,7 +40,7 @@ <return type="int" enum="Image.Format"> </return> <description> - Return the format of the [ImageTexture], one of [enum Image.Format]. + Returns the format of the [ImageTexture], one of [enum Image.Format]. </description> </method> <method name="load"> diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index 319f84b8d2..9c41e4bf1d 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -194,7 +194,7 @@ <return type="int" enum="Input.MouseMode"> </return> <description> - Return the mouse mode. See the constants for more information. + Returns the mouse mode. See the constants for more information. </description> </method> <method name="is_action_just_pressed" qualifiers="const"> diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml index 663eeda77a..ba3a7fe6d8 100644 --- a/doc/classes/ItemList.xml +++ b/doc/classes/ItemList.xml @@ -64,7 +64,7 @@ <return type="int"> </return> <description> - Return count of items currently in the item list. + Returns count of items currently in the item list. </description> </method> <method name="get_item_custom_bg_color" qualifiers="const"> @@ -122,7 +122,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the text for specified item index. + Returns the text for specified item index. </description> </method> <method name="get_item_tooltip" qualifiers="const"> @@ -131,7 +131,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return tooltip hint for specified item index. + Returns tooltip hint for specified item index. </description> </method> <method name="get_selected_items"> diff --git a/doc/classes/Marshalls.xml b/doc/classes/Marshalls.xml index 0d07d8b649..c7118a4d9f 100644 --- a/doc/classes/Marshalls.xml +++ b/doc/classes/Marshalls.xml @@ -15,7 +15,7 @@ <argument index="0" name="base64_str" type="String"> </argument> <description> - Return [PoolByteArray] of a given base64 encoded String. + Returns [PoolByteArray] of a given base64 encoded String. </description> </method> <method name="base64_to_utf8"> @@ -24,7 +24,7 @@ <argument index="0" name="base64_str" type="String"> </argument> <description> - Return utf8 String of a given base64 encoded String. + Returns utf8 String of a given base64 encoded String. </description> </method> <method name="base64_to_variant"> @@ -35,7 +35,7 @@ <argument index="1" name="allow_objects" type="bool" default="false"> </argument> <description> - Return [Variant] of a given base64 encoded String. When [code]allow_objects[/code] is [code]true[/code] decoding objects is allowed. + Returns [Variant] of a given base64 encoded String. When [code]allow_objects[/code] is [code]true[/code] decoding objects is allowed. [b]WARNING:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution). </description> </method> @@ -45,7 +45,7 @@ <argument index="0" name="array" type="PoolByteArray"> </argument> <description> - Return base64 encoded String of a given [PoolByteArray]. + Returns base64 encoded String of a given [PoolByteArray]. </description> </method> <method name="utf8_to_base64"> @@ -54,7 +54,7 @@ <argument index="0" name="utf8_str" type="String"> </argument> <description> - Return base64 encoded String of a given utf8 String. + Returns base64 encoded String of a given utf8 String. </description> </method> <method name="variant_to_base64"> @@ -65,7 +65,7 @@ <argument index="1" name="full_objects" type="bool" default="false"> </argument> <description> - Return base64 encoded String of a given [Variant]. When [code]full_objects[/code] is [code]true[/code] encoding objects is allowed (and can potentially include code). + Returns base64 encoded String of a given [Variant]. When [code]full_objects[/code] is [code]true[/code] encoding objects is allowed (and can potentially include code). </description> </method> </methods> diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml index dadc31b794..1043aa1087 100644 --- a/doc/classes/MenuButton.xml +++ b/doc/classes/MenuButton.xml @@ -13,7 +13,7 @@ <return type="PopupMenu"> </return> <description> - Return the [PopupMenu] contained in this button. + Returns the [PopupMenu] contained in this button. </description> </method> <method name="set_disable_shortcuts"> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index ae035341f6..b8bc5cbd11 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -50,7 +50,7 @@ <return type="int"> </return> <description> - Return the amount of surfaces that the [Mesh] holds. + Returns the amount of surfaces that the [Mesh] holds. </description> </method> <method name="surface_get_arrays" qualifiers="const"> @@ -77,7 +77,7 @@ <argument index="0" name="surf_idx" type="int"> </argument> <description> - Return a [Material] in a given surface. Surface is rendered using this material. + Returns a [Material] in a given surface. Surface is rendered using this material. </description> </method> </methods> diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml index de4f6cdf72..ad5824640d 100644 --- a/doc/classes/MeshLibrary.xml +++ b/doc/classes/MeshLibrary.xml @@ -37,7 +37,7 @@ <return type="PoolIntArray"> </return> <description> - Return the list of items. + Returns the list of items. </description> </method> <method name="get_item_mesh" qualifiers="const"> @@ -46,7 +46,7 @@ <argument index="0" name="id" type="int"> </argument> <description> - Return the mesh of the item. + Returns the mesh of the item. </description> </method> <method name="get_item_name" qualifiers="const"> @@ -55,7 +55,7 @@ <argument index="0" name="id" type="int"> </argument> <description> - Return the name of the item. + Returns the name of the item. </description> </method> <method name="get_item_navmesh" qualifiers="const"> diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 1532fac206..0784fc3a42 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -17,7 +17,7 @@ <return type="AABB"> </return> <description> - Return the visibility AABB. + Returns the visibility AABB. </description> </method> <method name="get_instance_color" qualifiers="const"> @@ -35,7 +35,7 @@ <argument index="0" name="instance" type="int"> </argument> <description> - Return the custom data that has been set for a specific instance. + Returns the custom data that has been set for a specific instance. </description> </method> <method name="get_instance_transform" qualifiers="const"> @@ -44,7 +44,7 @@ <argument index="0" name="instance" type="int"> </argument> <description> - Return the [Transform] of a specific instance. + Returns the [Transform] of a specific instance. </description> </method> <method name="get_instance_transform_2d" qualifiers="const"> @@ -53,7 +53,7 @@ <argument index="0" name="instance" type="int"> </argument> <description> - Return the [Transform2D] of a specific instance. + Returns the [Transform2D] of a specific instance. </description> </method> <method name="set_as_bulk_array"> diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml index 2788eb053a..79ad7f63ae 100644 --- a/doc/classes/NavigationMesh.xml +++ b/doc/classes/NavigationMesh.xml @@ -29,6 +29,14 @@ <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_polygon"> <return type="PoolIntArray"> </return> @@ -49,6 +57,16 @@ <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_vertices"> <return type="void"> </return> @@ -85,6 +103,10 @@ </member> <member name="filter/low_hanging_obstacles" type="bool" setter="set_filter_low_hanging_obstacles" getter="get_filter_low_hanging_obstacles"> </member> + <member name="geometry/collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask"> + </member> + <member name="geometry/parsed_geometry_type" type="int" setter="set_parsed_geometry_type" getter="get_parsed_geometry_type"> + </member> <member name="polygon/verts_per_poly" type="float" setter="set_verts_per_poly" getter="get_verts_per_poly"> </member> <member name="region/merge_size" type="float" setter="set_region_merge_size" getter="get_region_merge_size"> @@ -101,5 +123,11 @@ </constant> <constant name="SAMPLE_PARTITION_LAYERS" value="2"> </constant> + <constant name="PARSED_GEOMETRY_MESH_INSTANCES" value="0"> + </constant> + <constant name="PARSED_GEOMETRY_STATIC_COLLIDERS" value="1"> + </constant> + <constant name="PARSED_GEOMETRY_BOTH" value="2"> + </constant> </constants> </class> diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml index 73739ba79a..554858d895 100644 --- a/doc/classes/NodePath.xml +++ b/doc/classes/NodePath.xml @@ -68,14 +68,14 @@ <return type="bool"> </return> <description> - Return [code]true[/code] if the node path is absolute (not relative). + Returns [code]true[/code] if the node path is absolute (not relative). </description> </method> <method name="is_empty"> <return type="bool"> </return> <description> - Return [code]true[/code] if the node path is empty. + Returns [code]true[/code] if the node path is empty. </description> </method> </methods> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index c9c83bc0e0..dd0fcd63e7 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -97,6 +97,8 @@ </argument> <argument index="3" name="output" type="Array" default="[ ]"> </argument> + <argument index="4" name="read_stderr" type="bool" default="false"> + </argument> <description> Execute the file at the given path with the arguments passed as an array of strings. Platform path resolution will take place. The resolved file must exist and be executable. The arguments are used in the given order and separated by a space, so [code]OS.execute('ping', ['-w', '3', 'godotengine.org'], false)[/code] will resolve to [code]ping -w 3 godotengine.org[/code] in the system's shell. @@ -697,7 +699,8 @@ <argument index="0" name="icon" type="Image"> </argument> <description> - Sets the game's icon. + Sets the game's icon using an [Image] resource. + The same image is used for window caption, taskbar/dock and window selection dialog. Image is scaled as needed. </description> </method> <method name="set_ime_active"> @@ -718,6 +721,17 @@ Sets position of IME suggestion list popup (in window coordinates). </description> </method> + <method name="set_native_icon"> + <return type="void"> + </return> + <argument index="0" name="filename" type="String"> + </argument> + <description> + Sets the game's icon using a multi-size platform-specific icon file ([code]*.ico[/code] on Windows and [code]*.icns[/code] on macOS). + Appropriate size sub-icons are used for window caption, taskbar/dock and window selection dialog. + Note: This method is only implemented on macOS and Windows. + </description> + </method> <method name="set_thread_name"> <return type="int" enum="Error"> </return> diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index 06b4cb165e..1f714656de 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -51,7 +51,7 @@ <return type="int"> </return> <description> - Return the amount of items in the OptionButton. + Returns the amount of items in the OptionButton. </description> </method> <method name="get_item_icon" qualifiers="const"> @@ -60,7 +60,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the icon of the item at index "idx". + Returns the icon of the item at index "idx". </description> </method> <method name="get_item_id" qualifiers="const"> @@ -69,7 +69,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the ID of the item at index [code]idx[/code]. + Returns the ID of the item at index [code]idx[/code]. </description> </method> <method name="get_item_index" qualifiers="const"> @@ -78,7 +78,7 @@ <argument index="0" name="id" type="int"> </argument> <description> - Return the index of the item with the given [code]id[/code]. + Returns the index of the item with the given [code]id[/code]. </description> </method> <method name="get_item_metadata" qualifiers="const"> @@ -95,14 +95,14 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the text of the item at index "idx". + Returns the text of the item at index "idx". </description> </method> <method name="get_popup" qualifiers="const"> <return type="PopupMenu"> </return> <description> - Return the [PopupMenu] contained in this button. + Returns the [PopupMenu] contained in this button. </description> </method> <method name="get_selected_id" qualifiers="const"> diff --git a/doc/classes/PacketPeer.xml b/doc/classes/PacketPeer.xml index 5a54c7ba1c..4109d9d462 100644 --- a/doc/classes/PacketPeer.xml +++ b/doc/classes/PacketPeer.xml @@ -13,7 +13,7 @@ <return type="int"> </return> <description> - Return the number of packets currently available in the ring-buffer. + Returns the number of packets currently available in the ring-buffer. </description> </method> <method name="get_packet"> @@ -27,7 +27,7 @@ <return type="int" enum="Error"> </return> <description> - Return the error state of the last packet received (via [method get_packet] and [method get_var]). + Returns the error state of the last packet received (via [method get_packet] and [method get_var]). </description> </method> <method name="get_var"> diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml index 5892eb17b7..9843c16108 100644 --- a/doc/classes/PacketPeerUDP.xml +++ b/doc/classes/PacketPeerUDP.xml @@ -20,21 +20,21 @@ <return type="String"> </return> <description> - Return the IP of the remote peer that sent the last packet(that was received with [method PacketPeer.get_packet] or [method PacketPeer.get_var]). + Returns the IP of the remote peer that sent the last packet(that was received with [method PacketPeer.get_packet] or [method PacketPeer.get_var]). </description> </method> <method name="get_packet_port" qualifiers="const"> <return type="int"> </return> <description> - Return the port of the remote peer that sent the last packet(that was received with [method PacketPeer.get_packet] or [method PacketPeer.get_var]). + Returns the port of the remote peer that sent the last packet(that was received with [method PacketPeer.get_packet] or [method PacketPeer.get_var]). </description> </method> <method name="is_listening" qualifiers="const"> <return type="bool"> </return> <description> - Return whether this [PacketPeerUDP] is listening. + Returns whether this [PacketPeerUDP] is listening. </description> </method> <method name="listen"> diff --git a/doc/classes/PlaneMesh.xml b/doc/classes/PlaneMesh.xml index a8927f8479..a507f9f145 100644 --- a/doc/classes/PlaneMesh.xml +++ b/doc/classes/PlaneMesh.xml @@ -4,7 +4,7 @@ Class representing a planar [PrimitiveMesh]. </brief_description> <description> - Class representing a planar [PrimitiveMesh]. This flat mesh does not have a thickness. + Class representing a planar [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Z axes; this default rotation isn't suited for use with billboarded materials. For billboarded materials, use [QuadMesh] instead. </description> <tutorials> </tutorials> @@ -15,10 +15,10 @@ Size of the generated plane. Defaults to (2.0, 2.0). </member> <member name="subdivide_depth" type="int" setter="set_subdivide_depth" getter="get_subdivide_depth"> - Number of subdivision along the z-axis. Defaults to 0. + Number of subdivision along the Z axis. Defaults to 0. </member> <member name="subdivide_width" type="int" setter="set_subdivide_width" getter="get_subdivide_width"> - Number of subdivision along the x-axis. Defaults to 0. + Number of subdivision along the X axis. Defaults to 0. </member> </members> <constants> diff --git a/doc/classes/PoolByteArray.xml b/doc/classes/PoolByteArray.xml index f46cb243d7..cb99b660ae 100644 --- a/doc/classes/PoolByteArray.xml +++ b/doc/classes/PoolByteArray.xml @@ -116,14 +116,14 @@ <return type="String"> </return> <description> - Return SHA256 string of the PoolByteArray. + Returns SHA256 string of the PoolByteArray. </description> </method> <method name="size"> <return type="int"> </return> <description> - Return the size of the array. + Returns the size of the array. </description> </method> <method name="subarray"> diff --git a/doc/classes/PoolColorArray.xml b/doc/classes/PoolColorArray.xml index d16029a8d7..efc3582ba4 100644 --- a/doc/classes/PoolColorArray.xml +++ b/doc/classes/PoolColorArray.xml @@ -82,7 +82,7 @@ <return type="int"> </return> <description> - Return the size of the array. + Returns the size of the array. </description> </method> </methods> diff --git a/doc/classes/PoolIntArray.xml b/doc/classes/PoolIntArray.xml index 83d73c8a24..fca1083c25 100644 --- a/doc/classes/PoolIntArray.xml +++ b/doc/classes/PoolIntArray.xml @@ -82,7 +82,7 @@ <return type="int"> </return> <description> - Return the array size. + Returns the array size. </description> </method> </methods> diff --git a/doc/classes/PoolRealArray.xml b/doc/classes/PoolRealArray.xml index e1da99519c..c5f6062175 100644 --- a/doc/classes/PoolRealArray.xml +++ b/doc/classes/PoolRealArray.xml @@ -82,7 +82,7 @@ <return type="int"> </return> <description> - Return the size of the array. + Returns the size of the array. </description> </method> </methods> diff --git a/doc/classes/PoolStringArray.xml b/doc/classes/PoolStringArray.xml index 6ef4222996..01dca93be3 100644 --- a/doc/classes/PoolStringArray.xml +++ b/doc/classes/PoolStringArray.xml @@ -91,7 +91,7 @@ <return type="int"> </return> <description> - Return the size of the array. + Returns the size of the array. </description> </method> </methods> diff --git a/doc/classes/PoolVector2Array.xml b/doc/classes/PoolVector2Array.xml index 50ded06b90..45f619dc5d 100644 --- a/doc/classes/PoolVector2Array.xml +++ b/doc/classes/PoolVector2Array.xml @@ -82,7 +82,7 @@ <return type="int"> </return> <description> - Return the size of the array. + Returns the size of the array. </description> </method> </methods> diff --git a/doc/classes/PoolVector3Array.xml b/doc/classes/PoolVector3Array.xml index 69b4e54692..0a682e2baf 100644 --- a/doc/classes/PoolVector3Array.xml +++ b/doc/classes/PoolVector3Array.xml @@ -82,7 +82,7 @@ <return type="int"> </return> <description> - Return the size of the array. + Returns the size of the array. </description> </method> </methods> diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml index c3256f2f5b..e1b51463b2 100644 --- a/doc/classes/Popup.xml +++ b/doc/classes/Popup.xml @@ -27,6 +27,17 @@ Popup (show the control in modal form) in the center of the screen relative to its current canvas transform, at the current size, or at a size determined by "size". </description> </method> + <method name="popup_centered_clamped"> + <return type="void"> + </return> + <argument index="0" name="size" type="Vector2" default="Vector2( 0, 0 )"> + </argument> + <argument index="1" name="fallback_ratio" type="float" default="0.75"> + </argument> + <description> + Popup (show the control in modal form) in the center of the screen relative to the current canvas transform, clamping the size to [code]size[/code], then ensuring the popup is no larger than the viewport size multiplied by [code]fallback_ratio[/code]. + </description> + </method> <method name="popup_centered_minsize"> <return type="void"> </return> diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index a91f765d41..d4f4834a66 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -178,14 +178,14 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the accelerator of the item at index "idx". Accelerators are special combinations of keys that activate the item, no matter which control is focused. + Returns the accelerator of the item at index "idx". Accelerators are special combinations of keys that activate the item, no matter which control is focused. </description> </method> <method name="get_item_count" qualifiers="const"> <return type="int"> </return> <description> - Return the amount of items. + Returns the amount of items. </description> </method> <method name="get_item_icon" qualifiers="const"> @@ -194,7 +194,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the icon of the item at index "idx". + Returns the icon of the item at index "idx". </description> </method> <method name="get_item_id" qualifiers="const"> @@ -203,7 +203,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the id of the item at index "idx". + Returns the id of the item at index "idx". </description> </method> <method name="get_item_index" qualifiers="const"> @@ -221,7 +221,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the metadata of an item, which might be of any type. You can set it with [method set_item_metadata], which provides a simple way of assigning context data to items. + Returns the metadata of an item, which might be of any type. You can set it with [method set_item_metadata], which provides a simple way of assigning context data to items. </description> </method> <method name="get_item_shortcut" qualifiers="const"> @@ -238,7 +238,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the submenu name of the item at index "idx". + Returns the submenu name of the item at index "idx". </description> </method> <method name="get_item_text" qualifiers="const"> @@ -247,7 +247,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return the text of the item at index "idx". + Returns the text of the item at index "idx". </description> </method> <method name="get_item_tooltip" qualifiers="const"> @@ -270,7 +270,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return whether the item at index "idx" is checkable in some way, i.e., whether has a checkbox or radio button. Note that checkable items just display a checkmark or radio button, but don't have any built-in checking behavior and must be checked/unchecked manually. + Returns whether the item at index "idx" is checkable in some way, i.e., whether has a checkbox or radio button. Note that checkable items just display a checkmark or radio button, but don't have any built-in checking behavior and must be checked/unchecked manually. </description> </method> <method name="is_item_checked" qualifiers="const"> @@ -279,7 +279,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return whether the item at index "idx" is checked. + Returns whether the item at index "idx" is checked. </description> </method> <method name="is_item_disabled" qualifiers="const"> @@ -288,7 +288,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return whether the item at index "idx" is disabled. When it is disabled it can't be selected, or its action invoked. + Returns whether the item at index "idx" is disabled. When it is disabled it can't be selected, or its action invoked. </description> </method> <method name="is_item_radio_checkable" qualifiers="const"> @@ -297,7 +297,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return whether the item at index "idx" has radio-button-style checkability. Remember this is just cosmetic and you have to add the logic for checking/unchecking items in radio groups. + Returns whether the item at index "idx" has radio-button-style checkability. Remember this is just cosmetic and you have to add the logic for checking/unchecking items in radio groups. </description> </method> <method name="is_item_separator" qualifiers="const"> @@ -306,7 +306,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Return whether the item is a separator. If it is, it would be displayed as a line. + Returns whether the item is a separator. If it is, it would be displayed as a line. </description> </method> <method name="is_item_shortcut_disabled" qualifiers="const"> diff --git a/doc/classes/PrismMesh.xml b/doc/classes/PrismMesh.xml index 4c282c5e8d..62f1278bba 100644 --- a/doc/classes/PrismMesh.xml +++ b/doc/classes/PrismMesh.xml @@ -12,19 +12,19 @@ </methods> <members> <member name="left_to_right" type="float" setter="set_left_to_right" getter="get_left_to_right"> - Displacement of the upper edge along the x-axis. 0.0 positions edge straight above the bottom left edge. Defaults to 0.5 (positioned on the midpoint). + Displacement of the upper edge along the X axis. 0.0 positions edge straight above the bottom-left edge. Defaults to 0.5 (positioned on the midpoint). </member> <member name="size" type="Vector3" setter="set_size" getter="get_size"> Size of the prism. Defaults to (2.0, 2.0, 2.0). </member> <member name="subdivide_depth" type="int" setter="set_subdivide_depth" getter="get_subdivide_depth"> - Number of added edge loops along the z-axis. Defaults to 0. + Number of added edge loops along the Z axis. Defaults to 0. </member> <member name="subdivide_height" type="int" setter="set_subdivide_height" getter="get_subdivide_height"> - Number of added edge loops along the y-axis. Defaults to 0. + Number of added edge loops along the Y axis. Defaults to 0. </member> <member name="subdivide_width" type="int" setter="set_subdivide_width" getter="get_subdivide_width"> - Number of added edge loops along the x-axis. Defaults to 0. + Number of added edge loops along the X axis. Defaults to 0. </member> </members> <constants> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 4b5500d077..ff8b702859 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -180,6 +180,8 @@ <member name="application/config/icon" type="String" setter="" getter=""> Icon used for the project, set when project loads. Exporters will also use this icon when possible. </member> + <member name="application/config/macos_native_icon" type="String" setter="" getter=""> + </member> <member name="application/config/name" type="String" setter="" getter=""> The project's name. It is used both by the Project Manager and by exporters. The project name can be translated by translating its value in localization files. </member> @@ -189,6 +191,8 @@ <member name="application/config/use_custom_user_dir" type="bool" setter="" getter=""> If [code]true[/code], the project will save user data to its own user directory (see [member application/config/custom_user_dir_name]). This setting is only effective on desktop platforms. A name must be set in the [member application/config/custom_user_dir_name] setting for this to take effect. If [code]false[/code], the project will save user data to [code](OS user data directory)/Godot/app_userdata/(project name)[/code]. </member> + <member name="application/config/windows_native_icon" type="String" setter="" getter=""> + </member> <member name="application/run/disable_stderr" type="bool" setter="" getter=""> If [code]true[/code], disables printing to standard error in an exported build. </member> diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml index 1b33f62e0f..779ce11180 100644 --- a/doc/classes/QuadMesh.xml +++ b/doc/classes/QuadMesh.xml @@ -4,7 +4,7 @@ Class representing a square mesh. </brief_description> <description> - Class representing a square mesh with size (2,2,0). Consider using a [PlaneMesh] if you require a differently sized plane. + Class representing a square [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Y axes; this default rotation is more suited for use with billboarded materials. Unlike [PlaneMesh], this mesh doesn't provide subdivision options. </description> <tutorials> </tutorials> diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml index f7134e580d..3ef65e1edb 100644 --- a/doc/classes/Quat.xml +++ b/doc/classes/Quat.xml @@ -84,7 +84,7 @@ <return type="Vector3"> </return> <description> - Return Euler angles (in the YXZ convention: first Z, then X, and Y last) corresponding to the rotation represented by the unit quaternion. Returned vector contains the rotation angles in the format (X-angle, Y-angle, Z-angle). + Returns Euler angles (in the YXZ convention: first Z, then X, and Y last) corresponding to the rotation represented by the unit quaternion. Returned vector contains the rotation angles in the format (X-angle, Y-angle, Z-angle). </description> </method> <method name="inverse"> diff --git a/doc/classes/RayCast.xml b/doc/classes/RayCast.xml index 1d2999a1ed..1368143b67 100644 --- a/doc/classes/RayCast.xml +++ b/doc/classes/RayCast.xml @@ -50,7 +50,7 @@ <return type="Object"> </return> <description> - Return the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]). + Returns the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]). </description> </method> <method name="get_collider_shape" qualifiers="const"> @@ -87,7 +87,7 @@ <return type="bool"> </return> <description> - Return whether any object is intersecting with the ray's vector (considering the vector length). + Returns whether any object is intersecting with the ray's vector (considering the vector length). </description> </method> <method name="remove_exception"> diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml index 7a16e9e5e0..90e0178ddb 100644 --- a/doc/classes/RayCast2D.xml +++ b/doc/classes/RayCast2D.xml @@ -49,7 +49,7 @@ <return type="Object"> </return> <description> - Return the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]). + Returns the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]). </description> </method> <method name="get_collider_shape" qualifiers="const"> @@ -65,7 +65,7 @@ <argument index="0" name="bit" type="int"> </argument> <description> - Return an individual bit on the collision mask. + Returns an individual bit on the collision mask. </description> </method> <method name="get_collision_normal" qualifiers="const"> @@ -86,7 +86,7 @@ <return type="bool"> </return> <description> - Return whether any object is intersecting with the ray's vector (considering the vector length). + Returns whether any object is intersecting with the ray's vector (considering the vector length). </description> </method> <method name="remove_exception"> diff --git a/doc/classes/ResourceInteractiveLoader.xml b/doc/classes/ResourceInteractiveLoader.xml index 6b37cb25fb..bb9826999c 100644 --- a/doc/classes/ResourceInteractiveLoader.xml +++ b/doc/classes/ResourceInteractiveLoader.xml @@ -13,21 +13,21 @@ <return type="Resource"> </return> <description> - Return the loaded resource (only if loaded). Otherwise, returns null. + Returns the loaded resource (only if loaded). Otherwise, returns null. </description> </method> <method name="get_stage" qualifiers="const"> <return type="int"> </return> <description> - Return the load stage. The total amount of stages can be queried with [method get_stage_count] + Returns the load stage. The total amount of stages can be queried with [method get_stage_count] </description> </method> <method name="get_stage_count" qualifiers="const"> <return type="int"> </return> <description> - Return the total amount of stages (calls to [method poll]) needed to completely load this resource. + Returns the total amount of stages (calls to [method poll]) needed to completely load this resource. </description> </method> <method name="poll"> diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml index 70deb4509f..76b7c39191 100644 --- a/doc/classes/ResourceLoader.xml +++ b/doc/classes/ResourceLoader.xml @@ -33,7 +33,7 @@ <argument index="0" name="type" type="String"> </argument> <description> - Return the list of recognized extensions for a resource type. + Returns the list of recognized extensions for a resource type. </description> </method> <method name="has"> diff --git a/doc/classes/RigidBody.xml b/doc/classes/RigidBody.xml index 25b896ec3a..9ea6bb0fe1 100644 --- a/doc/classes/RigidBody.xml +++ b/doc/classes/RigidBody.xml @@ -86,7 +86,7 @@ <return type="Array"> </return> <description> - Return a list of the bodies colliding with this one. By default, number of max contacts reported is at 0, see the [member contacts_reported] property to increase it. Note that the result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead. + Returns a list of the bodies colliding with this one. By default, number of max contacts reported is at 0, see the [member contacts_reported] property to increase it. Note that the result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead. </description> </method> <method name="set_axis_velocity"> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index 0b1f659da3..a236d776c7 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -359,6 +359,12 @@ Emitted whenever a node is removed from the SceneTree. </description> </signal> + <signal name="node_renamed"> + <argument index="0" name="node" type="Node"> + </argument> + <description> + </description> + </signal> <signal name="physics_frame"> <description> Emitted immediately before [method Node._physics_process] is called on every node in the SceneTree. diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml index dec3c2b43c..c887e23de0 100644 --- a/doc/classes/Shape2D.xml +++ b/doc/classes/Shape2D.xml @@ -52,7 +52,7 @@ <argument index="4" name="shape_motion" type="Vector2"> </argument> <description> - Return whether this shape would collide with another, if a given movement was applied. + Returns whether this shape would collide with another, if a given movement was applied. This method needs the transformation matrix for this shape ([code]local_xform[/code]), the movement to test on this shape ([code]local_motion[/code]), the shape to check collisions with ([code]with_shape[/code]), the transformation matrix of that shape ([code]shape_xform[/code]), and the movement to test onto the other object ([code]shape_motion[/code]). </description> </method> diff --git a/doc/classes/Skeleton.xml b/doc/classes/Skeleton.xml index 8fab778a48..b693ee0a5e 100644 --- a/doc/classes/Skeleton.xml +++ b/doc/classes/Skeleton.xml @@ -44,14 +44,14 @@ <argument index="0" name="name" type="String"> </argument> <description> - Return the bone index that matches "name" as its name. + Returns the bone index that matches "name" as its name. </description> </method> <method name="get_bone_count" qualifiers="const"> <return type="int"> </return> <description> - Return the amount of bones in the skeleton. + Returns the amount of bones in the skeleton. </description> </method> <method name="get_bone_custom_pose" qualifiers="const"> @@ -60,7 +60,7 @@ <argument index="0" name="bone_idx" type="int"> </argument> <description> - Return the custom pose of the specified bone. Custom pose is applied on top of the rest pose. + Returns the custom pose of the specified bone. Custom pose is applied on top of the rest pose. </description> </method> <method name="get_bone_global_pose" qualifiers="const"> @@ -69,7 +69,7 @@ <argument index="0" name="bone_idx" type="int"> </argument> <description> - Return the overall transform of the specified bone, with respect to the skeleton. Being relative to the skeleton frame, this is not the actual "global" transform of the bone. + Returns the overall transform of the specified bone, with respect to the skeleton. Being relative to the skeleton frame, this is not the actual "global" transform of the bone. </description> </method> <method name="get_bone_name" qualifiers="const"> @@ -78,7 +78,7 @@ <argument index="0" name="bone_idx" type="int"> </argument> <description> - Return the name of the bone at index "index". + Returns the name of the bone at index "index". </description> </method> <method name="get_bone_parent" qualifiers="const"> @@ -87,7 +87,7 @@ <argument index="0" name="bone_idx" type="int"> </argument> <description> - Return the bone index which is the parent of the bone at "bone_idx". If -1, then bone has no parent. Note that the parent bone returned will always be less than "bone_idx". + Returns the bone index which is the parent of the bone at "bone_idx". If -1, then bone has no parent. Note that the parent bone returned will always be less than "bone_idx". </description> </method> <method name="get_bone_pose" qualifiers="const"> @@ -96,7 +96,7 @@ <argument index="0" name="bone_idx" type="int"> </argument> <description> - Return the pose transform of the specified bone. Pose is applied on top of the custom pose, which is applied on top the rest pose. + Returns the pose transform of the specified bone. Pose is applied on top of the custom pose, which is applied on top the rest pose. </description> </method> <method name="get_bone_rest" qualifiers="const"> @@ -105,7 +105,7 @@ <argument index="0" name="bone_idx" type="int"> </argument> <description> - Return the rest transform for a bone "bone_idx". + Returns the rest transform for a bone "bone_idx". </description> </method> <method name="get_bone_transform" qualifiers="const"> @@ -114,7 +114,7 @@ <argument index="0" name="bone_idx" type="int"> </argument> <description> - Return the combination of custom pose and pose. The returned transform is in skeleton's reference frame. + Returns the combination of custom pose and pose. The returned transform is in skeleton's reference frame. </description> </method> <method name="get_bound_child_nodes_to_bone" qualifiers="const"> @@ -229,7 +229,7 @@ <argument index="1" name="pose" type="Transform"> </argument> <description> - Return the pose transform for bone "bone_idx". + Returns the pose transform for bone "bone_idx". </description> </method> <method name="set_bone_rest"> diff --git a/doc/classes/SpatialMaterial.xml b/doc/classes/SpatialMaterial.xml index 8e93160af9..f0df5fac4a 100644 --- a/doc/classes/SpatialMaterial.xml +++ b/doc/classes/SpatialMaterial.xml @@ -120,6 +120,8 @@ <member name="flags_use_point_size" type="bool" setter="set_flag" getter="get_flag"> If [code]true[/code], render point size can be changed. Note: this is only effective for objects whose geometry is point-based rather than triangle-based. See also [member params_point_size]. </member> + <member name="flags_use_shadow_to_opacity" type="bool" setter="set_flag" getter="get_flag"> + </member> <member name="flags_vertex_lighting" type="bool" setter="set_flag" getter="get_flag"> If [code]true[/code], lighting is calculated per vertex rather than per pixel. This may increase performance on low-end devices. Default value: [code]false[/code]. </member> @@ -390,7 +392,9 @@ </constant> <constant name="FLAG_ENSURE_CORRECT_NORMALS" value="16" enum="Flags"> </constant> - <constant name="FLAG_MAX" value="18" enum="Flags"> + <constant name="FLAG_USE_SHADOW_TO_OPACITY" value="18" enum="Flags"> + </constant> + <constant name="FLAG_MAX" value="19" enum="Flags"> </constant> <constant name="DIFFUSE_BURLEY" value="0" enum="DiffuseMode"> Default diffuse scattering algorithm. diff --git a/doc/classes/SphereMesh.xml b/doc/classes/SphereMesh.xml index 0124d8a4b0..4ebb2e919d 100644 --- a/doc/classes/SphereMesh.xml +++ b/doc/classes/SphereMesh.xml @@ -15,7 +15,7 @@ Full height of the sphere. Defaults to 2.0. </member> <member name="is_hemisphere" type="bool" setter="set_is_hemisphere" getter="get_is_hemisphere"> - Determines whether a full sphere or a hemisphere is created. Attention: To get a regular hemisphere the height and radius of the sphere have to equal. Defaults to [code]false[/code]. + Determines whether a full sphere or a hemisphere is created. Attention: To get a regular hemisphere, the height and radius of the sphere have to equal. Defaults to [code]false[/code]. </member> <member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments"> Number of radial segments on the sphere. Defaults to 64. diff --git a/doc/classes/Sprite.xml b/doc/classes/Sprite.xml index cc5fe93567..26ff67cc74 100644 --- a/doc/classes/Sprite.xml +++ b/doc/classes/Sprite.xml @@ -13,7 +13,13 @@ <return type="Rect2"> </return> <description> - Returns a Rect2 representing the Sprite's boundary relative to its local coordinates. + Returns a [Rect2] representing the Sprite's boundary in local coordinates. Can be used to detect if the Sprite was clicked. Example: + [codeblock] + func _input(event): + if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT: + if get_rect().has_point(to_local(event.position)): + print("A click!") + [/codeblock] </description> </method> <method name="is_pixel_opaque" qualifiers="const"> @@ -48,7 +54,7 @@ The texture's drawing offset. </member> <member name="region_enabled" type="bool" setter="set_region" getter="is_region"> - If [code]true[/code], texture is cut from a larger atlas texture. See [code]region_rect[/code]. Default value: [code]false[/code]. + If [code]true[/code], texture is cut from a larger atlas texture. See [member region_rect]. Default value: [code]false[/code]. </member> <member name="region_filter_clip" type="bool" setter="set_region_filter_clip" getter="is_region_filter_clip_enabled"> If [code]true[/code], the outermost pixels get blurred out. diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml index af8e43944c..d278312fc3 100644 --- a/doc/classes/StreamPeer.xml +++ b/doc/classes/StreamPeer.xml @@ -41,7 +41,7 @@ <return type="int"> </return> <description> - Return the amount of bytes this [StreamPeer] has available. + Returns the amount of bytes this [StreamPeer] has available. </description> </method> <method name="get_data"> @@ -50,7 +50,7 @@ <argument index="0" name="bytes" type="int"> </argument> <description> - Return a chunk data with the received bytes. The amount of bytes to be received can be requested in the "bytes" argument. If not enough bytes are available, the function will block until the desired amount is received. This function returns two values, an Error code and a data array. + Returns a chunk data with the received bytes. The amount of bytes to be received can be requested in the "bytes" argument. If not enough bytes are available, the function will block until the desired amount is received. This function returns two values, an Error code and a data array. </description> </method> <method name="get_double"> @@ -73,7 +73,7 @@ <argument index="0" name="bytes" type="int"> </argument> <description> - Return a chunk data with the received bytes. The amount of bytes to be received can be requested in the "bytes" argument. If not enough bytes are available, the function will return how many were actually received. This function returns two values, an Error code, and a data array. + Returns a chunk data with the received bytes. The amount of bytes to be received can be requested in the "bytes" argument. If not enough bytes are available, the function will return how many were actually received. This function returns two values, an Error code, and a data array. </description> </method> <method name="get_string"> diff --git a/doc/classes/StreamPeerSSL.xml b/doc/classes/StreamPeerSSL.xml index f7fd36ed58..f28e6e5544 100644 --- a/doc/classes/StreamPeerSSL.xml +++ b/doc/classes/StreamPeerSSL.xml @@ -42,7 +42,7 @@ <return type="int" enum="StreamPeerSSL.Status"> </return> <description> - Return the status of the connection, one of STATUS_* enum. + Returns the status of the connection, one of STATUS_* enum. </description> </method> <method name="poll"> diff --git a/doc/classes/StreamPeerTCP.xml b/doc/classes/StreamPeerTCP.xml index 16bf69110d..0edea42521 100644 --- a/doc/classes/StreamPeerTCP.xml +++ b/doc/classes/StreamPeerTCP.xml @@ -31,21 +31,21 @@ <return type="String"> </return> <description> - Return the IP of this peer. + Returns the IP of this peer. </description> </method> <method name="get_connected_port" qualifiers="const"> <return type="int"> </return> <description> - Return the port of this peer. + Returns the port of this peer. </description> </method> <method name="get_status"> <return type="int" enum="StreamPeerTCP.Status"> </return> <description> - Return the status of the connection, see [enum StreamPeerTCP.Status]. + Returns the status of the connection, see [enum StreamPeerTCP.Status]. </description> </method> <method name="is_connected_to_host" qualifiers="const"> diff --git a/doc/classes/StyleBox.xml b/doc/classes/StyleBox.xml index 40cb2632b6..a156f134e7 100644 --- a/doc/classes/StyleBox.xml +++ b/doc/classes/StyleBox.xml @@ -37,7 +37,7 @@ <argument index="0" name="margin" type="int" enum="Margin"> </argument> <description> - Return the content margin offset for the specified margin + Returns the content margin offset for the specified margin Positive values reduce size inwards, unlike [Control]'s margin values. </description> </method> @@ -45,14 +45,14 @@ <return type="Vector2"> </return> <description> - Return the minimum size that this stylebox can be shrunk to. + Returns the minimum size that this stylebox can be shrunk to. </description> </method> <method name="get_offset" qualifiers="const"> <return type="Vector2"> </return> <description> - Return the "offset" of a stylebox, this is a helper function, like writing [code]Vector2(style.get_margin(MARGIN_LEFT), style.get_margin(MARGIN_TOP))[/code]. + Returns the "offset" of a stylebox, this is a helper function, like writing [code]Vector2(style.get_margin(MARGIN_LEFT), style.get_margin(MARGIN_TOP))[/code]. </description> </method> <method name="test_mask" qualifiers="const"> diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index 25188a80db..e97f9995ee 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -169,6 +169,12 @@ Returns a constructed [ArrayMesh] from current information passed in. If an existing [ArrayMesh] is passed in as an argument, will add an extra surface to the existing [ArrayMesh]. </description> </method> + <method name="commit_to_arrays"> + <return type="Array"> + </return> + <description> + </description> + </method> <method name="create_from"> <return type="void"> </return> @@ -180,6 +186,18 @@ Creates a vertex array from an existing [Mesh]. </description> </method> + <method name="create_from_blend_shape"> + <return type="void"> + </return> + <argument index="0" name="existing" type="Mesh"> + </argument> + <argument index="1" name="surface" type="int"> + </argument> + <argument index="2" name="blend_shape" type="String"> + </argument> + <description> + </description> + </method> <method name="deindex"> <return type="void"> </return> diff --git a/doc/classes/TCP_Server.xml b/doc/classes/TCP_Server.xml index ac9b33bc34..663d3248e8 100644 --- a/doc/classes/TCP_Server.xml +++ b/doc/classes/TCP_Server.xml @@ -13,7 +13,7 @@ <return type="bool"> </return> <description> - Return [code]true[/code] if a connection is available for taking. + Returns [code]true[/code] if a connection is available for taking. </description> </method> <method name="listen"> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 66c0f0277a..eb70d7a1c3 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -69,14 +69,14 @@ <return type="int"> </return> <description> - Return the column the editing cursor is at. + Returns the column the editing cursor is at. </description> </method> <method name="cursor_get_line" qualifiers="const"> <return type="int"> </return> <description> - Return the line the editing cursor is at. + Returns the line the editing cursor is at. </description> </method> <method name="cursor_set_column"> @@ -137,7 +137,7 @@ <return type="Array"> </return> <description> - Return an array containing the line number of each breakpoint. + Returns an array containing the line number of each breakpoint. </description> </method> <method name="get_keyword_color" qualifiers="const"> @@ -154,14 +154,14 @@ <argument index="0" name="line" type="int"> </argument> <description> - Return the text of a specific line. + Returns the text of a specific line. </description> </method> <method name="get_line_count" qualifiers="const"> <return type="int"> </return> <description> - Return the amount of total lines in the text. + Returns the amount of total lines in the text. </description> </method> <method name="get_menu" qualifiers="const"> @@ -175,35 +175,35 @@ <return type="int"> </return> <description> - Return the selection begin column. + Returns the selection begin column. </description> </method> <method name="get_selection_from_line" qualifiers="const"> <return type="int"> </return> <description> - Return the selection begin line. + Returns the selection begin line. </description> </method> <method name="get_selection_text" qualifiers="const"> <return type="String"> </return> <description> - Return the text inside the selection. + Returns the text inside the selection. </description> </method> <method name="get_selection_to_column" qualifiers="const"> <return type="int"> </return> <description> - Return the selection end column. + Returns the selection end column. </description> </method> <method name="get_selection_to_line" qualifiers="const"> <return type="int"> </return> <description> - Return the selection end line. + Returns the selection end line. </description> </method> <method name="get_word_under_cursor" qualifiers="const"> @@ -250,7 +250,7 @@ <return type="bool"> </return> <description> - Return [code]true[/code] if the selection is active. + Returns [code]true[/code] if the selection is active. </description> </method> <method name="menu_option"> diff --git a/doc/classes/Texture.xml b/doc/classes/Texture.xml index 39f3ee447c..4418a6ce8f 100644 --- a/doc/classes/Texture.xml +++ b/doc/classes/Texture.xml @@ -74,21 +74,21 @@ <return type="int"> </return> <description> - Return the texture height. + Returns the texture height. </description> </method> <method name="get_size" qualifiers="const"> <return type="Vector2"> </return> <description> - Return the texture size. + Returns the texture size. </description> </method> <method name="get_width" qualifiers="const"> <return type="int"> </return> <description> - Return the texture width. + Returns the texture width. </description> </method> <method name="has_alpha" qualifiers="const"> diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml index bc44ec161a..c14e098b12 100644 --- a/doc/classes/Theme.xml +++ b/doc/classes/Theme.xml @@ -8,6 +8,7 @@ Theme resources can be alternatively loaded by writing them in a .theme file, see docs for more info. </description> <tutorials> + <link>https://docs.godotengine.org/en/stable/tutorials/gui/gui_skinning.html</link> </tutorials> <methods> <method name="clear"> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index b60673bb5b..0272efeecb 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -271,6 +271,12 @@ Emitted when a cell with the [code]CELL_MODE_CUSTOM[/code] is clicked to be edited. </description> </signal> + <signal name="empty_rmb"> + <argument index="0" name="position" type="Vector2"> + </argument> + <description> + </description> + </signal> <signal name="empty_tree_rmb_selected"> <argument index="0" name="position" type="Vector2"> </argument> diff --git a/doc/classes/VehicleWheel.xml b/doc/classes/VehicleWheel.xml index f8dac82cb5..c3b668c170 100644 --- a/doc/classes/VehicleWheel.xml +++ b/doc/classes/VehicleWheel.xml @@ -9,6 +9,12 @@ <tutorials> </tutorials> <methods> + <method name="get_rpm" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_skidinfo" qualifiers="const"> <return type="float"> </return> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index b48dc9de35..53e66cee74 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -253,6 +253,9 @@ <member name="physics_object_picking" type="bool" setter="set_physics_object_picking" getter="get_physics_object_picking"> If [code]true[/code], the objects rendered by viewport become subjects of mouse picking process. Default value: [code]false[/code]. </member> + <member name="render_direct_to_screen" type="bool" setter="set_use_render_direct_to_screen" getter="is_using_render_direct_to_screen"> + If [code]true[/code], renders the Viewport directly to the screen instead of to the root viewport. Only available in GLES2. This is a low-level optimization and should not be used in most cases. If used, reading from the Viewport or from [code]SCREEN_TEXTURE[/code] becomes unavailable. For more information see [method VisualServer.viewport_set_render_direct_to_screen]. Default value: [code]false[/code]. + </member> <member name="render_target_clear_mode" type="int" setter="set_clear_mode" getter="get_clear_mode" enum="Viewport.ClearMode"> The clear mode when viewport used as a render target. Default value: [code]CLEAR_MODE_ALWAYS[/code]. </member> diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index dae120f09b..3997798cca 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -3590,7 +3590,14 @@ <argument index="2" name="screen" type="int" default="0"> </argument> <description> - Attaches a viewport to a screen. + Copies viewport to a region of the screen specified by [code]rect[/code]. If Viewport.[member Viewport.render_direct_to_screen] is [code]true[/code], then viewport does not use a framebuffer and the contents of the viewport are rendered directly to screen. However, note that the root viewport is drawn last, therefore it will draw over the screen. Accordingly, you must set the root viewport to an area that does not cover the area that you have attached this viewport to. + For example, you can set the root viewport to not render at all with the following code: + [codeblock] + func _ready(): + get_viewport().set_attach_to_screen_rect(Rect2()) + $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600)) + [/codeblock] + Using this can result in significant optimization, especially on lower-end devices. However, it comes at the cost of having to manage your viewports manually. For a further optimization see, [method viewport_set_render_direct_to_screen]. </description> </method> <method name="viewport_create"> @@ -3789,6 +3796,17 @@ Sets the viewport's parent to another viewport. </description> </method> + <method name="viewport_set_render_direct_to_screen"> + <return type="void"> + </return> + <argument index="0" name="viewport" type="RID"> + </argument> + <argument index="1" name="enabled" type="bool"> + </argument> + <description> + If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size. + </description> + </method> <method name="viewport_set_scenario"> <return type="void"> </return> diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml index d399f69c96..6d5f53d992 100644 --- a/doc/classes/VisualShader.xml +++ b/doc/classes/VisualShader.xml @@ -53,6 +53,22 @@ <description> </description> </method> + <method name="connect_nodes_forced"> + <return type="void"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="from_node" type="int"> + </argument> + <argument index="2" name="from_port" type="int"> + </argument> + <argument index="3" name="to_node" type="int"> + </argument> + <argument index="4" name="to_port" type="int"> + </argument> + <description> + </description> + </method> <method name="disconnect_nodes"> <return type="void"> </return> @@ -129,6 +145,12 @@ <description> </description> </method> + <method name="rebuild"> + <return type="void"> + </return> + <description> + </description> + </method> <method name="remove_node"> <return type="void"> </return> diff --git a/doc/classes/VisualShaderNodeExpression.xml b/doc/classes/VisualShaderNodeExpression.xml new file mode 100644 index 0000000000..8a5477280f --- /dev/null +++ b/doc/classes/VisualShaderNodeExpression.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeExpression" inherits="VisualShaderNodeGroupBase" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="build"> + <return type="void"> + </return> + <description> + </description> + </method> + </methods> + <members> + <member name="expression" type="String" setter="set_expression" getter="get_expression"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeGroupBase.xml b/doc/classes/VisualShaderNodeGroupBase.xml new file mode 100644 index 0000000000..37d48956f6 --- /dev/null +++ b/doc/classes/VisualShaderNodeGroupBase.xml @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeGroupBase" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_input_port"> + <return type="void"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <argument index="1" name="type" type="int"> + </argument> + <argument index="2" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="add_output_port"> + <return type="void"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <argument index="1" name="type" type="int"> + </argument> + <argument index="2" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="clear_input_ports"> + <return type="void"> + </return> + <description> + </description> + </method> + <method name="clear_output_ports"> + <return type="void"> + </return> + <description> + </description> + </method> + <method name="get_control"> + <return type="Control"> + </return> + <argument index="0" name="index" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_free_input_port_id" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_free_output_port_id" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_input_port_count" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_inputs" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_output_port_count" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_outputs" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_size" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + </description> + </method> + <method name="has_input_port" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="has_output_port" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="remove_input_port"> + <return type="void"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="remove_output_port"> + <return type="void"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_control"> + <return type="void"> + </return> + <argument index="0" name="control" type="Control"> + </argument> + <argument index="1" name="index" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_input_port_name"> + <return type="void"> + </return> + <argument index="0" name="arg0" type="int"> + </argument> + <argument index="1" name="arg1" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_input_port_type"> + <return type="void"> + </return> + <argument index="0" name="arg0" type="int"> + </argument> + <argument index="1" name="arg1" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_inputs"> + <return type="void"> + </return> + <argument index="0" name="inputs" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_output_port_name"> + <return type="void"> + </return> + <argument index="0" name="arg0" type="int"> + </argument> + <argument index="1" name="arg1" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_output_port_type"> + <return type="void"> + </return> + <argument index="0" name="arg0" type="int"> + </argument> + <argument index="1" name="arg1" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_outputs"> + <return type="void"> + </return> + <argument index="0" name="outputs" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_size"> + <return type="void"> + </return> + <argument index="0" name="size" type="Vector2"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/WindowDialog.xml b/doc/classes/WindowDialog.xml index 16b7bd84ad..c5d66af984 100644 --- a/doc/classes/WindowDialog.xml +++ b/doc/classes/WindowDialog.xml @@ -13,7 +13,7 @@ <return type="TextureButton"> </return> <description> - Return the close [TextureButton]. + Returns the close [TextureButton]. </description> </method> </methods> diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 3b31da1dd7..253936ca34 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -692,6 +692,7 @@ public: /* RENDER TARGET */ RID render_target_create() { return RID(); } + void render_target_set_position(RID p_render_target, int p_x, int p_y) {} void render_target_set_size(RID p_render_target, int p_width, int p_height) {} RID render_target_get_texture(RID p_render_target) const { return RID(); } void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {} diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 7232d2d95a..ee722e9d6c 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -113,9 +113,22 @@ void RasterizerCanvasGLES2::canvas_begin() { state.canvas_shader.bind(); state.using_transparent_rt = false; + int viewport_x, viewport_y, viewport_width, viewport_height; + if (storage->frame.current_rt) { glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); state.using_transparent_rt = storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; + + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + // set Viewport and Scissor when rendering directly to screen + viewport_width = storage->frame.current_rt->width; + viewport_height = storage->frame.current_rt->height; + viewport_x = storage->frame.current_rt->x; + viewport_y = OS::get_singleton()->get_window_size().height - viewport_height - storage->frame.current_rt->y; + glScissor(viewport_x, viewport_y, viewport_width, viewport_height); + glViewport(viewport_x, viewport_y, viewport_width, viewport_height); + glEnable(GL_SCISSOR_TEST); + } } if (storage->frame.clear_request) { @@ -179,6 +192,14 @@ void RasterizerCanvasGLES2::canvas_end() { glDisableVertexAttribArray(i); } + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + //reset viewport to full window size + int viewport_width = OS::get_singleton()->get_window_size().width; + int viewport_height = OS::get_singleton()->get_window_size().height; + glViewport(0, 0, viewport_width, viewport_height); + glScissor(0, 0, viewport_width, viewport_height); + } + state.using_texture_rect = false; state.using_skeleton = false; state.using_ninepatch = false; @@ -1192,6 +1213,11 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur void RasterizerCanvasGLES2::_copy_screen(const Rect2 &p_rect) { + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + ERR_PRINT_ONCE("Cannot use screen texture copying in render target set to render direct to screen"); + return; + } + if (storage->frame.current_rt->copy_screen_effect.color == 0) { ERR_EXPLAIN("Can't use screen texture copying in a render target configured without copy buffers"); ERR_FAIL(); diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 2d9eec10d2..83e1196979 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -1011,7 +1011,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G has_alpha = false; } - RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + RenderList::Element *e = (has_alpha || p_material->shader->spatial.no_depth_test) ? render_list.add_alpha_element() : render_list.add_element(); if (!e) { return; @@ -2695,6 +2695,8 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const Environment *env = NULL; int viewport_width, viewport_height; + int viewport_x = 0; + int viewport_y = 0; bool probe_interior = false; bool reverse_cull = false; @@ -2734,6 +2736,13 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const viewport_width = storage->frame.current_rt->width; viewport_height = storage->frame.current_rt->height; + viewport_x = storage->frame.current_rt->x; + + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + viewport_y = OS::get_singleton()->get_window_size().height - viewport_height - storage->frame.current_rt->y; + } else { + viewport_y = storage->frame.current_rt->y; + } } state.used_screen_texture = false; @@ -2799,7 +2808,13 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const // other stuff glBindFramebuffer(GL_FRAMEBUFFER, current_fb); - glViewport(0, 0, viewport_width, viewport_height); + glViewport(viewport_x, viewport_y, viewport_width, viewport_height); + + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + + glScissor(viewport_x, viewport_y, viewport_width, viewport_height); + glEnable(GL_SCISSOR_TEST); + } glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); @@ -2834,6 +2849,10 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + glDisable(GL_SCISSOR_TEST); + } + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); glBlendEquation(GL_FUNC_ADD); @@ -2860,13 +2879,6 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const } } - if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) { - - if (sky && sky->panorama.is_valid()) { - _draw_sky(sky, p_cam_projection, cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation); - } - } - if (probe_interior) { env_radiance_tex = 0; //do not use radiance texture on interiors state.default_ambient = Color(0, 0, 0, 1); //black as default ambient for interior @@ -2877,6 +2889,14 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const render_list.sort_by_key(false); _render_render_list(render_list.elements, render_list.element_count, cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, reverse_cull, false, false); + // then draw the sky after + if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) { + + if (sky && sky->panorama.is_valid()) { + _draw_sky(sky, p_cam_projection, cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation); + } + } + if (storage->frame.current_rt && state.used_screen_texture) { //copy screen texture diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index d805984dca..bd1a61688c 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -603,12 +603,10 @@ public: struct SortByReverseDepthAndPriority { _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - uint32_t layer_A = uint32_t(A->sort_key >> SORT_KEY_PRIORITY_SHIFT); - uint32_t layer_B = uint32_t(B->sort_key >> SORT_KEY_PRIORITY_SHIFT); - if (layer_A == layer_B) { + if (A->priority == B->priority) { return A->instance->depth > B->instance->depth; } else { - return layer_A < layer_B; + return A->priority < B->priority; } } }; diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index d709056709..c610f31bc1 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -4568,9 +4568,16 @@ void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerSc void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { + // do not allocate a render target with no size if (rt->width <= 0 || rt->height <= 0) return; + // do not allocate a render target that is attached to the screen + if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { + rt->fbo = RasterizerStorageGLES2::system_fbo; + return; + } + GLuint color_internal_format; GLuint color_format; GLuint color_type = GL_UNSIGNED_BYTE; @@ -4779,6 +4786,10 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) { + // there is nothing to clear when DIRECT_TO_SCREEN is used + if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) + return; + if (rt->fbo) { glDeleteFramebuffers(1, &rt->fbo); glDeleteTextures(1, &rt->color); @@ -4873,6 +4884,15 @@ RID RasterizerStorageGLES2::render_target_create() { return render_target_owner.make_rid(rt); } +void RasterizerStorageGLES2::render_target_set_position(RID p_render_target, int p_x, int p_y) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + rt->x = p_x; + rt->y = p_y; +} + void RasterizerStorageGLES2::render_target_set_size(RID p_render_target, int p_width, int p_height) { RenderTarget *rt = render_target_owner.getornull(p_render_target); @@ -5002,6 +5022,14 @@ void RasterizerStorageGLES2::render_target_set_flag(RID p_render_target, RenderT RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); + // When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as + // those functions change how they operate depending on the value of DIRECT_TO_SCREEN + if (p_flag == RENDER_TARGET_DIRECT_TO_SCREEN && p_value != rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { + _render_target_clear(rt); + rt->flags[p_flag] = p_value; + _render_target_allocate(rt); + } + rt->flags[p_flag] = p_value; switch (p_flag) { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 3134082e2a..af57aa3d9b 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -1175,7 +1175,7 @@ public: } } external; - int width, height; + int x, y, width, height; bool flags[RENDER_TARGET_FLAG_MAX]; @@ -1192,6 +1192,8 @@ public: multisample_color(0), multisample_depth(0), multisample_active(false), + x(0), + y(0), width(0), height(0), used_in_frame(false), @@ -1209,6 +1211,7 @@ public: void _render_target_allocate(RenderTarget *rt); virtual RID render_target_create(); + virtual void render_target_set_position(RID p_render_target, int p_x, int p_y); virtual void render_target_set_size(RID p_render_target, int p_width, int p_height); virtual RID render_target_get_texture(RID p_render_target) const; virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index d00b03fb8a..9778d39a21 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -316,9 +316,14 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->uniforms.front(); E; E = E->next()) { StringBuffer<> uniform_code; - uniform_code += "uniform "; + // use highp if no precision is specified to prevent different default values in fragment and vertex shader + SL::DataPrecision precision = E->get().precision; + if (precision == SL::PRECISION_DEFAULT) { + precision = SL::PRECISION_HIGHP; + } - uniform_code += _prestr(E->get().precision); + uniform_code += "uniform "; + uniform_code += _prestr(precision); uniform_code += _typestr(E->get().type); uniform_code += " "; uniform_code += _mkid(E->key()); @@ -934,6 +939,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; // No defines for particle shaders in GLES2, there are no GPU particles diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 0fa290e57c..2aef913ae8 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -1151,7 +1151,8 @@ void light_compute( float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, - inout vec3 specular_light) { + inout vec3 specular_light, + inout float alpha) { //this makes lights behave closer to linear, but then addition of lights looks bad //better left disabled @@ -1306,10 +1307,10 @@ LIGHT_SHADER_CODE // shlick+ggx as default #if defined(LIGHT_USE_ANISOTROPY) - float alpha = roughness * roughness; + float alpha_ggx = roughness * roughness; float aspect = sqrt(1.0 - anisotropy * 0.9); - float ax = alpha / aspect; - float ay = alpha * aspect; + float ax = alpha_ggx / aspect; + float ay = alpha_ggx * aspect; float XdotH = dot(T, H); float YdotH = dot(B, H); float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH, cNdotH); @@ -1317,10 +1318,10 @@ LIGHT_SHADER_CODE float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL); #else - float alpha = roughness * roughness; - float D = D_GGX(cNdotH, alpha); - //float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); - float G = V_GGX(cNdotL, cNdotV, alpha); + float alpha_ggx = roughness * roughness; + float D = D_GGX(cNdotH, alpha_ggx); + //float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); + float G = V_GGX(cNdotL, cNdotV, alpha_ggx); #endif // F vec3 f0 = F0(metallic, specular, diffuse_color); @@ -1350,6 +1351,10 @@ LIGHT_SHADER_CODE #endif } +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); +#endif + #endif //defined(USE_LIGHT_SHADER_CODE) } @@ -1535,17 +1540,21 @@ FRAGMENT_SHADER_CODE vec3 eye_position = view; +#if !defined(USE_SHADOW_TO_OPACITY) + #if defined(ALPHA_SCISSOR_USED) if (alpha < alpha_scissor) { discard; } -#endif +#endif // ALPHA_SCISSOR_USED #ifdef USE_DEPTH_PREPASS if (alpha < 0.99) { discard; } -#endif +#endif // USE_DEPTH_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY #ifdef BASE_PASS //none @@ -2061,13 +2070,32 @@ FRAGMENT_SHADER_CODE clearcoat_gloss, anisotropy, diffuse_light, - specular_light); + specular_light, + alpha); #endif //vertex lighting #endif //USE_LIGHTING //compute and merge +#ifdef USE_SHADOW_TO_OPACITY + + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_DEPTH_PREPASS + if (alpha < 0.99) { + discard; + } +#endif // USE_DEPTH_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY + #ifndef RENDER_DEPTH #ifdef SHADELESS @@ -2105,8 +2133,6 @@ FRAGMENT_SHADER_CODE #endif // gl_FragColor = vec4(normal, 1.0); -#endif //unshaded - //apply fog #if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) @@ -2161,6 +2187,8 @@ FRAGMENT_SHADER_CODE #endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) +#endif //unshaded + #else // not RENDER_DEPTH //depth render #ifdef USE_RGBA_SHADOWS diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 9aec348291..4552fddfe8 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2374,7 +2374,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G has_alpha = false; } - RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + RenderList::Element *e = (has_alpha || p_material->shader->spatial.no_depth_test) ? render_list.add_alpha_element() : render_list.add_element(); if (!e) return; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 661be28e6b..8311d0de84 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -7268,6 +7268,10 @@ RID RasterizerStorageGLES3::render_target_create() { return render_target_owner.make_rid(rt); } +void RasterizerStorageGLES3::render_target_set_position(RID p_render_target, int p_x, int p_y) { + //only used in GLES2 +} + void RasterizerStorageGLES3::render_target_set_size(RID p_render_target, int p_width, int p_height) { RenderTarget *rt = render_target_owner.getornull(p_render_target); @@ -8154,7 +8158,7 @@ void RasterizerStorageGLES3::initialize() { } shaders.cubemap_filter.init(); - bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx.mobile"); + bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx"); shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY, !ggx_hq); shaders.particles.init(); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index a4cc84ef02..3d86558407 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -297,6 +297,7 @@ public: target(GL_TEXTURE_2D), data_size(0), compressed(false), + srgb(false), total_data_size(0), ignore_mipmaps(false), mipmaps(0), @@ -1394,6 +1395,7 @@ public: void _render_target_allocate(RenderTarget *rt); virtual RID render_target_create(); + virtual void render_target_set_position(RID p_render_target, int p_x, int p_y); virtual void render_target_set_size(RID p_render_target, int p_width, int p_height); virtual RID render_target_get_texture(RID p_render_target) const; virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id); diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index ad26294527..e8417900ea 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -944,6 +944,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; /* PARTICLES SHADER */ diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index f65f798ff0..619e29b130 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -163,7 +163,7 @@ vec2 Hammersley(uint i, uint N) { #else -#define SAMPLE_COUNT 512u +#define SAMPLE_COUNT 1024u #endif diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 584668a09c..f08d3f4d23 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -993,7 +993,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) { #if defined(USE_LIGHT_SHADER_CODE) // light is written by the light shader @@ -1135,19 +1135,19 @@ LIGHT_SHADER_CODE #if defined(LIGHT_USE_ANISOTROPY) - float alpha = roughness * roughness; + float alpha_ggx = roughness * roughness; float aspect = sqrt(1.0 - anisotropy * 0.9); - float ax = alpha / aspect; - float ay = alpha * aspect; + float ax = alpha_ggx / aspect; + float ay = alpha_ggx * aspect; float XdotH = dot(T, H); float YdotH = dot(B, H); float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); #else - float alpha = roughness * roughness; - float D = D_GGX(cNdotH, alpha); - float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); + float alpha_ggx = roughness * roughness; + float D = D_GGX(cNdotH, alpha_ggx); + float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); #endif // F vec3 f0 = F0(metallic, specular, diffuse_color); @@ -1174,6 +1174,10 @@ LIGHT_SHADER_CODE #endif } +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); +#endif + #endif //defined(USE_LIGHT_SHADER_CODE) } @@ -1250,7 +1254,7 @@ vec3 light_transmittance(float translucency,vec3 light_vec, vec3 normal, vec3 po } #endif -void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) { vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex; float light_length = length(light_rel_vec); @@ -1304,10 +1308,10 @@ void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi light_attenuation *= mix(omni_lights[idx].shadow_color_contact.rgb, vec3(1.0), shadow); } #endif //SHADOWS_DISABLED - light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, omni_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, omni_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * omni_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, omni_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, omni_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * omni_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light, alpha); } -void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) { vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex; float light_length = length(light_rel_vec); @@ -1339,7 +1343,7 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi } #endif //SHADOWS_DISABLED - light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, spot_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, spot_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * spot_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, spot_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, spot_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * spot_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light, alpha); } void reflection_process(int idx, vec3 vertex, vec3 normal, vec3 binormal, vec3 tangent, float roughness, float anisotropy, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { @@ -1705,11 +1709,13 @@ FRAGMENT_SHADER_CODE /* clang-format on */ } +#if !defined(USE_SHADOW_TO_OPACITY) + #if defined(ALPHA_SCISSOR_USED) if (alpha < alpha_scissor) { discard; } -#endif +#endif // ALPHA_SCISSOR_USED #ifdef USE_OPAQUE_PREPASS @@ -1717,7 +1723,9 @@ FRAGMENT_SHADER_CODE discard; } -#endif +#endif // USE_OPAQUE_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY #if defined(ENABLE_NORMALMAP) @@ -2044,7 +2052,7 @@ FRAGMENT_SHADER_CODE specular_light *= mix(vec3(1.0), light_attenuation, specular_light_interp.a); #else - light_compute(normal, -light_direction_attenuation.xyz, eye_vec, binormal, tangent, light_color_energy.rgb, light_attenuation, albedo, transmission, light_params.z * specular_blob_intensity, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, -light_direction_attenuation.xyz, eye_vec, binormal, tangent, light_color_energy.rgb, light_attenuation, albedo, transmission, light_params.z * specular_blob_intensity, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light, alpha); #endif #endif //#USE_LIGHT_DIRECTIONAL @@ -2057,17 +2065,36 @@ FRAGMENT_SHADER_CODE #else for (int i = 0; i < omni_light_count; i++) { - light_process_omni(omni_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); + light_process_omni(omni_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light, alpha); } for (int i = 0; i < spot_light_count; i++) { - light_process_spot(spot_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); + light_process_spot(spot_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light, alpha); } #endif //USE_VERTEX_LIGHTING #endif +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_OPAQUE_PREPASS + + if (alpha < opaque_prepass_threshold) { + discard; + } + +#endif // USE_OPAQUE_PREPASS + +#endif // USE_SHADOW_TO_OPACITY + #ifdef RENDER_DEPTH //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else diff --git a/editor/SCsub b/editor/SCsub index 82a4ecb6c0..7d48e47c9f 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -79,9 +79,6 @@ if env['tools']: env.CommandNoCache('#editor/builtin_fonts.gen.h', flist, run_in_subprocess(editor_builders.make_fonts_header)) env.add_source_files(env.editor_sources, "*.cpp") - env_thirdparty = env.Clone() - env_thirdparty.disable_warnings() - env_thirdparty.add_source_files(env.editor_sources, ["#thirdparty/misc/clipper.cpp"]) SConscript('collada/SCsub') SConscript('doc/SCsub') diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index b2af11fab0..e8490e8729 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -63,8 +63,6 @@ public: ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo); } - //PopupDialog *ke_dialog; - void _fix_node_path(Variant &value) { NodePath np = value; @@ -1215,7 +1213,8 @@ void AnimationTrackEdit::_notification(int p_what) { if (has_focus()) { Color accent = get_color("accent_color", "Editor"); accent.a *= 0.7; - draw_rect(Rect2(Point2(), get_size()), accent, false); + // Offside so the horizontal sides aren't cutoff. + draw_rect(Rect2(Point2(1, 0), get_size() - Size2(1, 0)), accent, false); } Ref<Font> font = get_font("font", "Label"); @@ -2187,6 +2186,9 @@ Variant AnimationTrackEdit::get_drag_data(const Point2 &p_point) { Dictionary drag_data; drag_data["type"] = "animation_track"; + String base_path = animation->track_get_path(track); + base_path = base_path.get_slice(":", 0); // Remove sub-path. + drag_data["group"] = base_path; drag_data["index"] = track; ToolButton *tb = memnew(ToolButton); @@ -2207,8 +2209,18 @@ bool AnimationTrackEdit::can_drop_data(const Point2 &p_point, const Variant &p_d } String type = d["type"]; - if (type != "animation_track") + if (type != "animation_track") { return false; + } + + // Don't allow moving tracks outside their groups. + if (get_editor()->is_grouping_tracks()) { + String base_path = animation->track_get_path(track); + base_path = base_path.get_slice(":", 0); // Remove sub-path. + if (d["group"] != base_path) { + return false; + } + } if (p_point.y < get_size().height / 2) { dropping_at = -1; @@ -2229,8 +2241,18 @@ void AnimationTrackEdit::drop_data(const Point2 &p_point, const Variant &p_data) } String type = d["type"]; - if (type != "animation_track") + if (type != "animation_track") { return; + } + + // Don't allow moving tracks outside their groups. + if (get_editor()->is_grouping_tracks()) { + String base_path = animation->track_get_path(track); + base_path = base_path.get_slice(":", 0); // Remove sub-path. + if (d["group"] != base_path) { + return; + } + } int from_track = d["index"]; @@ -2685,6 +2707,13 @@ void AnimationTrackEditor::_track_remove_request(int p_track) { } } +void AnimationTrackEditor::_track_grab_focus(int p_track) { + + // Don't steal focus if not working with the track editor. + if (Object::cast_to<AnimationTrackEdit>(get_focus_owner())) + track_edits[p_track]->grab_focus(); +} + void AnimationTrackEditor::set_anim_pos(float p_pos) { timeline->set_play_position(p_pos); @@ -3449,14 +3478,14 @@ void AnimationTrackEditor::_update_tracks() { if (use_grouping) { String base_path = animation->track_get_path(i); - base_path = base_path.get_slice(":", 0); // remove subpath + base_path = base_path.get_slice(":", 0); // Remove sub-path. if (!group_sort.has(base_path)) { AnimationTrackEditGroup *g = memnew(AnimationTrackEditGroup); Ref<Texture> icon = get_icon("Node", "EditorIcons"); String name = base_path; String tooltip; - if (root) { + if (root && root->has_node(base_path)) { Node *n = root->get_node(base_path); if (n) { if (has_icon(n->get_class(), "EditorIcons")) { @@ -3656,7 +3685,8 @@ void AnimationTrackEditor::_update_step(double p_new_step) { step->set_block_signals(true); undo_redo->commit_action(); step->set_block_signals(false); - emit_signal("animation_step_changed", step_value); + emit_signal("animation_step_changed", p_new_step); + animation->_change_notify("step"); } void AnimationTrackEditor::_update_length(double p_new_len) { @@ -3665,17 +3695,18 @@ void AnimationTrackEditor::_update_length(double p_new_len) { } void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) { - if (p_to_track >= track_edits.size()) { - p_to_track = track_edits.size() - 1; - } - - if (p_from_track == p_to_track) + if (p_from_track == p_to_track || p_from_track == p_to_track - 1) { return; + } _clear_selection(); undo_redo->create_action(TTR("Rearrange Tracks")); - undo_redo->add_do_method(animation.ptr(), "track_swap", p_from_track, p_to_track); - undo_redo->add_undo_method(animation.ptr(), "track_swap", p_to_track, p_from_track); + undo_redo->add_do_method(animation.ptr(), "track_move_to", p_from_track, p_to_track); + // Take into account that the position of the tracks that come after the one removed will change. + int to_track_real = p_to_track > p_from_track ? p_to_track - 1 : p_to_track; + undo_redo->add_undo_method(animation.ptr(), "track_move_to", to_track_real, p_to_track > p_from_track ? p_from_track : p_from_track + 1); + undo_redo->add_do_method(this, "_track_grab_focus", to_track_real); + undo_redo->add_undo_method(this, "_track_grab_focus", p_from_track); undo_redo->commit_action(); } @@ -4877,10 +4908,20 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) { } void AnimationTrackEditor::_view_group_toggle() { + _update_tracks(); view_group->set_icon(get_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons")); } +bool AnimationTrackEditor::is_grouping_tracks() { + + if (!view_group) { + return false; + } + + return !view_group->is_pressed(); +} + void AnimationTrackEditor::_selection_changed() { if (selected_filter->is_pressed()) { @@ -4927,11 +4968,11 @@ void AnimationTrackEditor::_bind_methods() { ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update); ClassDB::bind_method("_timeline_changed", &AnimationTrackEditor::_timeline_changed); ClassDB::bind_method("_track_remove_request", &AnimationTrackEditor::_track_remove_request); + ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus); ClassDB::bind_method("_name_limit_changed", &AnimationTrackEditor::_name_limit_changed); ClassDB::bind_method("_update_scroll", &AnimationTrackEditor::_update_scroll); ClassDB::bind_method("_update_tracks", &AnimationTrackEditor::_update_tracks); ClassDB::bind_method("_update_step", &AnimationTrackEditor::_update_step); - ClassDB::bind_method("_update_length", &AnimationTrackEditor::_update_length); ClassDB::bind_method("_dropped_track", &AnimationTrackEditor::_dropped_track); ClassDB::bind_method("_add_track", &AnimationTrackEditor::_add_track); ClassDB::bind_method("_new_track_node_selected", &AnimationTrackEditor::_new_track_node_selected); @@ -4992,7 +5033,6 @@ AnimationTrackEditor::AnimationTrackEditor() { timeline->connect("name_limit_changed", this, "_name_limit_changed"); timeline->connect("track_added", this, "_add_track"); timeline->connect("value_changed", this, "_timeline_value_changed"); - timeline->connect("length_changed", this, "_update_length"); scroll = memnew(ScrollContainer); timeline_vbox->add_child(scroll); @@ -5027,7 +5067,6 @@ AnimationTrackEditor::AnimationTrackEditor() { scroll->set_enable_v_scroll(true); track_vbox->add_constant_override("separation", 0); - //timeline_vbox->add_child(memnew(HSeparator)); HBoxContainer *bottom_hb = memnew(HBoxContainer); add_child(bottom_hb); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index a69659642c..c64f663b3b 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -325,6 +325,7 @@ class AnimationTrackEditor : public VBoxContainer { void _name_limit_changed(); void _timeline_changed(float p_new_pos, bool p_drag); void _track_remove_request(int p_track); + void _track_grab_focus(int p_track); UndoRedo *undo_redo; @@ -513,6 +514,7 @@ public: float get_moving_selection_offset() const; bool is_snap_enabled(); float snap_time(float p_value); + bool is_grouping_tracks(); MenuButton *get_edit_menu(); AnimationTrackEditor(); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index ac42f15f7f..604a050fcd 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -38,7 +38,7 @@ #include "editor_settings.h" #include "scene/gui/box_container.h" -void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) { +void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_select_type) { type_list.clear(); ClassDB::get_class_list(&type_list); @@ -93,14 +93,7 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) { if (saved_size != Rect2()) { popup(saved_size); } else { - - Size2 popup_size = Size2(900, 700) * editor_get_scale(); - Size2 window_size = get_viewport_rect().size; - - popup_size.x = MIN(window_size.x * 0.8, popup_size.x); - popup_size.y = MIN(window_size.y * 0.8, popup_size.y); - - popup_centered(popup_size); + popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8); } if (p_dont_clear) { @@ -116,6 +109,7 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) { is_replace_mode = p_replace_mode; if (p_replace_mode) { + select_type(p_select_type); set_title(vformat(TTR("Change %s Type"), base_type)); get_ok()->set_text(TTR("Change")); } else { @@ -258,6 +252,27 @@ bool CreateDialog::_is_class_disabled_by_feature_profile(const StringName &p_cla return false; } +void CreateDialog::select_type(const String &p_type) { + TreeItem *to_select; + if (search_options_types.has(p_type)) { + to_select = search_options_types[p_type]; + } else { + to_select = search_options->get_root(); + } + + // uncollapse from selected type to top level + // TODO: should this be in tree? + TreeItem *cur = to_select; + while (cur) { + cur->set_collapsed(false); + cur = cur->get_parent(); + } + + to_select->select(0); + + search_options->scroll_to_item(to_select); +} + void CreateDialog::_update_search() { search_options->clear(); @@ -269,7 +284,7 @@ void CreateDialog::_update_search() { _parse_fs(EditorFileSystem::get_singleton()->get_filesystem()); */ - HashMap<String, TreeItem *> types; + search_options_types.clear(); TreeItem *root = search_options->create_item(); EditorData &ed = EditorNode::get_editor_data(); @@ -307,7 +322,7 @@ void CreateDialog::_update_search() { } if (search_box->get_text() == "") { - add_type(type, types, root, &to_select); + add_type(type, search_options_types, root, &to_select); } else { bool found = false; @@ -323,7 +338,7 @@ void CreateDialog::_update_search() { } if (found) - add_type(I->get(), types, root, &to_select); + add_type(I->get(), search_options_types, root, &to_select); } if (EditorNode::get_editor_data().get_custom_types().has(type) && ClassDB::is_parent_class(type, base_type)) { @@ -337,12 +352,12 @@ void CreateDialog::_update_search() { if (!show) continue; - if (!types.has(type)) - add_type(type, types, root, &to_select); + if (!search_options_types.has(type)) + add_type(type, search_options_types, root, &to_select); TreeItem *ti; - if (types.has(type)) - ti = types[type]; + if (search_options_types.has(type)) + ti = search_options_types[type]; else ti = search_options->get_root(); diff --git a/editor/create_dialog.h b/editor/create_dialog.h index d859f7cbe4..03c4b25f5c 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -53,6 +53,7 @@ class CreateDialog : public ConfirmationDialog { Button *favorite; LineEdit *search_box; Tree *search_options; + HashMap<String, TreeItem *> search_options_types; bool is_replace_mode; String base_type; String preferred_search_result_type; @@ -82,6 +83,8 @@ class CreateDialog : public ConfirmationDialog { void add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root, TreeItem **to_select); + void select_type(const String &p_type); + Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); @@ -104,7 +107,7 @@ public: void set_preferred_search_result_type(const String &p_preferred_type); String get_preferred_search_result_type(); - void popup_create(bool p_dont_clear, bool p_replace_mode = false); + void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_select_type = "Node"); CreateDialog(); }; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 6751e58bb2..37f148bdbb 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -615,6 +615,7 @@ void EditorExportPlugin::_bind_methods() { BIND_VMETHOD(MethodInfo("_export_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "type"), PropertyInfo(Variant::POOL_STRING_ARRAY, "features"))); BIND_VMETHOD(MethodInfo("_export_begin", PropertyInfo(Variant::POOL_STRING_ARRAY, "features"), PropertyInfo(Variant::BOOL, "is_debug"), PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"))); + BIND_VMETHOD(MethodInfo("_export_end")); } EditorExportPlugin::EditorExportPlugin() { @@ -692,6 +693,10 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } } + //add native icons to non-resource include list + _edit_filter_list(paths, String("*.icns"), false); + _edit_filter_list(paths, String("*.ico"), false); + _edit_filter_list(paths, p_preset->get_include_filter(), false); _edit_filter_list(paths, p_preset->get_exclude_filter(), true); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 90af593166..4ddb28b440 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -844,7 +844,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const bool updated_dir = false; String cd = p_dir->get_path(); - if (current_mtime != p_dir->modified_time || using_fat_32) { + if (current_mtime != p_dir->modified_time || using_fat32_or_exfat) { updated_dir = true; p_dir->modified_time = current_mtime; @@ -2140,8 +2140,8 @@ EditorFileSystem::EditorFileSystem() { if (da->change_dir("res://.import") != OK) { da->make_dir("res://.import"); } - //this should probably also work on Unix and use the string it returns for FAT32 - using_fat_32 = da->get_filesystem_type() == "FAT32"; + // This should probably also work on Unix and use the string it returns for FAT32 or exFAT + using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT"); memdelete(da); scan_total = 0; diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 8943706202..72d9489f21 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -237,7 +237,7 @@ class EditorFileSystem : public Node { static Error _resource_import(const String &p_path); - bool using_fat_32; //workaround for projects in FAT32 filesystem (pendrives, most of the time) + bool using_fat32_or_exfat; // Workaround for projects in FAT32 or exFAT filesystem (pendrives, most of the time) void _find_group_files(EditorFileSystemDirectory *efd, Map<String, Vector<String> > &group_files, Set<String> &groups_to_reimport); diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index 5b16b8f6d5..cddabbc4e4 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -228,7 +228,7 @@ void editor_register_fonts(Ref<Theme> p_theme) { p_theme->set_font("doc", "EditorFonts", df_doc); p_theme->set_font("doc_title", "EditorFonts", df_doc_title); - MAKE_SOURCE_FONT(df_doc_code, int(EDITOR_DEF("text_editor/help/help_source_font_size", 14)) * EDSCALE); + MAKE_SOURCE_FONT(df_doc_code, int(EDITOR_GET("text_editor/help/help_source_font_size")) * EDSCALE); p_theme->set_font("doc_source", "EditorFonts", df_doc_code); // Ruler font diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 907d43b26f..90604a36f1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1921,6 +1921,12 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { file->popup_centered_ratio(); } break; + case FILE_QUICK_OPEN: { + + quick_open->popup_dialog("Resource", true); + quick_open->set_title(TTR("Quick Open...")); + + } break; case FILE_QUICK_OPEN_SCENE: { quick_open->popup_dialog("PackedScene", true); @@ -2454,14 +2460,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case SETTINGS_MANAGE_FEATURE_PROFILES: { - Size2 popup_size = Size2(900, 800) * editor_get_scale(); - Size2 window_size = get_viewport()->get_size(); - - popup_size.x = MIN(window_size.x * 0.8, popup_size.x); - popup_size.y = MIN(window_size.y * 0.8, popup_size.y); - - feature_profile_manager->popup_centered(popup_size); - + feature_profile_manager->popup_centered_clamped(Size2(900, 800) * EDSCALE, 0.8); } break; case SETTINGS_TOGGLE_FULLSCREEN: { @@ -5702,6 +5701,7 @@ EditorNode::EditorNode() { p->add_separator(); p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT); p->add_separator(); + p->add_shortcut(ED_SHORTCUT("editor/quick_open", TTR("Quick Open..."), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_O), FILE_QUICK_OPEN); p->add_shortcut(ED_SHORTCUT("editor/quick_open_scene", TTR("Quick Open Scene..."), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCENE); p->add_shortcut(ED_SHORTCUT("editor/quick_open_script", TTR("Quick Open Script..."), KEY_MASK_ALT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCRIPT); p->add_separator(); @@ -6242,7 +6242,6 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(TextureEditorPlugin(this))); add_editor_plugin(memnew(AudioStreamEditorPlugin(this))); add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); - add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); add_editor_plugin(memnew(SkeletonEditorPlugin(this))); add_editor_plugin(memnew(SkeletonIKEditorPlugin(this))); add_editor_plugin(memnew(PhysicalBonePlugin(this))); @@ -6403,7 +6402,7 @@ EditorNode::EditorNode() { ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_F1); ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_F2); ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_F3); //hack needed for script editor F3 search to work :) Assign like this or don't use F3 - ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_F4); + ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_MASK_SHIFT | KEY_F1); #endif ED_SHORTCUT("editor/editor_assetlib", TTR("Open Asset Library")); ED_SHORTCUT("editor/editor_next", TTR("Open the next Editor")); diff --git a/editor/editor_node.h b/editor/editor_node.h index cfe8bf9ec4..6e7b2b2443 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -146,6 +146,7 @@ private: FILE_SAVE_OPTIMIZED, FILE_OPEN_RECENT, FILE_OPEN_OLD_SCENE, + FILE_QUICK_OPEN, FILE_QUICK_OPEN_SCENE, FILE_QUICK_OPEN_SCRIPT, FILE_OPEN_PREV, diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 8af4ee8017..56fc1f87a5 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -400,6 +400,18 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C EditorNode::get_singleton()->get_inspector_dock_addon_area()->add_child(p_control); } break; + case CONTAINER_PROJECT_SETTING_TAB_LEFT: { + + ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(p_control); + ProjectSettingsEditor::get_singleton()->get_tabs()->move_child(p_control, 0); + + } break; + case CONTAINER_PROJECT_SETTING_TAB_RIGHT: { + + ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(p_control); + ProjectSettingsEditor::get_singleton()->get_tabs()->move_child(p_control, 1); + + } break; } } @@ -450,6 +462,12 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati EditorNode::get_singleton()->get_inspector_dock_addon_area()->remove_child(p_control); } break; + case CONTAINER_PROJECT_SETTING_TAB_LEFT: + case CONTAINER_PROJECT_SETTING_TAB_RIGHT: { + + ProjectSettingsEditor::get_singleton()->get_tabs()->remove_child(p_control); + + } break; } } @@ -863,6 +881,8 @@ void EditorPlugin::_bind_methods() { BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_SIDE_RIGHT); BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_BOTTOM); BIND_ENUM_CONSTANT(CONTAINER_PROPERTY_EDITOR_BOTTOM); + BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_LEFT); + BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_RIGHT); BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_UL); BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_BL); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 2fcc487377..ba4df35e66 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -137,7 +137,9 @@ public: CONTAINER_CANVAS_EDITOR_SIDE_LEFT, CONTAINER_CANVAS_EDITOR_SIDE_RIGHT, CONTAINER_CANVAS_EDITOR_BOTTOM, - CONTAINER_PROPERTY_EDITOR_BOTTOM + CONTAINER_PROPERTY_EDITOR_BOTTOM, + CONTAINER_PROJECT_SETTING_TAB_LEFT, + CONTAINER_PROJECT_SETTING_TAB_RIGHT, }; enum DockSlot { diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 173333dac9..2baad8c904 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -71,7 +71,21 @@ Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String &p_ return generate(res, p_size); } -bool EditorResourcePreviewGenerator::should_generate_small_preview() const { +bool EditorResourcePreviewGenerator::generate_small_preview_automatically() const { + + if (get_script_instance() && get_script_instance()->has_method("generate_small_preview_automatically")) { + return get_script_instance()->call("generate_small_preview_automatically"); + } + + return false; +} + +bool EditorResourcePreviewGenerator::can_generate_small_preview() const { + + if (get_script_instance() && get_script_instance()->has_method("can_generate_small_preview")) { + return get_script_instance()->call("can_generate_small_preview"); + } + return false; } @@ -80,6 +94,8 @@ void EditorResourcePreviewGenerator::_bind_methods() { ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles", PropertyInfo(Variant::STRING, "type"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture), "generate", PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::VECTOR2, "size"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture), "generate_from_path", PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), PropertyInfo(Variant::VECTOR2, "size"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "generate_small_preview_automatically")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "can_generate_small_preview")); } EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() { @@ -154,16 +170,27 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref< } r_texture = generated; - if (r_texture.is_valid() && preview_generators[i]->should_generate_small_preview()) { - int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retrieve the default icon size - small_thumbnail_size *= EDSCALE; + int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retrieve the default icon size + small_thumbnail_size *= EDSCALE; + if (preview_generators[i]->can_generate_small_preview()) { + Ref<Texture> generated_small; + if (p_item.resource.is_valid()) { + generated_small = preview_generators[i]->generate(p_item.resource, Vector2(small_thumbnail_size, small_thumbnail_size)); + } else { + generated_small = preview_generators[i]->generate_from_path(p_item.path, Vector2(small_thumbnail_size, small_thumbnail_size)); + } + r_small_texture = generated_small; + } + + if (!r_small_texture.is_valid() && r_texture.is_valid() && preview_generators[i]->generate_small_preview_automatically()) { Ref<Image> small_image = r_texture->get_data(); small_image = small_image->duplicate(); small_image->resize(small_thumbnail_size, small_thumbnail_size, Image::INTERPOLATE_CUBIC); r_small_texture.instance(); r_small_texture->create_from_image(small_image); } + break; } diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index 9b9223a818..e0fd54c924 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -48,7 +48,8 @@ public: virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const; virtual Ref<Texture> generate_from_path(const String &p_path, const Size2 p_size) const; - virtual bool should_generate_small_preview() const; + virtual bool generate_small_preview_automatically() const; + virtual bool can_generate_small_preview() const; EditorResourcePreviewGenerator(); }; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index cb40926ce3..c0dc231ea9 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -268,6 +268,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { String host_lang = OS::get_singleton()->get_locale(); host_lang = TranslationServer::standardize_locale(host_lang); + // Some locales are not properly supported currently in Godot due to lack of font shaping + // (e.g. Arabic or Hindi), so even though we have work in progress translations for them, + // we skip them as they don't render properly. (GH-28577) + const Vector<String> locales_to_skip = String("ar,bn,fa,he,hi,ml,si,ta,te,ur").split(","); + String best; EditorTranslationList *etl = _editor_translations; @@ -275,6 +280,15 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { while (etl->data) { const String &locale = etl->lang; + + // Skip locales which we can't render properly (see above comment). + // Test against language code without regional variants (e.g. ur_PK). + String lang_code = locale.get_slice("_", 0); + if (locales_to_skip.find(lang_code) != -1) { + etl++; + continue; + } + lang_hint += ","; lang_hint += locale; @@ -473,6 +487,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Help _initial_set("text_editor/help/show_help_index", true); + _initial_set("text_editor/help_source_font_size", 14); + hints["text_editor/help/help_source_font_size"] = PropertyInfo(Variant::REAL, "text_editor/help/help_source_font_size", PROPERTY_HINT_RANGE, "10, 50, 1"); /* Editors */ diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index b7e9d36d88..194a131095 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -756,7 +756,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { Ref<Texture> type_icon; Ref<Texture> big_icon; - String tooltip = fname; + String tooltip = fpath; // Select the icons if (!finfo->import_broken) { @@ -2160,6 +2160,18 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) { } } +void FileSystemDock::_tree_rmb_empty(const Vector2 &p_pos) { + // Right click is pressed in the empty space of the tree + path = "res://"; + tree_popup->clear(); + tree_popup->set_size(Size2(1, 1)); + tree_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); + tree_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); + tree_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); + tree_popup->set_position(tree->get_global_position() + p_pos); + tree_popup->popup(); +} + void FileSystemDock::_tree_empty_selected() { tree->deselect_all(); } @@ -2353,6 +2365,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_file_list_rmb_option", "option"), &FileSystemDock::_file_list_rmb_option); ClassDB::bind_method(D_METHOD("_file_list_rmb_select"), &FileSystemDock::_file_list_rmb_select); ClassDB::bind_method(D_METHOD("_file_list_rmb_pressed"), &FileSystemDock::_file_list_rmb_pressed); + ClassDB::bind_method(D_METHOD("_tree_rmb_empty"), &FileSystemDock::_tree_rmb_empty); ClassDB::bind_method(D_METHOD("_file_deleted"), &FileSystemDock::_file_deleted); ClassDB::bind_method(D_METHOD("_folder_deleted"), &FileSystemDock::_folder_deleted); @@ -2485,6 +2498,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { tree->connect("item_activated", this, "_tree_activate_file"); tree->connect("multi_selected", this, "_tree_multi_selected"); tree->connect("item_rmb_selected", this, "_tree_rmb_select"); + tree->connect("empty_rmb", this, "_tree_rmb_empty"); tree->connect("nothing_selected", this, "_tree_empty_selected"); tree->connect("gui_input", this, "_tree_gui_input"); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 9d20544ac2..978235b328 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -236,6 +236,7 @@ private: void _file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths, bool p_display_path_dependent_options = true); void _tree_rmb_select(const Vector2 &p_pos); + void _tree_rmb_empty(const Vector2 &p_pos); void _file_list_rmb_select(int p_item, const Vector2 &p_pos); void _file_list_rmb_pressed(const Vector2 &p_pos); void _tree_empty_selected(); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 11af9fc2eb..e1ab5c62a7 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -367,28 +367,11 @@ FindInFilesDialog::FindInFilesDialog() { Label *filter_label = memnew(Label); filter_label->set_text(TTR("Filters:")); + filter_label->set_tooltip(TTR("Include the files with the following extensions. Add or remove them in ProjectSettings.")); gc->add_child(filter_label); - { - HBoxContainer *hbc = memnew(HBoxContainer); - - // TODO: Unhardcode this. - Vector<String> exts; - exts.push_back("gd"); - if (Engine::get_singleton()->has_singleton("GodotSharp")) - exts.push_back("cs"); - exts.push_back("shader"); - - for (int i = 0; i < exts.size(); ++i) { - CheckBox *cb = memnew(CheckBox); - cb->set_text(exts[i]); - cb->set_pressed(true); - hbc->add_child(cb); - _filters.push_back(cb); - } - - gc->add_child(hbc); - } + _filters_container = memnew(HBoxContainer); + gc->add_child(_filters_container); _find_button = add_button(TTR("Find..."), false, "find"); _find_button->set_disabled(true); @@ -424,11 +407,12 @@ String FindInFilesDialog::get_folder() const { } Set<String> FindInFilesDialog::get_filter() const { + // could check the _filters_preferences but it might not have been generated yet. Set<String> filters; - for (int i = 0; i < _filters.size(); ++i) { - CheckBox *cb = _filters[i]; + for (int i = 0; i < _filters_container->get_child_count(); ++i) { + CheckBox *cb = (CheckBox *)_filters_container->get_child(i); if (cb->is_pressed()) { - filters.insert(_filters[i]->get_text()); + filters.insert(cb->get_text()); } } return filters; @@ -440,6 +424,20 @@ void FindInFilesDialog::_notification(int p_what) { // Doesn't work more than once if not deferred... _search_text_line_edit->call_deferred("grab_focus"); _search_text_line_edit->select_all(); + // Extensions might have changed in the meantime, we clean them and instance them again. + for (int i = 0; i < _filters_container->get_child_count(); i++) { + _filters_container->get_child(i)->queue_delete(); + } + Array exts = ProjectSettings::get_singleton()->get("editor/search_in_file_extensions"); + for (int i = 0; i < exts.size(); ++i) { + CheckBox *cb = memnew(CheckBox); + cb->set_text(exts[i]); + if (!_filters_preferences.has(exts[i])) { + _filters_preferences[exts[i]] = true; + } + cb->set_pressed(_filters_preferences[exts[i]]); + _filters_container->add_child(cb); + } } } } @@ -449,6 +447,10 @@ void FindInFilesDialog::_on_folder_button_pressed() { } void FindInFilesDialog::custom_action(const String &p_action) { + for (int i = 0; i < _filters_container->get_child_count(); ++i) { + CheckBox *cb = (CheckBox *)_filters_container->get_child(i); + _filters_preferences[cb->get_text()] = cb->is_pressed(); + } if (p_action == "find") { emit_signal(SIGNAL_FIND_REQUESTED); hide(); diff --git a/editor/find_in_files.h b/editor/find_in_files.h index 220f8cc136..5f728a104b 100644 --- a/editor/find_in_files.h +++ b/editor/find_in_files.h @@ -31,6 +31,7 @@ #ifndef FIND_IN_FILES_H #define FIND_IN_FILES_H +#include "core/hash_map.h" #include "scene/gui/dialogs.h" // Performs the actual search @@ -88,6 +89,7 @@ private: class LineEdit; class CheckBox; class FileDialog; +class HBoxContainer; // Prompts search parameters class FindInFilesDialog : public AcceptDialog { @@ -120,12 +122,13 @@ private: LineEdit *_search_text_line_edit; LineEdit *_folder_line_edit; - Vector<CheckBox *> _filters; CheckBox *_match_case_checkbox; CheckBox *_whole_words_checkbox; Button *_find_button; Button *_replace_button; FileDialog *_folder_dialog; + HBoxContainer *_filters_container; + HashMap<String, bool> _filters_preferences; }; class Button; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 5ac7bc3bc8..5da731b0a0 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1291,6 +1291,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } String root_type = p_options["nodes/root_type"]; + root_type = root_type.split(" ")[0]; // full root_type is "ClassName (filename.gd)" for a script global class. + + Ref<Script> root_script = NULL; + if (ScriptServer::is_global_class(root_type)) { + root_script = ResourceLoader::load(ScriptServer::get_global_class_path(root_type)); + root_type = ScriptServer::get_global_class_base(root_type); + } if (root_type != "Spatial") { Node *base_node = Object::cast_to<Node>(ClassDB::instance(root_type)); @@ -1303,6 +1310,10 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } } + if (root_script.is_valid()) { + scene->set_script(Variant(root_script)); + } + if (Object::cast_to<Spatial>(scene)) { float root_scale = p_options["nodes/root_scale"]; Object::cast_to<Spatial>(scene)->scale(Vector3(root_scale, root_scale, root_scale)); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 0a9436952b..951e971615 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -54,13 +54,9 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) { track_editor->set_root(NULL); track_editor->show_select_node_warning(true); _update_player(); - //editor->animation_editor_make_visible(false); } } -void AnimationPlayerEditor::_gui_input(Ref<InputEvent> p_event) { -} - void AnimationPlayerEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_PROCESS: { @@ -293,25 +289,40 @@ void AnimationPlayerEditor::_pause_pressed() { //player->set_pause( pause->is_pressed() ); } -void AnimationPlayerEditor::_animation_selected(int p_which) { - if (updating) - return; +String AnimationPlayerEditor::_get_current_animation() const { + // when selecting an animation, the idea is that the only interesting behavior // ui-wise is that it should play/blend the next one if currently playing - String current; if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); + return animation->get_item_text(animation->get_selected()); } - if (current != "") { + return ""; +} - player->set_assigned_animation(current); +void AnimationPlayerEditor::_animation_selected(int p_which) { + + if (updating) + return; + + _current_animation_updated(); +} +void AnimationPlayerEditor::_current_animation_updated() { + + String current = _get_current_animation(); + + if (current != "") { Ref<Animation> anim = player->get_animation(current); + + player->set_assigned_animation(current); { + if (!anim->is_connected("changed", this, "_current_animation_updated")) + anim->connect("changed", this, "_current_animation_updated"); + track_editor->set_animation(anim); Node *root = player->get_node(player->get_root()); if (root) { @@ -679,19 +690,22 @@ Dictionary AnimationPlayerEditor::get_state() const { } void AnimationPlayerEditor::set_state(const Dictionary &p_state) { - if (p_state.has("visible") && p_state["visible"]) { + if (!p_state.has("visible") || !p_state["visible"]) { + return; + } + if (!EditorNode::get_singleton()->get_edited_scene()) { + return; + } - if (!EditorNode::get_singleton()->get_edited_scene()) - return; + if (p_state.has("player")) { Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]); if (Object::cast_to<AnimationPlayer>(n) && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) { player = Object::cast_to<AnimationPlayer>(n); _update_player(); - show(); + editor->make_bottom_panel_item_visible(this); set_process(true); ensure_visibility(); - //EditorNode::get_singleton()->animation_panel_make_visible(true); if (p_state.has("animation")) { String anim = p_state["animation"]; @@ -699,10 +713,10 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { _animation_edit(); } } + } - if (p_state.has("track_editor_state")) { - track_editor->set_state(p_state["track_editor_state"]); - } + if (p_state.has("track_editor_state")) { + track_editor->set_state(p_state["track_editor_state"]); } } @@ -721,17 +735,17 @@ void AnimationPlayerEditor::_animation_edit() { String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); track_editor->set_animation(anim); + Node *root = player->get_node(player->get_root()); if (root) { track_editor->set_root(root); } - } else { - track_editor->set_animation(Ref<Animation>()); track_editor->set_root(NULL); } } + void AnimationPlayerEditor::_dialog_action(String p_file) { switch (current_option) { @@ -881,8 +895,6 @@ void AnimationPlayerEditor::_update_player() { _animation_selected(0); } - //pause->set_pressed(player->is_paused()); - if (animation->get_item_count()) { String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); @@ -910,8 +922,6 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { track_editor->show_select_node_warning(false); } else { track_editor->show_select_node_warning(true); - - //hide(); } } @@ -1068,17 +1078,19 @@ void AnimationPlayerEditor::_list_changed() { _update_player(); } -void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len) { - - frame->set_max(p_len); -} - void AnimationPlayerEditor::_animation_key_editor_anim_step_changed(float p_len) { if (p_len) frame->set_step(p_len); else frame->set_step(0.00001); + + String current = _get_current_animation(); + + if (current != "") { + Ref<Animation> anim = player->get_animation(current); + anim->_change_notify("step"); + } } void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) { @@ -1110,7 +1122,6 @@ void AnimationPlayerEditor::_hide_anim_editors() { track_editor->set_animation(Ref<Animation>()); track_editor->set_root(NULL); track_editor->show_select_node_warning(true); - //editor->animation_editor_make_visible(false); } void AnimationPlayerEditor::_animation_about_to_show_menu() { @@ -1431,6 +1442,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { new_state["show_rulers"] = false; new_state["show_guides"] = false; new_state["show_helpers"] = false; + new_state["show_zoom_control"] = false; // TODO: Save/restore only affected entries CanvasItemEditor::get_singleton()->set_state(new_state); } @@ -1483,7 +1495,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { if (valid) { player->seek(pos, true); get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials - values_backup.update_skeletons(); // Needed for Skeletons + values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D) VS::get_singleton()->viewport_set_active(onion.captures[cidx], true); VS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); @@ -1547,7 +1559,6 @@ void AnimationPlayerEditor::_pin_pressed() { void AnimationPlayerEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &AnimationPlayerEditor::_gui_input); ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationPlayerEditor::_node_removed); ClassDB::bind_method(D_METHOD("_play_pressed"), &AnimationPlayerEditor::_play_pressed); ClassDB::bind_method(D_METHOD("_play_from_pressed"), &AnimationPlayerEditor::_play_from_pressed); @@ -1557,6 +1568,7 @@ void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_autoplay_pressed"), &AnimationPlayerEditor::_autoplay_pressed); ClassDB::bind_method(D_METHOD("_pause_pressed"), &AnimationPlayerEditor::_pause_pressed); ClassDB::bind_method(D_METHOD("_animation_selected"), &AnimationPlayerEditor::_animation_selected); + ClassDB::bind_method(D_METHOD("_current_animation_updated"), &AnimationPlayerEditor::_current_animation_updated); ClassDB::bind_method(D_METHOD("_animation_name_edited"), &AnimationPlayerEditor::_animation_name_edited); ClassDB::bind_method(D_METHOD("_animation_new"), &AnimationPlayerEditor::_animation_new); ClassDB::bind_method(D_METHOD("_animation_rename"), &AnimationPlayerEditor::_animation_rename); @@ -1576,7 +1588,6 @@ void AnimationPlayerEditor::_bind_methods() { //ClassDB::bind_method(D_METHOD("_editor_load_all"),&AnimationPlayerEditor::_editor_load_all); ClassDB::bind_method(D_METHOD("_list_changed"), &AnimationPlayerEditor::_list_changed); ClassDB::bind_method(D_METHOD("_animation_key_editor_seek"), &AnimationPlayerEditor::_animation_key_editor_seek); - ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_len_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_len_changed); ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_step_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_step_changed); ClassDB::bind_method(D_METHOD("_hide_anim_editors"), &AnimationPlayerEditor::_hide_anim_editors); ClassDB::bind_method(D_METHOD("_animation_duplicate"), &AnimationPlayerEditor::_animation_duplicate); @@ -1610,12 +1621,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay player = NULL; - Label *l; - - /*l= memnew( Label ); - l->set_text("Animation Player:"); - add_child(l);*/ - HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); @@ -1640,10 +1645,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay play_from->set_tooltip(TTR("Play selected animation from current pos. (D)")); hb->add_child(play_from); - //pause = memnew( Button ); - //pause->set_toggle_mode(true); - //hb->add_child(pause); - frame = memnew(SpinBox); hb->add_child(frame); frame->set_custom_minimum_size(Size2(60, 0)); @@ -1669,7 +1670,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay tool_anim = memnew(MenuButton); tool_anim->set_flat(false); - //tool_anim->set_flat(false); tool_anim->set_tooltip(TTR("Animation Tools")); tool_anim->set_text(TTR("Animation")); tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/new_animation", TTR("New")), TOOL_NEW_ANIM); @@ -1700,9 +1700,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay hb->add_child(autoplay); autoplay->set_tooltip(TTR("Autoplay on Load")); - //tool_anim->get_popup()->add_separator(); - //tool_anim->get_popup()->add_item("Edit Anim Resource",TOOL_PASTE_ANIM); - hb->add_child(memnew(VSeparator)); track_editor = memnew(AnimationTrackEditor); @@ -1752,10 +1749,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay VBoxContainer *vb = memnew(VBoxContainer); name_dialog->add_child(vb); - l = memnew(Label); - l->set_text(TTR("Animation Name:")); - vb->add_child(l); - name_title = l; + name_title = memnew(Label(TTR("Animation Name:"))); + vb->add_child(name_title); name = memnew(LineEdit); vb->add_child(name); @@ -1774,7 +1769,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay blend_editor.dialog->set_hide_on_ok(true); VBoxContainer *blend_vb = memnew(VBoxContainer); blend_editor.dialog->add_child(blend_vb); - //blend_editor.dialog->set_child_rect(blend_vb); blend_editor.tree = memnew(Tree); blend_editor.tree->set_columns(2); blend_vb->add_margin_child(TTR("Blend Times:"), blend_editor.tree, true); @@ -1792,8 +1786,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay play_bw->connect("pressed", this, "_play_bw_pressed"); play_bw_from->connect("pressed", this, "_play_bw_from_pressed"); stop->connect("pressed", this, "_stop_pressed"); - //pause->connect("pressed", this,"_pause_pressed"); - //frame->connect("text_entered", this,"_seek_frame_changed"); animation->connect("item_selected", this, "_animation_selected", Vector<Variant>(), true); @@ -1809,7 +1801,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay add_child(track_editor); track_editor->set_v_size_flags(SIZE_EXPAND_FILL); track_editor->connect("timeline_changed", this, "_animation_key_editor_seek"); - track_editor->connect("animation_len_changed", this, "_animation_key_editor_anim_len_changed"); track_editor->connect("animation_step_changed", this, "_animation_key_editor_anim_step_changed"); _update_player(); @@ -1897,11 +1888,6 @@ void AnimationPlayerEditorPlugin::make_visible(bool p_visible) { editor->make_bottom_panel_item_visible(anim_editor); anim_editor->set_process(true); anim_editor->ensure_visibility(); - //editor->animation_panel_make_visible(true); - } else { - - //anim_editor->hide(); - //anim_editor->set_idle_process(false); } } @@ -1910,16 +1896,7 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin(EditorNode *p_node) { editor = p_node; anim_editor = memnew(AnimationPlayerEditor(editor, this)); anim_editor->set_undo_redo(editor->get_undo_redo()); - editor->add_bottom_panel_item(TTR("Animation"), anim_editor); - /* - editor->get_viewport()->add_child(anim_editor); - anim_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); - anim_editor->set_anchor( MARGIN_TOP, Control::ANCHOR_END); - anim_editor->set_margin( MARGIN_TOP, 75 ); - anim_editor->set_anchor( MARGIN_RIGHT, Control::ANCHOR_END); - anim_editor->set_margin( MARGIN_RIGHT, 0 );*/ - anim_editor->hide(); } AnimationPlayerEditorPlugin::~AnimationPlayerEditorPlugin() { diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index c6ab6c5e30..b1026b5b9f 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -97,8 +97,6 @@ class AnimationPlayerEditor : public VBoxContainer { Button *play_from; Button *play_bw; Button *play_bw_from; - - //Button *pause; Button *autoplay; MenuButton *tool_anim; @@ -173,7 +171,9 @@ class AnimationPlayerEditor : public VBoxContainer { void _autoplay_pressed(); void _stop_pressed(); void _pause_pressed(); + String _get_current_animation() const; void _animation_selected(int p_which); + void _current_animation_updated(); void _animation_new(); void _animation_rename(); void _animation_name_edited(); @@ -229,7 +229,6 @@ class AnimationPlayerEditor : public VBoxContainer { protected: void _notification(int p_what); - void _gui_input(Ref<InputEvent> p_event); void _node_removed(Node *p_node); static void _bind_methods(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 126cd20c53..92cc12d931 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4009,6 +4009,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { show_rulers = !show_rulers; int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS); view_menu->get_popup()->set_item_checked(idx, show_rulers); + _update_scrollbars(); viewport->update(); } break; case SHOW_GUIDES: { @@ -4321,6 +4322,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { Map<Node *, Object *> &selection = editor_selection->get_selection(); + undo_redo->create_action(TTR("Create Custom Bone(s) from Node(s)")); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { Node2D *n2d = Object::cast_to<Node2D>(E->key()); @@ -4330,19 +4332,24 @@ void CanvasItemEditor::_popup_callback(int p_op) { continue; if (!n2d->get_parent_item()) continue; + if (n2d->has_meta("_edit_bone_") && (bool)n2d->get_meta("_edit_bone_") == true) + continue; - n2d->set_meta("_edit_bone_", true); - if (!skeleton_show_bones) - skeleton_menu->get_popup()->activate_item(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES)); + undo_redo->add_do_method(n2d, "set_meta", "_edit_bone_", true); + undo_redo->add_undo_method(n2d, "remove_meta", "_edit_bone_"); } - _queue_update_bone_list(); - viewport->update(); + undo_redo->add_do_method(this, "_queue_update_bone_list"); + undo_redo->add_undo_method(this, "_queue_update_bone_list"); + undo_redo->add_do_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "update"); + undo_redo->commit_action(); } break; case SKELETON_CLEAR_BONES: { Map<Node *, Object *> &selection = editor_selection->get_selection(); + undo_redo->create_action(TTR("Clear Bones")); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { Node2D *n2d = Object::cast_to<Node2D>(E->key()); @@ -4350,40 +4357,47 @@ void CanvasItemEditor::_popup_callback(int p_op) { continue; if (!n2d->is_visible_in_tree()) continue; + if (!n2d->has_meta("_edit_bone_")) + continue; - n2d->set_meta("_edit_bone_", Variant()); - if (!skeleton_show_bones) - skeleton_menu->get_popup()->activate_item(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES)); + undo_redo->add_do_method(n2d, "remove_meta", "_edit_bone_"); + undo_redo->add_undo_method(n2d, "set_meta", "_edit_bone_", n2d->get_meta("_edit_bone_")); } - _queue_update_bone_list(); - viewport->update(); + undo_redo->add_do_method(this, "_queue_update_bone_list"); + undo_redo->add_undo_method(this, "_queue_update_bone_list"); + undo_redo->add_do_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "update"); + undo_redo->commit_action(); } break; case SKELETON_SET_IK_CHAIN: { List<Node *> selection = editor_selection->get_selected_node_list(); + undo_redo->create_action(TTR("Make IK Chain")); 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()) continue; - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) continue; + if (canvas_item->has_meta("_edit_ik_") && (bool)canvas_item->get_meta("_edit_ik_") == true) + continue; - canvas_item->set_meta("_edit_ik_", true); - if (!skeleton_show_bones) - skeleton_menu->get_popup()->activate_item(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES)); + undo_redo->add_do_method(canvas_item, "set_meta", "_edit_ik_", true); + undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_ik_"); } - - viewport->update(); + undo_redo->add_do_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "update"); + undo_redo->commit_action(); } break; case SKELETON_CLEAR_IK_CHAIN: { Map<Node *, Object *> &selection = editor_selection->get_selection(); + undo_redo->create_action(TTR("Clear IK Chain")); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *n2d = Object::cast_to<CanvasItem>(E->key()); @@ -4391,12 +4405,15 @@ void CanvasItemEditor::_popup_callback(int p_op) { continue; if (!n2d->is_visible_in_tree()) continue; + if (!n2d->has_meta("_edit_ik_")) + continue; - n2d->set_meta("_edit_ik_", Variant()); - if (!skeleton_show_bones) - skeleton_menu->get_popup()->activate_item(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES)); + undo_redo->add_do_method(n2d, "remove_meta", "_edit_ik_"); + undo_redo->add_undo_method(n2d, "set_meta", "_edit_ik_", n2d->get_meta("_edit_ik_")); } - viewport->update(); + undo_redo->add_do_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "update"); + undo_redo->commit_action(); } break; } @@ -4478,6 +4495,7 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method("_draw_viewport", &CanvasItemEditor::_draw_viewport); ClassDB::bind_method("_gui_input_viewport", &CanvasItemEditor::_gui_input_viewport); ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed); + ClassDB::bind_method("_queue_update_bone_list", &CanvasItemEditor::_update_bone_list); ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list); ClassDB::bind_method("_tree_changed", &CanvasItemEditor::_tree_changed); ClassDB::bind_method("_selection_changed", &CanvasItemEditor::_selection_changed); @@ -4514,6 +4532,7 @@ Dictionary CanvasItemEditor::get_state() const { state["show_rulers"] = show_rulers; state["show_guides"] = show_guides; state["show_helpers"] = show_helpers; + state["show_zoom_control"] = zoom_hb->is_visible(); state["show_edit_locks"] = show_edit_locks; state["snap_rotation"] = snap_rotation; state["snap_relative"] = snap_relative; @@ -4524,6 +4543,7 @@ Dictionary CanvasItemEditor::get_state() const { void CanvasItemEditor::set_state(const Dictionary &p_state) { + bool update_scrollbars = false; Dictionary state = p_state; if (state.has("zoom")) { zoom = p_state["zoom"]; @@ -4532,7 +4552,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { if (state.has("ofs")) { view_offset = p_state["ofs"]; previous_update_view_offset = view_offset; - _update_scrollbars(); + update_scrollbars = true; } if (state.has("grid_offset")) { @@ -4620,6 +4640,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { show_rulers = state["show_rulers"]; int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS); view_menu->get_popup()->set_item_checked(idx, show_rulers); + update_scrollbars = true; } if (state.has("show_guides")) { @@ -4640,6 +4661,11 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { view_menu->get_popup()->set_item_checked(idx, show_edit_locks); } + if (state.has("show_zoom_control")) { + // This one is not user-controllable, but instrumentable + zoom_hb->set_visible(state["show_zoom_control"]); + } + if (state.has("snap_rotation")) { snap_rotation = state["snap_rotation"]; int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_ROTATION); @@ -4664,6 +4690,9 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones); } + if (update_scrollbars) { + _update_scrollbars(); + } viewport->update(); } diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 58d7968723..28e57ac48a 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -78,7 +78,7 @@ bool EditorTexturePreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "Texture"); } -bool EditorTexturePreviewPlugin::should_generate_small_preview() const { +bool EditorTexturePreviewPlugin::generate_small_preview_automatically() const { return true; } @@ -186,7 +186,7 @@ Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 p EditorImagePreviewPlugin::EditorImagePreviewPlugin() { } -bool EditorImagePreviewPlugin::should_generate_small_preview() const { +bool EditorImagePreviewPlugin::generate_small_preview_automatically() const { return true; } //////////////////////////////////////////////////////////////////////////// @@ -250,7 +250,7 @@ Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size2 return ptex; } -bool EditorBitmapPreviewPlugin::should_generate_small_preview() const { +bool EditorBitmapPreviewPlugin::generate_small_preview_automatically() const { return true; } @@ -317,7 +317,7 @@ bool EditorMaterialPreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "Material"); //any material } -bool EditorMaterialPreviewPlugin::should_generate_small_preview() const { +bool EditorMaterialPreviewPlugin::generate_small_preview_automatically() const { return true; } diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index ed2c003a0a..16b1f3082b 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -39,7 +39,7 @@ class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorTexturePreviewPlugin, EditorResourcePreviewGenerator) public: virtual bool handles(const String &p_type) const; - virtual bool should_generate_small_preview() const; + virtual bool generate_small_preview_automatically() const; virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const; EditorTexturePreviewPlugin(); @@ -49,7 +49,7 @@ class EditorImagePreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorImagePreviewPlugin, EditorResourcePreviewGenerator) public: virtual bool handles(const String &p_type) const; - virtual bool should_generate_small_preview() const; + virtual bool generate_small_preview_automatically() const; virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const; EditorImagePreviewPlugin(); @@ -59,7 +59,7 @@ class EditorBitmapPreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorBitmapPreviewPlugin, EditorResourcePreviewGenerator) public: virtual bool handles(const String &p_type) const; - virtual bool should_generate_small_preview() const; + virtual bool generate_small_preview_automatically() const; virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const; EditorBitmapPreviewPlugin(); @@ -98,7 +98,7 @@ protected: public: virtual bool handles(const String &p_type) const; - virtual bool should_generate_small_preview() const; + virtual bool generate_small_preview_automatically() const; virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const; EditorMaterialPreviewPlugin(); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 828abef9a9..839c9483d7 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1558,7 +1558,15 @@ struct _ScriptEditorItemData { bool operator<(const _ScriptEditorItemData &id) const { - return category == id.category ? sort_key < id.sort_key : category < id.category; + if (category == id.category) { + if (sort_key == id.sort_key) { + return index < id.index; + } else { + return sort_key < id.sort_key; + } + } else { + return category < id.category; + } } }; @@ -3047,7 +3055,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { members_overview->set_custom_minimum_size(Size2(0, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing members_overview->set_v_size_flags(SIZE_EXPAND_FILL); members_overview->set_allow_rmb_select(true); - members_overview->set_drag_forwarding(this); help_overview = memnew(ItemList); overview_vbox->add_child(help_overview); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index ff0959c8a1..f66ae0465f 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1772,7 +1772,7 @@ void ScriptTextEditor::register_editor() { #ifdef OSX_ENABLED ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_ALT | KEY_MASK_SHIFT | KEY_SPACE); #else - ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_SHIFT | KEY_F1); + ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_ALT | KEY_F1); #endif ScriptEditor::register_create_script_editor_function(create_editor); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 95a70f2ae5..60f1248ace 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -3510,10 +3510,14 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed camera->make_current(); surface->set_focus_mode(FOCUS_ALL); + VBoxContainer *vbox = memnew(VBoxContainer); + surface->add_child(vbox); + vbox->set_position(Point2(10, 10) * EDSCALE); + view_menu = memnew(MenuButton); view_menu->set_flat(false); - surface->add_child(view_menu); - view_menu->set_position(Point2(10, 10) * EDSCALE); + vbox->add_child(view_menu); + view_menu->set_h_size_flags(0); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM); @@ -3566,9 +3570,9 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT); preview_camera = memnew(CheckBox); - preview_camera->set_position(Point2(10, 38) * EDSCALE); // Below the 'view_menu' MenuButton. preview_camera->set_text(TTR("Preview")); - surface->add_child(preview_camera); + vbox->add_child(preview_camera); + preview_camera->set_h_size_flags(0); preview_camera->hide(); preview_camera->connect("toggled", this, "_toggle_camera_preview"); previewing = NULL; diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index 7642bfaf04..2deb2090e2 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -327,7 +327,14 @@ void SpriteEditor::_convert_to_mesh_2d_node() { MeshInstance2D *mesh_instance = memnew(MeshInstance2D); mesh_instance->set_mesh(mesh); - EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(node, mesh_instance); + + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Convert to Mesh2D")); + ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, mesh_instance, true, false); + ur->add_do_reference(mesh_instance); + ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", mesh_instance, node, false, false); + ur->add_undo_reference(node); + ur->commit_action(); } void SpriteEditor::_convert_to_polygon_2d_node() { @@ -379,7 +386,13 @@ void SpriteEditor::_convert_to_polygon_2d_node() { polygon_2d_instance->set_polygon(polygon); polygon_2d_instance->set_polygons(polys); - EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(node, polygon_2d_instance); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Convert to Polygon2D")); + ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, polygon_2d_instance, true, false); + ur->add_do_reference(polygon_2d_instance); + ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", polygon_2d_instance, node, false, false); + ur->add_undo_reference(node); + ur->commit_action(); } void SpriteEditor::_create_collision_polygon_2d_node() { @@ -396,7 +409,12 @@ void SpriteEditor::_create_collision_polygon_2d_node() { CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D); collision_polygon_2d_instance->set_polygon(outline); - _add_as_sibling_or_child(node, collision_polygon_2d_instance); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Create CollisionPolygon2D Sibling")); + ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance); + ur->add_do_reference(collision_polygon_2d_instance); + ur->add_undo_method(node != this->get_tree()->get_edited_scene_root() ? node->get_parent() : this->get_tree()->get_edited_scene_root(), "remove_child", collision_polygon_2d_instance); + ur->commit_action(); } } @@ -425,15 +443,20 @@ void SpriteEditor::_create_light_occluder_2d_node() { LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D); light_occluder_2d_instance->set_occluder_polygon(polygon); - _add_as_sibling_or_child(node, light_occluder_2d_instance); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Create LightOccluder2D Sibling")); + ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance); + ur->add_do_reference(light_occluder_2d_instance); + ur->add_undo_method(node != this->get_tree()->get_edited_scene_root() ? node->get_parent() : this->get_tree()->get_edited_scene_root(), "remove_child", light_occluder_2d_instance); + ur->commit_action(); } } -void SpriteEditor::_add_as_sibling_or_child(Node2D *p_own_node, Node2D *p_new_node) { +void SpriteEditor::_add_as_sibling_or_child(Node *p_own_node, Node *p_new_node) { // Can't make sibling if own node is scene root if (p_own_node != this->get_tree()->get_edited_scene_root()) { p_own_node->get_parent()->add_child(p_new_node, true); - p_new_node->set_transform(p_own_node->get_transform()); + Object::cast_to<Node2D>(p_new_node)->set_transform(Object::cast_to<Node2D>(p_own_node)->get_transform()); } else { p_own_node->add_child(p_new_node, true); } @@ -534,6 +557,7 @@ void SpriteEditor::_bind_methods() { ClassDB::bind_method("_debug_uv_draw", &SpriteEditor::_debug_uv_draw); ClassDB::bind_method("_update_mesh_data", &SpriteEditor::_update_mesh_data); ClassDB::bind_method("_create_node", &SpriteEditor::_create_node); + ClassDB::bind_method("_add_as_sibling_or_child", &SpriteEditor::_add_as_sibling_or_child); } SpriteEditor::SpriteEditor() { diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_editor_plugin.h index 460f5a5707..81be4a19e9 100644 --- a/editor/plugins/sprite_editor_plugin.h +++ b/editor/plugins/sprite_editor_plugin.h @@ -84,7 +84,7 @@ class SpriteEditor : public Control { void _create_collision_polygon_2d_node(); void _create_light_occluder_2d_node(); - void _add_as_sibling_or_child(Node2D *p_own_node, Node2D *p_new_node); + void _add_as_sibling_or_child(Node *p_own_node, Node *p_new_node); protected: void _node_removed(Node *p_node); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 672d5d3496..5b67d259ba 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -879,11 +879,9 @@ ThemeEditor::ThemeEditor() { void ThemeEditorPlugin::edit(Object *p_node) { if (Object::cast_to<Theme>(p_node)) { - theme_editor->show(); theme_editor->edit(Object::cast_to<Theme>(p_node)); } else { theme_editor->edit(Ref<Theme>()); - theme_editor->hide(); } } @@ -898,11 +896,11 @@ void ThemeEditorPlugin::make_visible(bool p_visible) { theme_editor->set_process(true); button->show(); editor->make_bottom_panel_item_visible(theme_editor); - } else { theme_editor->set_process(false); if (theme_editor->is_visible_in_tree()) editor->hide_bottom_panel(); + button->hide(); } } diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 29a54f815d..772e47ac3a 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -760,7 +760,7 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p r.position += (r.size + Vector2(spacing, spacing)) * offset; } Size2 sc = p_xform.get_scale(); - + Size2 cell_size = node->get_cell_size(); Rect2 rect = Rect2(); rect.position = node->map_to_world(p_point) + node->get_cell_draw_offset(); @@ -770,62 +770,25 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p rect.size = r.size; } - if (rect.size.y > rect.size.x) { - if ((p_flip_h && (p_flip_v || p_transpose)) || (p_flip_v && !p_transpose)) - tile_ofs.y += rect.size.y - rect.size.x; - } else if (rect.size.y < rect.size.x) { - if ((p_flip_v && (p_flip_h || p_transpose)) || (p_flip_h && !p_transpose)) - tile_ofs.x += rect.size.x - rect.size.y; - } - if (p_transpose) { SWAP(tile_ofs.x, tile_ofs.y); + rect.position.x += cell_size.x / 2 - rect.size.y / 2; + rect.position.y += cell_size.y / 2 - rect.size.x / 2; + } else { + rect.position += cell_size / 2 - rect.size / 2; } + if (p_flip_h) { sc.x *= -1.0; tile_ofs.x *= -1.0; } + if (p_flip_v) { sc.y *= -1.0; tile_ofs.y *= -1.0; } - if (node->get_tile_origin() == TileMap::TILE_ORIGIN_TOP_LEFT) { - - rect.position += tile_ofs; - } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_BOTTOM_LEFT) { - Size2 cell_size = node->get_cell_size(); - - rect.position += tile_ofs; - - if (p_transpose) { - if (p_flip_h) - rect.position.x -= cell_size.x; - else - rect.position.x += cell_size.x; - } else { - if (p_flip_v) - rect.position.y -= cell_size.y; - else - rect.position.y += cell_size.y; - } - - } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_CENTER) { - Size2 cell_size = node->get_cell_size(); - - rect.position += tile_ofs; - - if (p_flip_h) - rect.position.x -= cell_size.x / 2; - else - rect.position.x += cell_size.x / 2; - - if (p_flip_v) - rect.position.y -= cell_size.y / 2; - else - rect.position.y += cell_size.y / 2; - } - + rect.position += tile_ofs; rect.position = p_xform.xform(rect.position); rect.size *= sc; diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 93c6614841..a00be3c0ce 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -372,6 +372,15 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tool_editmode[EDITMODE_COLLISION]->set_pressed(true); edit_mode = EDITMODE_COLLISION; + tool_editmode[EDITMODE_REGION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_region", TTR("Region Mode"), KEY_1)); + tool_editmode[EDITMODE_COLLISION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_collision", TTR("Collision Mode"), KEY_2)); + tool_editmode[EDITMODE_OCCLUSION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_occlusion", TTR("Occlusion Mode"), KEY_3)); + tool_editmode[EDITMODE_NAVIGATION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_navigation", TTR("Navigation Mode"), KEY_4)); + tool_editmode[EDITMODE_BITMASK]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_bitmask", TTR("Bitmask Mode"), KEY_5)); + tool_editmode[EDITMODE_PRIORITY]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_priority", TTR("Priority Mode"), KEY_6)); + tool_editmode[EDITMODE_ICON]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_icon", TTR("Icon Mode"), KEY_7)); + tool_editmode[EDITMODE_Z_INDEX]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_z_index", TTR("Z Index Mode"), KEY_8)); + main_vb->add_child(tool_hb); separator_editmode = memnew(HSeparator); main_vb->add_child(separator_editmode); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index cdb1dbfdc4..a1b903576e 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "visual_shader_editor_plugin.h" #include "core/io/resource_loader.h" +#include "core/math/math_defs.h" #include "core/os/input.h" #include "core/os/keyboard.h" #include "core/project_settings.h" @@ -68,6 +69,7 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { } } visual_shader = Ref<VisualShader>(p_visual_shader); + visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE); } else { visual_shader.unref(); } @@ -701,7 +703,7 @@ void VisualShaderEditor::_update_graph() { expression_box->set_context_menu_enabled(false); expression_box->set_show_line_numbers(true); - expression_box->connect("text_changed", this, "_set_expression", varray(nodes[n_i]), CONNECT_DEFERRED); + expression_box->connect("focus_exited", this, "_expression_focus_out", varray(expression_box, nodes[n_i])); } if (!uniform.is_valid()) { @@ -915,7 +917,7 @@ void VisualShaderEditor::_remove_output_port(int p_node, int p_port) { undo_redo->commit_action(); } -void VisualShaderEditor::_set_expression(int p_node) { +void VisualShaderEditor::_expression_focus_out(Object *text_edit, int p_node) { VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node); @@ -923,24 +925,19 @@ void VisualShaderEditor::_set_expression(int p_node) { return; } - TextEdit *expression_box = Object::cast_to<TextEdit>(node->get_control(0)); + TextEdit *expression_box = Object::cast_to<TextEdit>(text_edit); + + if (node->get_expression() == expression_box->get_text()) + return; undo_redo->create_action(TTR("Set expression")); undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text()); undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression()); - undo_redo->add_do_method(this, "_start_rebuild_timer", 1.0); + undo_redo->add_do_method(this, "_rebuild"); undo_redo->add_undo_method(this, "_rebuild"); undo_redo->commit_action(); } -void VisualShaderEditor::_start_rebuild_timer(int p_delay) { - build_timer->start(p_delay); -} - -void VisualShaderEditor::_rebuild_timeout() { - _rebuild(); -} - void VisualShaderEditor::_rebuild() { EditorNode::get_singleton()->get_log()->clear(); visual_shader->rebuild(); @@ -984,9 +981,9 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p box_size.x = gn->get_size().x; } } - box_size.x -= text_box->get_margin(Margin::MARGIN_LEFT); + box_size.x -= text_box->get_margin(MARGIN_LEFT); box_size.x -= 28 * EDSCALE; - box_size.y -= text_box->get_margin(Margin::MARGIN_TOP); + box_size.y -= text_box->get_margin(MARGIN_TOP); box_size.y -= 28 * EDSCALE; text_box->set_custom_minimum_size(Size2(box_size.x, box_size.y)); text_box->set_size(Size2(1, 1)); @@ -1143,6 +1140,13 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type)); ERR_FAIL_COND(!vsn); + VisualShaderNodeScalarConstant *constant = Object::cast_to<VisualShaderNodeScalarConstant>(vsn); + + if (constant) { + if ((int)add_options[p_idx].value != -1) + constant->set_constant(add_options[p_idx].value); + } + if (p_op_idx != -1) { VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsn); @@ -1797,9 +1801,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_rebuild", &VisualShaderEditor::_rebuild); ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph); ClassDB::bind_method("_update_options_menu", &VisualShaderEditor::_update_options_menu); - ClassDB::bind_method("_start_rebuild_timer", &VisualShaderEditor::_start_rebuild_timer); - ClassDB::bind_method("_set_expression", &VisualShaderEditor::_set_expression); - ClassDB::bind_method("_rebuild_timeout", &VisualShaderEditor::_rebuild_timeout); + ClassDB::bind_method("_expression_focus_out", &VisualShaderEditor::_expression_focus_out); ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node); ClassDB::bind_method("_node_dragged", &VisualShaderEditor::_node_dragged); ClassDB::bind_method("_connection_request", &VisualShaderEditor::_connection_request); @@ -1994,6 +1996,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR)); // BOOLEAN + add_options.push_back(AddOption("If", "Conditional", "Functions", "VisualShaderNodeIf", TTR("Returns an associated vector if the provided scalars are equal, greater or less."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Switch", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated vector if the provided boolean value is true or false."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("BooleanConstant", "Conditional", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); @@ -2107,6 +2110,19 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("ScalarFunc", "Scalar", "Common", "VisualShaderNodeScalarFunc", TTR("Scalar function."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("ScalarOp", "Scalar", "Common", "VisualShaderNodeScalarOp", TTR("Scalar operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + //CONSTANTS + + add_options.push_back(AddOption("E", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("E constant (2.718282). Represents the base of the natural logarithm."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_E)); + add_options.push_back(AddOption("Epsilon", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Epsilon constant (0.00001). Smallest possible scalar number."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, CMP_EPSILON)); + add_options.push_back(AddOption("Phi", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Phi constant (1.618034). Golden ratio."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, 1.618034f)); + add_options.push_back(AddOption("Pi/4", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Pi/4 constant (0.785398) or 45 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI / 4)); + add_options.push_back(AddOption("Pi/2", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Pi/2 constant (1.570796) or 90 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI / 2)); + add_options.push_back(AddOption("Pi", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Pi constant (3.141593) or 180 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI)); + add_options.push_back(AddOption("Tau", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Tau constant (6.283185) or 360 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_TAU)); + add_options.push_back(AddOption("Sqrt2", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Sqrt2 constant (1.414214). Square root of 2."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_SQRT2)); + + // FUNCTIONS + add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeScalarFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("ACos", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("ACosH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -2287,13 +2303,6 @@ VisualShaderEditor::VisualShaderEditor() { add_child(property_editor); property_editor->connect("variant_changed", this, "_port_edited"); - - // BUILD TIMER FOR EXPRESSION NODES - - build_timer = memnew(Timer); - add_child(build_timer); - build_timer->connect("timeout", this, "_rebuild_timeout"); - build_timer->set_one_shot(true); } void VisualShaderEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index b1cf2e7244..1b009b61d5 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -84,8 +84,6 @@ class VisualShaderEditor : public VBoxContainer { LineEdit *node_filter; RichTextLabel *node_desc; - Timer *build_timer; - void _tools_menu_option(int p_idx); void _show_members_dialog(bool at_mouse_pos); @@ -103,8 +101,9 @@ class VisualShaderEditor : public VBoxContainer { int mode; int return_type; int func; + float value; - AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1, int p_func = -1) { + AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1) { name = p_name; type = p_type; category = p_category; @@ -114,9 +113,10 @@ class VisualShaderEditor : public VBoxContainer { return_type = p_return_type; mode = p_mode; func = p_func; + value = p_value; } - AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1, int p_func = -1) { + AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1) { name = p_name; type = p_type; category = p_category; @@ -126,6 +126,7 @@ class VisualShaderEditor : public VBoxContainer { return_type = p_return_type; mode = p_mode; func = p_func; + value = p_value; } }; @@ -184,10 +185,7 @@ class VisualShaderEditor : public VBoxContainer { void _change_output_port_type(int p_type, int p_node, int p_port); void _change_output_port_name(const String &p_text, Object *line_edit, int p_node, int p_port); - void _start_rebuild_timer(int p_delay); - - void _set_expression(int p_node); - void _rebuild_timeout(); + void _expression_focus_out(Object *text_edit, int p_node); void _set_node_size(int p_type, int p_node, const Size2 &p_size); void _node_resized(const Vector2 &p_new_size, int p_type, int p_node); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index e1950c666c..ee78b240a4 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -88,14 +88,7 @@ void ProjectExportDialog::popup_export() { if (saved_size != Rect2()) { popup(saved_size); } else { - - Size2 popup_size = Size2(900, 700) * editor_get_scale(); - Size2 window_size = get_viewport_rect().size; - - popup_size.x = MIN(window_size.x * 0.8, popup_size.x); - popup_size.y = MIN(window_size.y * 0.8, popup_size.y); - - popup_centered(popup_size); + popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8); } } @@ -571,9 +564,8 @@ void ProjectExportDialog::_duplicate_preset() { Ref<EditorExportPreset> preset = current->get_platform()->create_preset(); ERR_FAIL_COND(!preset.is_valid()); - String name = current->get_name() + "" + itos(1); + String name = current->get_name() + " (copy)"; bool make_runnable = true; - int attempt = 2; while (true) { bool valid = true; @@ -592,8 +584,7 @@ void ProjectExportDialog::_duplicate_preset() { if (valid) break; - attempt++; - name = current->get_name() + " " + itos(attempt); + name += " (copy)"; } preset->set_name(name); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 6de4330493..b0baf954d2 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1627,40 +1627,28 @@ void ProjectManager::_show_project(const String &p_path) { OS::get_singleton()->shell_open(String("file://") + p_path); } -void ProjectManager::_scan_dir(DirAccess *da, float pos, float total, List<String> *r_projects) { - - List<String> subdirs; +void ProjectManager::_scan_dir(const String &path, List<String> *r_projects) { + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + da->change_dir(path); da->list_dir_begin(); String n = da->get_next(); while (n != String()) { if (da->current_is_dir() && !n.begins_with(".")) { - subdirs.push_front(n); + _scan_dir(da->get_current_dir().plus_file(n), r_projects); } else if (n == "project.godot") { r_projects->push_back(da->get_current_dir()); } n = da->get_next(); } da->list_dir_end(); - int m = 0; - for (List<String>::Element *E = subdirs.front(); E; E = E->next()) { - - da->change_dir(E->get()); - - float slice = total / subdirs.size(); - _scan_dir(da, pos + slice * m, slice, r_projects); - da->change_dir(".."); - m++; - } + memdelete(da); } void ProjectManager::_scan_begin(const String &p_base) { print_line("Scanning projects at: " + p_base); List<String> projects; - DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - da->change_dir(p_base); - _scan_dir(da, 0, 1, &projects); - memdelete(da); + _scan_dir(p_base, &projects); print_line("Found " + itos(projects.size()) + " projects."); for (List<String>::Element *E = projects.front(); E; E = E->next()) { @@ -2166,6 +2154,19 @@ ProjectManager::ProjectManager() { Button *cancel = memnew(Button); cancel->set_text(TTR("Exit")); cancel->set_custom_minimum_size(Size2(100, 1) * EDSCALE); + +#ifndef OSX_ENABLED + // Pressing Command + Q quits the Project Manager + // This is handled by the platform implementation on macOS, + // so only define the shortcut on other platforms + InputEventKey *quit_key = memnew(InputEventKey); + quit_key->set_command(true); + quit_key->set_scancode(KEY_Q); + ShortCut *quit_shortcut = memnew(ShortCut); + quit_shortcut->set_shortcut(quit_key); + cancel->set_shortcut(quit_shortcut); +#endif + cc->add_child(cancel); cancel->connect("pressed", this, "_exit_dialog"); vb->add_child(cc); diff --git a/editor/project_manager.h b/editor/project_manager.h index 382e9fc8fb..fa878e75a6 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -106,7 +106,7 @@ class ProjectManager : public Control { void _on_project_created(const String &dir); void _on_projects_updated(); void _update_scroll_position(const String &dir); - void _scan_dir(DirAccess *da, float pos, float total, List<String> *r_projects); + void _scan_dir(const String &path, List<String> *r_projects); void _install_project(const String &p_zip_path, const String &p_title); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 71bddebcf5..872f8fcd2c 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -793,15 +793,9 @@ void ProjectSettingsEditor::popup_project_settings() { if (saved_size != Rect2()) { popup(saved_size); } else { - - Size2 popup_size = Size2(900, 700) * editor_get_scale(); - Size2 window_size = get_viewport_rect().size; - - popup_size.x = MIN(window_size.x * 0.8, popup_size.x); - popup_size.y = MIN(window_size.y * 0.8, popup_size.y); - - popup_centered(popup_size); + popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8); } + globals_editor->update_category_list(); _update_translations(); autoload_settings->update_autoload(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 1f5300e351..ce2795f37b 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -31,6 +31,7 @@ #include "scene_tree_dock.h" #include "core/io/resource_saver.h" +#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/project_settings.h" @@ -347,7 +348,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (!profile_allow_editing) { break; } - create_dialog->popup_create(false, true); + create_dialog->popup_create(false, true, scene_tree->get_selected()->get_class()); } break; case TOOL_ATTACH_SCRIPT: { @@ -517,6 +518,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { editor_data->get_undo_redo().add_do_method(editor_selection, "clear"); Node *dupsingle = NULL; + List<Node *> editable_children; for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { @@ -529,6 +531,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Map<const Node *, Node *> duplimap; Node *dup = node->duplicate_from_editor(duplimap); + if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node)) + editable_children.push_back(dup); + ERR_CONTINUE(!dup); if (selection.size() == 1) @@ -561,6 +566,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (dupsingle) editor->push_item(dupsingle); + for (List<Node *>::Element *E = editable_children.front(); E; E = E->next()) + _toggle_editable_children(E->get()); + } break; case TOOL_REPARENT: { @@ -796,7 +804,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { editable_instance_remove_dialog->popup_centered_minsize(); break; } - _toggle_editable_children(); + _toggle_editable_children(node); } } } break; @@ -1612,30 +1620,27 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { _update_script_button(); } -void SceneTreeDock::_toggle_editable_children() { +void SceneTreeDock::_toggle_editable_children_from_selection() { + List<Node *> selection = editor_selection->get_selected_node_list(); List<Node *>::Element *e = selection.front(); - if (e) { - Node *node = e->get(); - if (node) { - bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node); - int editable_item_idx = menu->get_item_idx_from_text(TTR("Editable Children")); - int placeholder_item_idx = menu->get_item_idx_from_text(TTR("Load As Placeholder")); - editable = !editable; + if (e) { + _toggle_editable_children(e->get()); + } +} - EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, editable); +void SceneTreeDock::_toggle_editable_children(Node *p_node) { - menu->set_item_checked(editable_item_idx, editable); - if (editable) { - node->set_scene_instance_load_placeholder(false); - menu->set_item_checked(placeholder_item_idx, false); - } + if (p_node) { + bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node); + EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(p_node, editable); + if (editable) + p_node->set_scene_instance_load_placeholder(false); - SpatialEditor::get_singleton()->update_all_gizmos(node); + SpatialEditor::get_singleton()->update_all_gizmos(p_node); - scene_tree->update_tree(); - } + scene_tree->update_tree(); } } @@ -1853,7 +1858,7 @@ void SceneTreeDock::_create() { scene_tree->get_scene_tree()->call_deferred("grab_focus"); } -void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties) { +void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties, bool p_remove_old) { Node *n = p_node; Node *newnode = p_by_node; @@ -1917,16 +1922,20 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop Node *c = newnode->get_child(i); c->call("set_transform", c->call("get_transform")); } - editor_data->get_undo_redo().clear_history(); + //p_remove_old was added to support undo + if (p_remove_old) + editor_data->get_undo_redo().clear_history(); newnode->set_name(newname); editor->push_item(newnode); - memdelete(n); + if (p_remove_old) { + memdelete(n); - while (to_erase.front()) { - memdelete(to_erase.front()->get()); - to_erase.pop_front(); + while (to_erase.front()) { + memdelete(to_erase.front()->get()); + to_erase.pop_front(); + } } } @@ -1942,13 +1951,7 @@ void SceneTreeDock::set_selected(Node *p_node, bool p_emit_selected) { void SceneTreeDock::import_subscene() { - Size2 popup_size = Size2(500, 800) * editor_get_scale(); - Size2 window_size = get_viewport_rect().size; - - popup_size.x = MIN(window_size.x * 0.8, popup_size.x); - popup_size.y = MIN(window_size.y * 0.8, popup_size.y); - - import_subscene_dialog->popup_centered(popup_size); + import_subscene_dialog->popup_centered_clamped(Size2(500, 800) * EDSCALE, 0.8); } void SceneTreeDock::_import_subscene() { @@ -2132,7 +2135,7 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) { int to_pos = -1; _normalize_drop(to_node, to_pos, p_type); - _do_reparent(to_node, to_pos, nodes, true); + _do_reparent(to_node, to_pos, nodes, !Input::get_singleton()->is_key_pressed(KEY_SHIFT)); } void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) { @@ -2481,7 +2484,7 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_input"), &SceneTreeDock::_input); ClassDB::bind_method(D_METHOD("_nodes_drag_begin"), &SceneTreeDock::_nodes_drag_begin); ClassDB::bind_method(D_METHOD("_delete_confirm"), &SceneTreeDock::_delete_confirm); - ClassDB::bind_method(D_METHOD("_toggle_editable_children"), &SceneTreeDock::_toggle_editable_children); + ClassDB::bind_method(D_METHOD("_toggle_editable_children_from_selection"), &SceneTreeDock::_toggle_editable_children_from_selection); ClassDB::bind_method(D_METHOD("_node_prerenamed"), &SceneTreeDock::_node_prerenamed); ClassDB::bind_method(D_METHOD("_import_subscene"), &SceneTreeDock::_import_subscene); ClassDB::bind_method(D_METHOD("_selection_changed"), &SceneTreeDock::_selection_changed); @@ -2501,6 +2504,7 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_feature_profile_changed"), &SceneTreeDock::_feature_profile_changed); ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance); + ClassDB::bind_method(D_METHOD("replace_node"), &SceneTreeDock::replace_node); ADD_SIGNAL(MethodInfo("remote_tree_selected")); } @@ -2649,7 +2653,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel editable_instance_remove_dialog = memnew(ConfirmationDialog); add_child(editable_instance_remove_dialog); - editable_instance_remove_dialog->connect("confirmed", this, "_toggle_editable_children"); + editable_instance_remove_dialog->connect("confirmed", this, "_toggle_editable_children_from_selection"); import_subscene_dialog = memnew(EditorSubScene); add_child(import_subscene_dialog); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index e66525d721..9f9e93f2df 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -172,7 +172,8 @@ class SceneTreeDock : public VBoxContainer { void _delete_confirm(); - void _toggle_editable_children(); + void _toggle_editable_children_from_selection(); + void _toggle_editable_children(Node *p_node); void _node_prerenamed(Node *p_node, const String &p_new_name); @@ -243,7 +244,7 @@ public: void show_tab_buttons(); void hide_tab_buttons(); - void replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties = true); + void replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties = true, bool p_remove_old = true); void open_script_dialog(Node *p_for_node); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 76feaedb1a..5ca3448693 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -379,6 +379,12 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { } if (!keep) { + if (editor_selection) { + Node *n = get_node(item->get_metadata(0)); + if (n) { + editor_selection->remove_node(n); + } + } memdelete(item); return false; } else { @@ -471,6 +477,17 @@ void SceneTreeEditor::_node_removed(Node *p_node) { emit_signal("node_selected"); } } + +void SceneTreeEditor::_node_renamed(Node *p_node) { + + emit_signal("node_renamed"); + + if (!tree_dirty) { + MessageQueue::get_singleton()->push_call(this, "_update_tree"); + tree_dirty = true; + } +} + void SceneTreeEditor::_update_tree() { if (!is_inside_tree()) { @@ -594,6 +611,7 @@ void SceneTreeEditor::_notification(int p_what) { get_tree()->connect("tree_changed", this, "_tree_changed"); get_tree()->connect("node_removed", this, "_node_removed"); + get_tree()->connect("node_renamed", this, "_node_renamed"); get_tree()->connect("node_configuration_warning_changed", this, "_warning_changed"); tree->connect("item_collapsed", this, "_cell_collapsed"); @@ -604,6 +622,7 @@ void SceneTreeEditor::_notification(int p_what) { get_tree()->disconnect("tree_changed", this, "_tree_changed"); get_tree()->disconnect("node_removed", this, "_node_removed"); + get_tree()->disconnect("node_renamed", this, "_node_renamed"); tree->disconnect("item_collapsed", this, "_cell_collapsed"); get_tree()->disconnect("node_configuration_warning_changed", this, "_warning_changed"); } break; @@ -685,12 +704,6 @@ void SceneTreeEditor::_rename_node(ObjectID p_node, const String &p_name) { n->set_name(p_name); item->set_metadata(0, n->get_path()); item->set_text(0, p_name); - emit_signal("node_renamed"); - - if (!tree_dirty) { - MessageQueue::get_singleton()->push_call(this, "_update_tree"); - tree_dirty = true; - } } void SceneTreeEditor::_renamed() { @@ -1025,6 +1038,7 @@ void SceneTreeEditor::_bind_methods() { ClassDB::bind_method("_tree_changed", &SceneTreeEditor::_tree_changed); ClassDB::bind_method("_update_tree", &SceneTreeEditor::_update_tree); ClassDB::bind_method("_node_removed", &SceneTreeEditor::_node_removed); + ClassDB::bind_method("_node_renamed", &SceneTreeEditor::_node_renamed); ClassDB::bind_method("_selected_changed", &SceneTreeEditor::_selected_changed); ClassDB::bind_method("_deselect_items", &SceneTreeEditor::_deselect_items); ClassDB::bind_method("_renamed", &SceneTreeEditor::_renamed); diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 9158c4aa48..1c14da0d3a 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -78,6 +78,7 @@ class SceneTreeEditor : public Control { void _update_tree(); void _tree_changed(); void _node_removed(Node *p_node); + void _node_renamed(Node *p_node); TreeItem *_find(TreeItem *p_node, const NodePath &p_path); void _notification(int p_what); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index a661c2cfc3..621ab039f4 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -262,7 +262,7 @@ void ScriptEditorDebugger::_scene_tree_folded(Object *obj) { return; ObjectID id = item->get_metadata(0); - if (item->is_collapsed()) { + if (unfold_cache.has(id)) { unfold_cache.erase(id); } else { unfold_cache.insert(id); diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index 68a1117364..b4643231d7 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -98,14 +98,7 @@ void EditorSettingsDialog::popup_edit_settings() { if (saved_size != Rect2()) { popup(saved_size); } else { - - Size2 popup_size = Size2(900, 700) * editor_get_scale(); - Size2 window_size = get_viewport_rect().size; - - popup_size.x = MIN(window_size.x * 0.8, popup_size.x); - popup_size.y = MIN(window_size.y * 0.8, popup_size.y); - - popup_centered(popup_size); + popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8); } _focus_current_search_box(); diff --git a/main/main.cpp b/main/main.cpp index da77962c8a..63ce165d80 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -204,7 +204,8 @@ void finalize_physics() { void Main::print_help(const char *p_binary) { - print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - https://godotengine.org"); + print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); + OS::get_singleton()->print("Free and open source software under the terms of the MIT license.\n"); OS::get_singleton()->print("(c) 2007-2019 Juan Linietsky, Ariel Manzur.\n"); OS::get_singleton()->print("(c) 2014-2019 Godot Engine contributors.\n"); OS::get_singleton()->print("\n"); @@ -247,6 +248,7 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(").\n"); OS::get_singleton()->print("\n"); +#ifndef SERVER_ENABLED OS::get_singleton()->print("Display options:\n"); OS::get_singleton()->print(" -f, --fullscreen Request fullscreen mode.\n"); OS::get_singleton()->print(" -m, --maximized Request a maximized window.\n"); @@ -257,14 +259,15 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" --low-dpi Force low-DPI mode (macOS and Windows only).\n"); OS::get_singleton()->print(" --no-window Disable window creation (Windows only). Useful together with --script.\n"); OS::get_singleton()->print("\n"); +#endif OS::get_singleton()->print("Debug options:\n"); OS::get_singleton()->print(" -d, --debug Debug (local stdout debugger).\n"); OS::get_singleton()->print(" -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n"); OS::get_singleton()->print(" --profiling Enable profiling in the script debugger.\n"); OS::get_singleton()->print(" --remote-debug <address> Remote debug (<host/IP>:<port> address).\n"); -#ifdef DEBUG_ENABLED - OS::get_singleton()->print(" --debug-collisions Show collisions shapes when running the scene.\n"); +#if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED) + OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n"); OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n"); #endif OS::get_singleton()->print(" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).\n"); @@ -429,6 +432,49 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph print_line(get_full_version_string()); goto error; + } else if (I->get() == "-v" || I->get() == "--verbose") { // verbose output + + OS::get_singleton()->_verbose_stdout = true; + } else if (I->get() == "--quiet") { // quieter output + + quiet_stdout = true; + + } else if (I->get() == "--audio-driver") { // audio driver + + if (I->next()) { + + audio_driver = I->next()->get(); + N = I->next()->next(); + } else { + OS::get_singleton()->print("Missing audio driver argument, aborting.\n"); + goto error; + } + + } else if (I->get() == "--video-driver") { // force video driver + + if (I->next()) { + + video_driver = I->next()->get(); + N = I->next()->next(); + } else { + OS::get_singleton()->print("Missing video driver argument, aborting.\n"); + goto error; + } +#ifndef SERVER_ENABLED + } else if (I->get() == "-f" || I->get() == "--fullscreen") { // force fullscreen + + init_fullscreen = true; + } else if (I->get() == "-m" || I->get() == "--maximized") { // force maximized window + + init_maximized = true; + video_mode.maximized = true; + + } else if (I->get() == "-w" || I->get() == "--windowed") { // force windowed window + + init_windowed = true; + } else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window + + init_always_on_top = true; } else if (I->get() == "--resolution") { // force resolution if (I->next()) { @@ -459,6 +505,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->print("Missing resolution argument, aborting.\n"); goto error; } + } else if (I->get() == "--position") { // set window position if (I->next()) { @@ -483,29 +530,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph goto error; } - } else if (I->get() == "-m" || I->get() == "--maximized") { // force maximized window - - init_maximized = true; - video_mode.maximized = true; - } else if (I->get() == "-w" || I->get() == "--windowed") { // force windowed window + } else if (I->get() == "--low-dpi") { // force low DPI (macOS only) - init_windowed = true; - } else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window + force_lowdpi = true; + } else if (I->get() == "--no-window") { // disable window creation (Windows only) - init_always_on_top = true; + OS::get_singleton()->set_no_window_mode(true); +#endif } else if (I->get() == "--profiling") { // enable profiling use_debug_profiler = true; - } else if (I->get() == "--video-driver") { // force video driver - - if (I->next()) { - video_driver = I->next()->get(); - N = I->next()->next(); - } else { - OS::get_singleton()->print("Missing video driver argument, aborting.\n"); - goto error; - } } else if (I->get() == "-l" || I->get() == "--language") { // language if (I->next()) { @@ -516,9 +551,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->print("Missing language argument, aborting.\n"); goto error; } - } else if (I->get() == "--low-dpi") { // force low DPI (macOS only) - force_lowdpi = true; } else if (I->get() == "--remote-fs") { // remote filesystem if (I->next()) { @@ -555,22 +588,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->print("Missing render thread mode argument, aborting.\n"); goto error; } - - } else if (I->get() == "--audio-driver") { // audio driver - - if (I->next()) { - - audio_driver = I->next()->get(); - N = I->next()->next(); - } else { - OS::get_singleton()->print("Missing audio driver argument, aborting.\n"); - goto error; - } - - } else if (I->get() == "-f" || I->get() == "--fullscreen") { // force fullscreen - - //video_mode.fullscreen=false; - init_fullscreen = true; #ifdef TOOLS_ENABLED } else if (I->get() == "-e" || I->get() == "--editor") { // starts editor @@ -583,14 +600,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph auto_build_solutions = true; editor = true; #endif - } else if (I->get() == "--no-window") { // disable window creation, Windows only - - OS::get_singleton()->set_no_window_mode(true); - } else if (I->get() == "--quiet") { // quieter output - - quiet_stdout = true; - } else if (I->get() == "-v" || I->get() == "--verbose") { // verbose output - OS::get_singleton()->_verbose_stdout = true; } else if (I->get() == "--path") { // set path of project to start or edit if (I->next()) { @@ -674,7 +683,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "-d" || I->get() == "--debug") { debug_mode = "local"; -#ifdef DEBUG_ENABLED +#if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED) } else if (I->get() == "--debug-collisions") { debug_collisions = true; } else if (I->get() == "--debug-navigation") { @@ -1083,6 +1092,9 @@ error: Error Main::setup2(Thread::ID p_main_tid_override) { + // Print engine name and version + print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); + if (p_main_tid_override) { Thread::_main_thread_id = p_main_tid_override; } @@ -1189,6 +1201,12 @@ Error Main::setup2(Thread::ID p_main_tid_override) { GLOBAL_DEF("application/config/icon", String()); ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp")); + GLOBAL_DEF("application/config/macos_native_icon", String()); + ProjectSettings::get_singleton()->set_custom_property_info("application/config/macos_native_icon", PropertyInfo(Variant::STRING, "application/config/macos_native_icon", PROPERTY_HINT_FILE, "*.icns")); + + GLOBAL_DEF("application/config/windows_native_icon", String()); + ProjectSettings::get_singleton()->set_custom_property_info("application/config/windows_native_icon", PropertyInfo(Variant::STRING, "application/config/windows_native_icon", PROPERTY_HINT_FILE, "*.ico")); + InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); if (id) { if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) { @@ -1739,8 +1757,24 @@ bool Main::start() { ERR_FAIL_COND_V(!scene, false) sml->add_current_scene(scene); +#ifdef OSX_ENABLED + String mac_iconpath = GLOBAL_DEF("application/config/macos_native_icon", "Variant()"); + if (mac_iconpath != "") { + OS::get_singleton()->set_native_icon(mac_iconpath); + hasicon = true; + } +#endif + +#ifdef WINDOWS_ENABLED + String win_iconpath = GLOBAL_DEF("application/config/windows_native_icon", "Variant()"); + if (win_iconpath != "") { + OS::get_singleton()->set_native_icon(win_iconpath); + hasicon = true; + } +#endif + String iconpath = GLOBAL_DEF("application/config/icon", "Variant()"); - if (iconpath != "") { + if ((iconpath != "") && (!hasicon)) { Ref<Image> icon; icon.instance(); if (ImageLoader::load_image(iconpath, icon) == OK) { diff --git a/methods.py b/methods.py index 11efd68ce4..af20619416 100644 --- a/methods.py +++ b/methods.py @@ -61,6 +61,7 @@ def update_version(module_version_string=""): f.write("#define VERSION_BUILD \"" + str(build_name) + "\"\n") f.write("#define VERSION_MODULE_CONFIG \"" + str(version.module_config) + module_version_string + "\"\n") f.write("#define VERSION_YEAR " + str(version.year) + "\n") + f.write("#define VERSION_WEBSITE \"" + str(version.website) + "\"\n") f.close() # NOTE: It is safe to generate this file here, since this is still executed serially diff --git a/modules/gdnative/gdnative/dictionary.cpp b/modules/gdnative/gdnative/dictionary.cpp index 2c6c9e2de2..fff3fc3625 100644 --- a/modules/gdnative/gdnative/dictionary.cpp +++ b/modules/gdnative/gdnative/dictionary.cpp @@ -55,6 +55,15 @@ void GDAPI godot_dictionary_destroy(godot_dictionary *p_self) { self->~Dictionary(); } +godot_dictionary GDAPI godot_dictionary_duplicate(const godot_dictionary *p_self, const godot_bool p_deep) { + const Dictionary *self = (const Dictionary *)p_self; + godot_dictionary res; + Dictionary *val = (Dictionary *)&res; + memnew_placement(val, Dictionary); + *val = self->duplicate(p_deep); + return res; +} + godot_int GDAPI godot_dictionary_size(const godot_dictionary *p_self) { const Dictionary *self = (const Dictionary *)p_self; return self->size(); diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp index 8f0d5a2db4..ac4d5a86b2 100644 --- a/modules/gdnative/gdnative/variant.cpp +++ b/modules/gdnative/gdnative/variant.cpp @@ -518,7 +518,7 @@ void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_varia const Variant *a = (const Variant *)p_a; const Variant *b = (const Variant *)p_b; Variant *ret = (Variant *)r_ret; - Variant::evaluate(op, a, b, *ret, *r_valid); + Variant::evaluate(op, *a, *b, *ret, *r_valid); } #ifdef __cplusplus diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 93f4d75330..8afe988102 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -11,7 +11,24 @@ "major": 1, "minor": 1 }, - "next": null, + "next": { + "type": "CORE", + "version": { + "major": 1, + "minor": 2 + }, + "next": null, + "api": [ + { + "name": "godot_dictionary_duplicate", + "return_type": "godot_dictionary", + "arguments": [ + ["const godot_dictionary *", "p_self"], + ["const godot_bool", "p_deep"] + ] + } + ] + }, "api": [ { "name": "godot_color_to_abgr32", diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h index 14e35b4692..483cd9c4e3 100644 --- a/modules/gdnative/include/gdnative/dictionary.h +++ b/modules/gdnative/include/gdnative/dictionary.h @@ -63,6 +63,8 @@ void GDAPI godot_dictionary_new(godot_dictionary *r_dest); void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src); void GDAPI godot_dictionary_destroy(godot_dictionary *p_self); +godot_dictionary GDAPI godot_dictionary_duplicate(const godot_dictionary *p_self, const godot_bool p_deep); + godot_int GDAPI godot_dictionary_size(const godot_dictionary *p_self); godot_bool GDAPI godot_dictionary_empty(const godot_dictionary *p_self); diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 060a9d6c91..62b65fe96b 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -56,6 +56,10 @@ static bool _is_hex_symbol(CharType c) { return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } +static bool _is_bin_symbol(CharType c) { + return (c == '0' || c == '1'); +} + Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) { Map<int, TextEdit::HighlighterInfo> color_map; @@ -76,6 +80,7 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ bool in_member_variable = false; bool in_node_path = false; bool is_hex_notation = false; + bool is_bin_notation = false; bool expect_type = false; Color keyword_color; Color color; @@ -118,14 +123,26 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ is_hex_notation = false; } + // disallow anything not a 0 or 1 + if (is_bin_notation && (_is_bin_symbol(str[j]))) { + is_number = true; + } else if (is_bin_notation) { + is_bin_notation = false; + is_number = false; + } else { + is_bin_notation = false; + } + // check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation - if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) { + if ((str[j] == '.' || str[j] == 'x' || str[j] == 'b' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) { is_number = true; is_symbol = false; is_char = false; if (str[j] == 'x' && str[j - 1] == '0') { is_hex_notation = true; + } else if (str[j] == 'b' && str[j - 1] == '0') { + is_bin_notation = true; } } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index d91e32249e..fa80c31984 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2054,7 +2054,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context if (!p_only_functions) { List<PropertyInfo> members; - tmp.get_property_list(&members); + p_base.value.get_property_list(&members); for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { if (String(E->get().name).find("/") == -1) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index de15f939ce..9590009a54 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3369,7 +3369,7 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) { return; } - if (!p_class->constant_expressions.empty() || !p_class->subclasses.empty() || !p_class->functions.empty() || !p_class->variables.empty()) { + if (!p_class->constant_expressions.empty() || !p_class->subclasses.empty() || !p_class->functions.empty() || !p_class->variables.empty() || p_class->classname_used) { _set_error("'extends' must be used before anything else."); return; @@ -3506,6 +3506,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _set_error("'class_name' syntax: 'class_name <UniqueName>'"); return; } + if (p_class->classname_used) { + _set_error("'class_name' already used for this class."); + return; + } + + p_class->classname_used = true; p_class->name = tokenizer->get_token_identifier(1); @@ -5248,6 +5254,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) { if (base_script.is_valid()) { String ident = base; + Ref<GDScript> find_subclass = base_script; for (int i = extend_iter; i < p_class->extends_class.size(); i++) { @@ -5257,7 +5264,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) { if (base_script->get_subclasses().has(subclass)) { - base_script = base_script->get_subclasses()[subclass]; + find_subclass = base_script->get_subclasses()[subclass]; } else if (base_script->get_constants().has(subclass)) { Ref<GDScript> new_base_class = base_script->get_constants()[subclass]; @@ -5265,7 +5272,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) { _set_error("Constant is not a class: " + ident, p_class->line); return; } - base_script = new_base_class; + find_subclass = new_base_class; } else { _set_error("Could not find subclass: " + ident, p_class->line); @@ -5273,7 +5280,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) { } } - script = base_script; + script = find_subclass; } else if (!base_class) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 809bff8f20..5e4de11357 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -149,6 +149,7 @@ public: bool tool; StringName name; bool extends_used; + bool classname_used; StringName extends_file; Vector<StringName> extends_class; DataType base_type; @@ -198,6 +199,7 @@ public: tool = false; type = TYPE_CLASS; extends_used = false; + classname_used = false; end_line = -1; owner = NULL; } diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index b8048fb5dd..a93d1ceebb 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -376,6 +376,11 @@ static bool _is_hex(CharType c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } +static bool _is_bin(CharType c) { + + return (c == '0' || c == '1'); +} + void GDScriptTokenizerText::_make_token(Token p_type) { TokenData &tk = tk_rb[tk_rb_pos]; @@ -877,6 +882,7 @@ void GDScriptTokenizerText::_advance() { bool period_found = false; bool exponent_found = false; bool hexa_found = false; + bool bin_found = false; bool sign_found = false; String str; @@ -887,16 +893,28 @@ void GDScriptTokenizerText::_advance() { if (period_found || exponent_found) { _make_error("Invalid numeric constant at '.'"); return; + } else if (bin_found) { + _make_error("Invalid binary constant at '.'"); + return; + } else if (hexa_found) { + _make_error("Invalid hexadecimal constant at '.'"); + return; } period_found = true; } else if (GETCHAR(i) == 'x') { - if (hexa_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) { + if (hexa_found || bin_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) { _make_error("Invalid numeric constant at 'x'"); return; } hexa_found = true; + } else if (GETCHAR(i) == 'b') { + if (hexa_found || bin_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) { + _make_error("Invalid numeric constant at 'b'"); + return; + } + bin_found = true; } else if (!hexa_found && GETCHAR(i) == 'e') { - if (exponent_found) { + if (exponent_found || bin_found) { _make_error("Invalid numeric constant at 'e'"); return; } @@ -905,6 +923,8 @@ void GDScriptTokenizerText::_advance() { //all ok } else if (hexa_found && _is_hex(GETCHAR(i))) { + } else if (bin_found && _is_bin(GETCHAR(i))) { + } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) { if (sign_found) { _make_error("Invalid numeric constant at '-'"); @@ -930,6 +950,9 @@ void GDScriptTokenizerText::_advance() { if (hexa_found) { int64_t val = str.hex_to_int64(); _make_constant(val); + } else if (bin_found) { + int64_t val = str.bin_to_int64(); + _make_constant(val); } else if (period_found || exponent_found) { double val = str.to_double(); _make_constant(val); diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 657aa1f9ce..890bd730f7 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -1179,6 +1179,10 @@ void GridMapEditor::_floor_changed(float p_value) { _update_selection_transform(); } +void GridMapEditor::_floor_mouse_exited() { + floor->get_line_edit()->release_focus(); +} + void GridMapEditor::_bind_methods() { ClassDB::bind_method("_text_changed", &GridMapEditor::_text_changed); @@ -1188,6 +1192,7 @@ void GridMapEditor::_bind_methods() { ClassDB::bind_method("_configure", &GridMapEditor::_configure); ClassDB::bind_method("_item_selected_cbk", &GridMapEditor::_item_selected_cbk); ClassDB::bind_method("_floor_changed", &GridMapEditor::_floor_changed); + ClassDB::bind_method("_floor_mouse_exited", &GridMapEditor::_floor_mouse_exited); ClassDB::bind_method("_set_selection", &GridMapEditor::_set_selection); ClassDB::bind_method(D_METHOD("_set_display_mode", "mode"), &GridMapEditor::_set_display_mode); @@ -1221,6 +1226,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { spatial_editor_hb->add_child(floor); floor->connect("value_changed", this, "_floor_changed"); + floor->connect("mouse_exited", this, "_floor_mouse_exited"); + floor->get_line_edit()->connect("mouse_exited", this, "_floor_mouse_exited"); spatial_editor_hb->add_child(memnew(VSeparator)); diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 8e1948ea7d..da36165d4e 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -225,6 +225,7 @@ class GridMapEditor : public VBoxContainer { void _set_selection(bool p_active, const Vector3 p_begin = Vector3(), const Vector3 p_end = Vector3()); void _floor_changed(float p_value); + void _floor_mouse_exited(); void _delete_selection(); void _fill_selection(); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index bfbd6ca80e..72199281ff 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1855,6 +1855,34 @@ void CSharpInstance::_call_notification(int p_notification) { } } +String CSharpInstance::to_string(bool *r_valid) { + MonoObject *mono_object = get_mono_object(); + + if (mono_object == NULL) { + if (r_valid) + *r_valid = false; + return String(); + } + + MonoException *exc = NULL; + MonoString *result = GDMonoUtils::object_to_string(mono_object, &exc); + + if (exc) { + GDMonoUtils::set_pending_exception(exc); + if (r_valid) + *r_valid = false; + return String(); + } + + if (result == NULL) { + if (r_valid) + *r_valid = false; + return String(); + } + + return GDMonoMarshal::mono_string_to_godot(result); +} + Ref<Script> CSharpInstance::get_script() const { return script; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 298d55c4df..e735e0f741 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -261,6 +261,8 @@ public: virtual void notification(int p_notification); void _call_notification(int p_notification); + virtual String to_string(bool *r_valid); + virtual Ref<Script> get_script() const; virtual ScriptLanguage *get_language(); diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs index 967e3bcc19..e5044feb75 100644 --- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs @@ -186,7 +186,7 @@ namespace GodotSharpTools.Build private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, List<string> customProperties) { - string arguments = string.Format(@"""{0}"" /v:normal /t:Build ""/p:{1}"" ""/l:{2},{3};{4}""", + string arguments = string.Format(@"""{0}"" /v:normal /t:Rebuild ""/p:{1}"" ""/l:{2},{3};{4}""", solution, "Configuration=" + config, typeof(GodotBuildLogger).FullName, @@ -196,7 +196,7 @@ namespace GodotSharpTools.Build foreach (string customProperty in customProperties) { - arguments += " \"/p:" + customProperty + "\""; + arguments += " /p:" + customProperty; } return arguments; diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs index 89279c69a6..f4ab11a222 100644 --- a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs @@ -80,7 +80,7 @@ namespace GodotSharpTools.Project toolsGroup.AddProperty("DebugSymbols", "true"); toolsGroup.AddProperty("DebugType", "portable"); toolsGroup.AddProperty("Optimize", "false"); - toolsGroup.AddProperty("DefineConstants", "DEBUG;TOOLS;"); + toolsGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;TOOLS;"); toolsGroup.AddProperty("ErrorReport", "prompt"); toolsGroup.AddProperty("WarningLevel", "4"); toolsGroup.AddProperty("ConsolePause", "false"); @@ -161,7 +161,7 @@ namespace GodotSharpTools.Project debugGroup.AddProperty("DebugSymbols", "true"); debugGroup.AddProperty("DebugType", "portable"); debugGroup.AddProperty("Optimize", "false"); - debugGroup.AddProperty("DefineConstants", "DEBUG;"); + debugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;"); debugGroup.AddProperty("ErrorReport", "prompt"); debugGroup.AddProperty("WarningLevel", "4"); debugGroup.AddProperty("ConsolePause", "false"); @@ -170,6 +170,7 @@ namespace GodotSharpTools.Project releaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "; releaseGroup.AddProperty("DebugType", "portable"); releaseGroup.AddProperty("Optimize", "true"); + releaseGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;"); releaseGroup.AddProperty("ErrorReport", "prompt"); releaseGroup.AddProperty("WarningLevel", "4"); releaseGroup.AddProperty("ConsolePause", "false"); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index a408716641..cd7774e7a1 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -2300,9 +2300,14 @@ void BindingsGenerator::_populate_object_type_interfaces() { if (method_info.name.empty()) continue; + String cname = method_info.name; + + if (blacklisted_methods.find(itype.cname) && blacklisted_methods[itype.cname].find(cname)) + continue; + MethodInterface imethod; imethod.name = method_info.name; - imethod.cname = imethod.name; + imethod.cname = cname; if (method_info.flags & METHOD_FLAG_VIRTUAL) imethod.is_virtual = true; @@ -2975,6 +2980,13 @@ void BindingsGenerator::_populate_global_constants() { } } +void BindingsGenerator::_initialize_blacklisted_methods() { + + blacklisted_methods["Object"].push_back("to_string"); // there is already ToString + blacklisted_methods["Object"].push_back("_to_string"); // override ToString instead + blacklisted_methods["Object"].push_back("_init"); // never called in C# (TODO: implement it) +} + void BindingsGenerator::_log(const char *p_format, ...) { if (log_print_enabled) { @@ -2992,6 +3004,8 @@ void BindingsGenerator::_initialize() { enum_types.clear(); + _initialize_blacklisted_methods(); + _populate_object_type_interfaces(); _populate_builtin_type_interfaces(); diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index bdba28c267..ffc73a7e3e 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -491,6 +491,10 @@ class BindingsGenerator { List<InternalCall> core_custom_icalls; List<InternalCall> editor_custom_icalls; + Map<StringName, List<StringName> > blacklisted_methods; + + void _initialize_blacklisted_methods(); + struct NameCache { StringName type_void; StringName type_Array; diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index de3fd91223..9f132825fb 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -30,6 +30,7 @@ #include "godotsharp_builds.h" +#include "core/os/os.h" #include "core/vector.h" #include "main/main.h" @@ -351,7 +352,7 @@ bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) { return true; } -bool GodotSharpBuilds::build_project_blocking(const String &p_config) { +bool GodotSharpBuilds::build_project_blocking(const String &p_config, const Vector<String> &p_godot_defines) { if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) return true; // No solution to build @@ -366,6 +367,21 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) { pr.step("Building project solution", 0); MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), p_config); + + // Add Godot defines + String constants = "GodotDefineConstants=\""; + + for (int i = 0; i < p_godot_defines.size(); i++) { + constants += "GODOT_" + p_godot_defines[i].to_upper().replace("-", "_").replace(" ", "_").replace(";", "_") + ";"; + } + +#ifdef REAL_T_IS_DOUBLE + constants += "GODOT_REAL_T_IS_DOUBLE;"; +#endif + + constants += "\""; + build_info.custom_props.push_back(constants); + if (!GodotSharpBuilds::get_singleton()->build(build_info)) { GodotSharpBuilds::show_build_error_dialog("Failed to build project solution"); return false; @@ -393,7 +409,10 @@ bool GodotSharpBuilds::editor_build_callback() { ERR_FAIL_COND_V(copy_err != OK, false); } - return build_project_blocking("Tools"); + Vector<String> godot_defines; + godot_defines.push_back(OS::get_singleton()->get_name()); + godot_defines.push_back(sizeof(void *) == 4 ? "32" : "64"); + return build_project_blocking("Tools", godot_defines); } GodotSharpBuilds *GodotSharpBuilds::singleton = NULL; diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h index 652d30538a..2e9050e12e 100644 --- a/modules/mono/editor/godotsharp_builds.h +++ b/modules/mono/editor/godotsharp_builds.h @@ -92,7 +92,7 @@ public: static bool make_api_assembly(APIAssembly::Type p_api_type); - static bool build_project_blocking(const String &p_config); + static bool build_project_blocking(const String &p_config, const Vector<String> &p_godot_defines); static bool editor_build_callback(); diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index ee5fed1a0c..ae5b939b26 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -94,7 +94,12 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug ERR_FAIL_COND(!_add_file(scripts_metadata_path, scripts_metadata_path)); - ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config)); + // Turn export features into defines + Vector<String> godot_defines; + for (Set<String>::Element *E = p_features.front(); E; E = E->next()) { + godot_defines.push_back(E->get()); + } + ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config, godot_defines)); // Add dependency assemblies diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp index 21ce9ca5c4..5d9e39b6c2 100644 --- a/modules/mono/editor/mono_bottom_panel.cpp +++ b/modules/mono/editor/mono_bottom_panel.cpp @@ -175,7 +175,10 @@ void MonoBottomPanel::_build_project_pressed() { ERR_FAIL_COND(copy_err != OK); } - bool build_success = GodotSharpBuilds::get_singleton()->build_project_blocking("Tools"); + Vector<String> godot_defines; + godot_defines.push_back(OS::get_singleton()->get_name()); + godot_defines.push_back((sizeof(void *) == 4 ? "32" : "64")); + bool build_success = GodotSharpBuilds::get_singleton()->build_project_blocking("Tools", godot_defines); if (build_success) { // Notify running game for hot-reload diff --git a/modules/mono/glue/Managed/Files/AABB.cs b/modules/mono/glue/Managed/Files/AABB.cs index 33b2b46712..a2ebbc0736 100644 --- a/modules/mono/glue/Managed/Files/AABB.cs +++ b/modules/mono/glue/Managed/Files/AABB.cs @@ -414,6 +414,21 @@ namespace Godot _position = position; _size = size; } + public AABB(Vector3 position, real_t width, real_t height, real_t depth) + { + _position = position; + _size = new Vector3(width, height, depth); + } + public AABB(real_t x, real_t y, real_t z, Vector3 size) + { + _position = new Vector3(x, y, z); + _size = size; + } + public AABB(real_t x, real_t y, real_t z, real_t width, real_t height, real_t depth) + { + _position = new Vector3(x, y, z); + _size = new Vector3(width, height, depth); + } public static bool operator ==(AABB left, AABB right) { diff --git a/modules/mono/glue/Managed/Files/Basis.cs b/modules/mono/glue/Managed/Files/Basis.cs index ac9576cebd..9cc31a0557 100644 --- a/modules/mono/glue/Managed/Files/Basis.cs +++ b/modules/mono/glue/Managed/Files/Basis.cs @@ -260,13 +260,13 @@ namespace Godot Vector3 euler; euler.z = 0.0f; - real_t mxy = m.Row1[2]; + real_t mzy = m.Row1[2]; - if (mxy < 1.0f) + if (mzy < 1.0f) { - if (mxy > -1.0f) + if (mzy > -1.0f) { - euler.x = Mathf.Asin(-mxy); + euler.x = Mathf.Asin(-mzy); euler.y = Mathf.Atan2(m.Row0[2], m.Row2[2]); euler.z = Mathf.Atan2(m.Row1[0], m.Row1[1]); } @@ -418,19 +418,11 @@ namespace Godot public Basis Scaled(Vector3 scale) { - var m = this; - - m.Row0[0] *= scale.x; - m.Row0[1] *= scale.x; - m.Row0[2] *= scale.x; - m.Row1[0] *= scale.y; - m.Row1[1] *= scale.y; - m.Row1[2] *= scale.y; - m.Row2[0] *= scale.z; - m.Row2[1] *= scale.z; - m.Row2[2] *= scale.z; - - return m; + var b = this; + b.Row0 *= scale.x; + b.Row1 *= scale.y; + b.Row2 *= scale.z; + return b; } public real_t Tdotx(Vector3 with) @@ -583,31 +575,29 @@ namespace Godot public Basis(Vector3 axis, real_t phi) { - var axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); - + Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); real_t cosine = Mathf.Cos(phi); + Row0.x = axisSq.x + cosine * (1.0f - axisSq.x); + Row1.y = axisSq.y + cosine * (1.0f - axisSq.y); + Row2.z = axisSq.z + cosine * (1.0f - axisSq.z); + real_t sine = Mathf.Sin(phi); + real_t t = 1.0f - cosine; - Row0 = new Vector3 - ( - axis_sq.x + cosine * (1.0f - axis_sq.x), - axis.x * axis.y * (1.0f - cosine) - axis.z * sine, - axis.z * axis.x * (1.0f - cosine) + axis.y * sine - ); + real_t xyzt = axis.x * axis.y * t; + real_t zyxs = axis.z * sine; + Row0.y = xyzt - zyxs; + Row1.x = xyzt + zyxs; - Row1 = new Vector3 - ( - axis.x * axis.y * (1.0f - cosine) + axis.z * sine, - axis_sq.y + cosine * (1.0f - axis_sq.y), - axis.y * axis.z * (1.0f - cosine) - axis.x * sine - ); + xyzt = axis.x * axis.z * t; + zyxs = axis.y * sine; + Row0.z = xyzt + zyxs; + Row2.x = xyzt - zyxs; - Row2 = new Vector3 - ( - axis.z * axis.x * (1.0f - cosine) - axis.y * sine, - axis.y * axis.z * (1.0f - cosine) + axis.x * sine, - axis_sq.z + cosine * (1.0f - axis_sq.z) - ); + xyzt = axis.y * axis.z * t; + zyxs = axis.x * sine; + Row1.z = xyzt - zyxs; + Row2.y = xyzt + zyxs; } public Basis(Vector3 column0, Vector3 column1, Vector3 column2) @@ -622,11 +612,12 @@ namespace Godot // We need to assign the struct fields here first so we can't do it that way... } - internal Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) + // Arguments are named such that xy is equal to calling x.y + internal Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz) { - Row0 = new Vector3(xx, xy, xz); - Row1 = new Vector3(yx, yy, yz); - Row2 = new Vector3(zx, zy, zz); + Row0 = new Vector3(xx, yx, zx); + Row1 = new Vector3(xy, yy, zy); + Row2 = new Vector3(xz, yz, zz); } public static Basis operator *(Basis left, Basis right) diff --git a/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs index 366d89b1c2..5023725f17 100644 --- a/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs +++ b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs @@ -24,12 +24,12 @@ namespace Godot public T GetOwner<T>() where T : class { - return (T)(object)GetOwner(); + return (T)(object)Owner; } public T GetOwnerOrNull<T>() where T : class { - return GetOwner() as T; + return Owner as T; } public T GetParent<T>() where T : class diff --git a/modules/mono/glue/Managed/Files/MarshalUtils.cs b/modules/mono/glue/Managed/Files/MarshalUtils.cs index 730a1e1585..a1d63a62ef 100644 --- a/modules/mono/glue/Managed/Files/MarshalUtils.cs +++ b/modules/mono/glue/Managed/Files/MarshalUtils.cs @@ -23,7 +23,7 @@ namespace Godot /// <summary> /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="Godot.Collections.Dictionary{T}"/>; otherwise returns <see langword="false"/>. + /// is <see cref="Godot.Collections.Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>. /// </summary> /// <exception cref="System.InvalidOperationException"> /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false. @@ -45,6 +45,44 @@ namespace Godot valueType = genericArgs[1]; } + static bool GenericIEnumerableIsAssignableFromType(Type type) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + return true; + + foreach (var interfaceType in type.GetInterfaces()) + { + if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + return true; + } + + Type baseType = type.BaseType; + + if (baseType == null) + return false; + + return GenericIEnumerableIsAssignableFromType(baseType); + } + + static bool GenericIDictionaryIsAssignableFromType(Type type) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + return true; + + foreach (var interfaceType in type.GetInterfaces()) + { + if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + return true; + } + + Type baseType = type.BaseType; + + if (baseType == null) + return false; + + return GenericIDictionaryIsAssignableFromType(baseType); + } + static bool GenericIEnumerableIsAssignableFromType(Type type, out Type elementType) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs index ff26c7fddf..8fb8730b88 100644 --- a/modules/mono/glue/Managed/Files/Mathf.cs +++ b/modules/mono/glue/Managed/Files/Mathf.cs @@ -44,9 +44,9 @@ namespace Godot return (real_t)Math.Atan(s); } - public static real_t Atan2(real_t x, real_t y) + public static real_t Atan2(real_t y, real_t x) { - return (real_t)Math.Atan2(x, y); + return (real_t)Math.Atan2(y, x); } public static Vector2 Cartesian2Polar(real_t x, real_t y) diff --git a/modules/mono/glue/Managed/Files/Transform2D.cs b/modules/mono/glue/Managed/Files/Transform2D.cs index f7bb41d523..33ff286769 100644 --- a/modules/mono/glue/Managed/Files/Transform2D.cs +++ b/modules/mono/glue/Managed/Files/Transform2D.cs @@ -298,6 +298,7 @@ namespace Godot origin = originPos; } + // Arguments are named such that xy is equal to calling x.y public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy) { x = new Vector2(xx, xy); diff --git a/modules/mono/glue/Managed/IgnoredFiles/Node.cs b/modules/mono/glue/Managed/IgnoredFiles/Node.cs index 99ba0f827a..cff61b1e0b 100644 --- a/modules/mono/glue/Managed/IgnoredFiles/Node.cs +++ b/modules/mono/glue/Managed/IgnoredFiles/Node.cs @@ -15,9 +15,10 @@ namespace Godot throw new NotImplementedException(); } - public Node GetOwner() + public Node Owner { - throw new NotImplementedException(); + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); } public Node GetParent() diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 4aef5684fd..47239f1260 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -162,7 +162,7 @@ MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) { #ifdef DEBUG_ENABLED CRASH_COND(!exc); #endif - GDMonoUtils::runtime_object_init(exc); + GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException)); GDMonoUtils::set_pending_exception((MonoException *)exc); return NULL; } @@ -176,7 +176,7 @@ MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject #ifdef DEBUG_ENABLED CRASH_COND(!exc); #endif - GDMonoUtils::runtime_object_init(exc); + GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException)); GDMonoUtils::set_pending_exception((MonoException *)exc); return NULL; } diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 461dcf3ec0..c462b8f71d 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -161,8 +161,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); - MonoReflectionType *key_reftype, *value_reftype; - if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) { return Variant::DICTIONARY; } @@ -170,8 +169,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { return Variant::DICTIONARY; } - MonoReflectionType *elem_reftype; - if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) { return Variant::ARRAY; } @@ -193,16 +191,14 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { // The order in which we check the following interfaces is very important (dictionaries and generics first) - MonoReflectionType *key_reftype, *value_reftype; - if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) return Variant::DICTIONARY; if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) { return Variant::DICTIONARY; } - MonoReflectionType *elem_reftype; - if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) return Variant::ARRAY; if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { @@ -850,8 +846,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) { MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type_class->get_mono_type()); - MonoReflectionType *key_reftype, *value_reftype; - if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) { return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj); } @@ -859,8 +854,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) { return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj); } - MonoReflectionType *elem_reftype; - if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) { return GDMonoUtils::Marshal::enumerable_to_array(p_obj); } @@ -888,8 +882,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) { // The order in which we check the following interfaces is very important (dictionaries and generics first) - MonoReflectionType *key_reftype, *value_reftype; - if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) { + if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) { return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj); } @@ -897,8 +890,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) { return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj); } - MonoReflectionType *elem_reftype; - if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) { + if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) { return GDMonoUtils::Marshal::enumerable_to_array(p_obj); } diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 5236e43c90..413c8cba85 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -161,6 +161,8 @@ void MonoCache::clear_members() { methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType = NULL; methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType = NULL; + methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info = NULL; + methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info = NULL; methodthunk_MarshalUtils_MakeGenericArrayType = NULL; methodthunk_MarshalUtils_MakeGenericDictionaryType = NULL; @@ -282,8 +284,10 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, (GenericIEnumerableIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, (GenericIEnumerableIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, (MakeGenericArrayType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericArrayType", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, (MakeGenericDictionaryType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericDictionaryType", 2)); @@ -300,7 +304,7 @@ void update_godot_api_cache() { // TODO Move to CSharpLanguage::init() and do handle disposal MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); - GDMonoUtils::runtime_object_init(task_scheduler); + GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler)); mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler); mono_cache.godot_api_cache_updated = true; @@ -401,11 +405,10 @@ MonoThread *get_current_thread() { return mono_thread_current(); } -void runtime_object_init(MonoObject *p_this_obj) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - // FIXME: Do not use mono_runtime_object_init, it aborts if an exception is thrown - mono_runtime_object_init(p_this_obj); - GD_MONO_END_RUNTIME_INVOKE; +void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) { + GDMonoMethod *ctor = p_class->get_method(".ctor", 0); + ERR_FAIL_NULL(ctor); + ctor->invoke_raw(p_this_obj, NULL, r_exc); } GDMonoClass *get_object_class(MonoObject *p_object) { @@ -467,7 +470,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object); // Construct - GDMonoUtils::runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object, p_class); return mono_object; } @@ -477,7 +480,7 @@ MonoObject *create_managed_from(const NodePath &p_from) { ERR_FAIL_NULL_V(mono_object, NULL); // Construct - GDMonoUtils::runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(NodePath)); CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from))); @@ -489,7 +492,7 @@ MonoObject *create_managed_from(const RID &p_from) { ERR_FAIL_NULL_V(mono_object, NULL); // Construct - GDMonoUtils::runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(RID)); CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from))); @@ -788,16 +791,32 @@ void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoRefl UNLIKELY_UNHANDLED_EXCEPTION(exc); } -MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) { +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) { GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType); MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) { + GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType); + MonoException *exc = NULL; + MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return res; +} + +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) { + GenericIEnumerableIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info); + MonoException *exc = NULL; MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_elem_reftype, &exc); UNLIKELY_UNHANDLED_EXCEPTION(exc); return res; } MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { - GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType); + GenericIDictionaryIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info); MonoException *exc = NULL; MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_key_reftype, r_value_reftype, &exc); UNLIKELY_UNHANDLED_EXCEPTION(exc); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 081a8a9813..ee239be959 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -64,8 +64,10 @@ typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoExcepti typedef void (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **); typedef void (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); -typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType)(MonoReflectionType *, MonoReflectionType **, MonoException **); -typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); +typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType)(MonoReflectionType *, MonoException **); +typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType)(MonoReflectionType *, MonoException **); +typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoException **); +typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); typedef MonoReflectionType *(*MakeGenericArrayType)(MonoReflectionType *, MonoException **); typedef MonoReflectionType *(*MakeGenericDictionaryType)(MonoReflectionType *, MonoReflectionType *, MonoException **); @@ -82,6 +84,8 @@ MonoBoolean type_is_generic_dictionary(MonoReflectionType *p_reftype); void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype); void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype); +MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype); +MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype); MonoBoolean generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype); MonoBoolean generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype); @@ -197,6 +201,8 @@ struct MonoCache { GenericIEnumerableIsAssignableFromType methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType; GenericIDictionaryIsAssignableFromType methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType; + GenericIEnumerableIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info; + GenericIDictionaryIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info; MakeGenericArrayType methodthunk_MarshalUtils_MakeGenericArrayType; MakeGenericDictionaryType methodthunk_MarshalUtils_MakeGenericDictionaryType; @@ -249,7 +255,7 @@ _FORCE_INLINE_ bool is_main_thread() { return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current(); } -void runtime_object_init(MonoObject *p_this_obj); +void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = NULL); GDMonoClass *get_object_class(MonoObject *p_object); GDMonoClass *type_get_proxy_class(const StringName &p_type); diff --git a/modules/recast/navigation_mesh_editor_plugin.cpp b/modules/recast/navigation_mesh_editor_plugin.cpp index 62108620bd..eadc11fcee 100644 --- a/modules/recast/navigation_mesh_editor_plugin.cpp +++ b/modules/recast/navigation_mesh_editor_plugin.cpp @@ -54,26 +54,28 @@ void NavigationMeshEditor::_notification(int p_option) { } void NavigationMeshEditor::_bake_pressed() { + button_bake->set_pressed(false); ERR_FAIL_COND(!node); const String conf_warning = node->get_configuration_warning(); if (!conf_warning.empty()) { err_dialog->set_text(conf_warning); err_dialog->popup_centered_minsize(); - button_bake->set_pressed(false); return; } - NavigationMeshGenerator::clear(node->get_navigation_mesh()); - NavigationMeshGenerator::bake(node->get_navigation_mesh(), node); + EditorNavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh()); + EditorNavigationMeshGenerator::get_singleton()->bake(node->get_navigation_mesh(), node); - node->update_gizmo(); + if (node) { + node->update_gizmo(); + } } void NavigationMeshEditor::_clear_pressed() { if (node) - NavigationMeshGenerator::clear(node->get_navigation_mesh()); + EditorNavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh()); button_bake->set_pressed(false); bake_info->set_text(""); diff --git a/modules/recast/navigation_mesh_generator.cpp b/modules/recast/navigation_mesh_generator.cpp index 79ccbbb030..0cac07e3e7 100644 --- a/modules/recast/navigation_mesh_generator.cpp +++ b/modules/recast/navigation_mesh_generator.cpp @@ -29,14 +29,31 @@ /*************************************************************************/ #include "navigation_mesh_generator.h" - -void NavigationMeshGenerator::_add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies) { +#include "core/math/quick_hull.h" +#include "core/os/thread.h" +#include "editor/editor_settings.h" +#include "scene/3d/collision_shape.h" +#include "scene/3d/mesh_instance.h" +#include "scene/3d/physics_body.h" +#include "scene/resources/box_shape.h" +#include "scene/resources/capsule_shape.h" +#include "scene/resources/concave_polygon_shape.h" +#include "scene/resources/convex_polygon_shape.h" +#include "scene/resources/cylinder_shape.h" +#include "scene/resources/plane_shape.h" +#include "scene/resources/primitive_meshes.h" +#include "scene/resources/shape.h" +#include "scene/resources/sphere_shape.h" + +EditorNavigationMeshGenerator *EditorNavigationMeshGenerator::singleton = NULL; + +void EditorNavigationMeshGenerator::_add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies) { p_verticies.push_back(p_vec3.x); p_verticies.push_back(p_vec3.y); p_verticies.push_back(p_vec3.z); } -void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { +void EditorNavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { int current_vertex_count = 0; for (int i = 0; i < p_mesh->get_surface_count(); i++) { @@ -91,23 +108,132 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform } } -void NavigationMeshGenerator::_parse_geometry(const Transform &p_base_inverse, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices) { +void EditorNavigationMeshGenerator::_add_faces(const PoolVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { + int face_count = p_faces.size() / 3; + int current_vertex_count = p_verticies.size() / 3; + + for (int j = 0; j < face_count; j++) { + _add_vertex(p_xform.xform(p_faces[j * 3 + 0]), p_verticies); + _add_vertex(p_xform.xform(p_faces[j * 3 + 1]), p_verticies); + _add_vertex(p_xform.xform(p_faces[j * 3 + 2]), p_verticies); + + p_indices.push_back(current_vertex_count + (j * 3 + 0)); + p_indices.push_back(current_vertex_count + (j * 3 + 2)); + p_indices.push_back(current_vertex_count + (j * 3 + 1)); + } +} + +void EditorNavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask) { - if (Object::cast_to<MeshInstance>(p_node)) { + if (Object::cast_to<MeshInstance>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(p_node); Ref<Mesh> mesh = mesh_instance->get_mesh(); if (mesh.is_valid()) { - _add_mesh(mesh, p_base_inverse * mesh_instance->get_global_transform(), p_verticies, p_indices); + _add_mesh(mesh, p_accumulated_transform * mesh_instance->get_transform(), p_verticies, p_indices); } } + if (Object::cast_to<StaticBody>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES) { + StaticBody *static_body = Object::cast_to<StaticBody>(p_node); + + if (static_body->get_collision_layer() & p_collision_mask) { + + for (int i = 0; i < p_node->get_child_count(); ++i) { + Node *child = p_node->get_child(i); + if (Object::cast_to<CollisionShape>(child)) { + CollisionShape *col_shape = Object::cast_to<CollisionShape>(child); + + Transform transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform(); + + Ref<Mesh> mesh; + Ref<Shape> s = col_shape->get_shape(); + + BoxShape *box = Object::cast_to<BoxShape>(*s); + if (box) { + Ref<CubeMesh> cube_mesh; + cube_mesh.instance(); + cube_mesh->set_size(box->get_extents() * 2.0); + mesh = cube_mesh; + } + + CapsuleShape *capsule = Object::cast_to<CapsuleShape>(*s); + if (capsule) { + Ref<CapsuleMesh> capsule_mesh; + capsule_mesh.instance(); + capsule_mesh->set_radius(capsule->get_radius()); + capsule_mesh->set_mid_height(capsule->get_height() / 2.0); + mesh = capsule_mesh; + } + + CylinderShape *cylinder = Object::cast_to<CylinderShape>(*s); + if (cylinder) { + Ref<CylinderMesh> cylinder_mesh; + cylinder_mesh.instance(); + cylinder_mesh->set_height(cylinder->get_height()); + cylinder_mesh->set_bottom_radius(cylinder->get_radius()); + cylinder_mesh->set_top_radius(cylinder->get_radius()); + mesh = cylinder_mesh; + } + + SphereShape *sphere = Object::cast_to<SphereShape>(*s); + if (sphere) { + Ref<SphereMesh> sphere_mesh; + sphere_mesh.instance(); + sphere_mesh->set_radius(sphere->get_radius()); + sphere_mesh->set_height(sphere->get_radius() * 2.0); + mesh = sphere_mesh; + } + + ConcavePolygonShape *concave_polygon = Object::cast_to<ConcavePolygonShape>(*s); + if (concave_polygon) { + _add_faces(concave_polygon->get_faces(), transform, p_verticies, p_indices); + } + + ConvexPolygonShape *convex_polygon = Object::cast_to<ConvexPolygonShape>(*s); + if (convex_polygon) { + Vector<Vector3> varr = Variant(convex_polygon->get_points()); + Geometry::MeshData md; + + Error err = QuickHull::build(varr, md); + + if (err == OK) { + PoolVector3Array faces; + + for (int j = 0; j < md.faces.size(); ++j) { + Geometry::MeshData::Face face = md.faces[j]; + + for (int k = 2; k < face.indices.size(); ++k) { + faces.push_back(md.vertices[face.indices[0]]); + faces.push_back(md.vertices[face.indices[k - 1]]); + faces.push_back(md.vertices[face.indices[k]]); + } + } + + _add_faces(faces, transform, p_verticies, p_indices); + } + } + + if (mesh.is_valid()) { + _add_mesh(mesh, transform, p_verticies, p_indices); + } + } + } + } + } + + if (Object::cast_to<Spatial>(p_node)) { + + Spatial *spatial = Object::cast_to<Spatial>(p_node); + p_accumulated_transform = p_accumulated_transform * spatial->get_transform(); + } + for (int i = 0; i < p_node->get_child_count(); i++) { - _parse_geometry(p_base_inverse, p_node->get_child(i), p_verticies, p_indices); + _parse_geometry(p_accumulated_transform, p_node->get_child(i), p_verticies, p_indices, p_generate_from, p_collision_mask); } } -void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh) { +void EditorNavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh) { PoolVector<Vector3> nav_vertices; @@ -135,7 +261,7 @@ void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(con } } -void NavigationMeshGenerator::_build_recast_navigation_mesh(Ref<NavigationMesh> p_nav_mesh, EditorProgress *ep, +void EditorNavigationMeshGenerator::_build_recast_navigation_mesh(Ref<NavigationMesh> p_nav_mesh, EditorProgress *ep, rcHeightfield *hf, rcCompactHeightfield *chf, rcContourSet *cset, rcPolyMesh *poly_mesh, rcPolyMeshDetail *detail_mesh, Vector<float> &vertices, Vector<int> &indices) { rcContext ctx; @@ -257,7 +383,18 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(Ref<NavigationMesh> detail_mesh = 0; } -void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) { +EditorNavigationMeshGenerator *EditorNavigationMeshGenerator::get_singleton() { + return singleton; +} + +EditorNavigationMeshGenerator::EditorNavigationMeshGenerator() { + singleton = this; +} + +EditorNavigationMeshGenerator::~EditorNavigationMeshGenerator() { +} + +void EditorNavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) { ERR_FAIL_COND(!p_nav_mesh.is_valid()); @@ -267,7 +404,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) Vector<float> vertices; Vector<int> indices; - _parse_geometry(Object::cast_to<Spatial>(p_node)->get_global_transform().affine_inverse(), p_node, vertices, indices); + _parse_geometry(Object::cast_to<Spatial>(p_node)->get_transform().affine_inverse(), p_node, vertices, indices, p_nav_mesh->get_parsed_geometry_type(), p_nav_mesh->get_collision_mask()); if (vertices.size() > 0 && indices.size() > 0) { @@ -297,9 +434,14 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) ep.step(TTR("Done!"), 11); } -void NavigationMeshGenerator::clear(Ref<NavigationMesh> p_nav_mesh) { +void EditorNavigationMeshGenerator::clear(Ref<NavigationMesh> p_nav_mesh) { if (p_nav_mesh.is_valid()) { p_nav_mesh->clear_polygons(); p_nav_mesh->set_vertices(PoolVector<Vector3>()); } } + +void EditorNavigationMeshGenerator::_bind_methods() { + ClassDB::bind_method(D_METHOD("bake", "nav_mesh", "root_node"), &EditorNavigationMeshGenerator::bake); + ClassDB::bind_method(D_METHOD("clear", "nav_mesh"), &EditorNavigationMeshGenerator::clear); +} diff --git a/modules/recast/navigation_mesh_generator.h b/modules/recast/navigation_mesh_generator.h index 3adc01ccda..30a6e3c835 100644 --- a/modules/recast/navigation_mesh_generator.h +++ b/modules/recast/navigation_mesh_generator.h @@ -31,20 +31,23 @@ #ifndef NAVIGATION_MESH_GENERATOR_H #define NAVIGATION_MESH_GENERATOR_H -#include "core/os/thread.h" #include "editor/editor_node.h" -#include "editor/editor_settings.h" -#include "scene/3d/mesh_instance.h" #include "scene/3d/navigation_mesh.h" -#include "scene/resources/shape.h" #include <Recast.h> -class NavigationMeshGenerator { +class EditorNavigationMeshGenerator : public Object { + GDCLASS(EditorNavigationMeshGenerator, Object); + + static EditorNavigationMeshGenerator *singleton; + protected: + static void _bind_methods(); + static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies); static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); - static void _parse_geometry(const Transform &p_base_inverse, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices); + static void _add_faces(const PoolVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); + static void _parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask); static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh); static void _build_recast_navigation_mesh(Ref<NavigationMesh> p_nav_mesh, EditorProgress *ep, @@ -52,8 +55,13 @@ protected: rcPolyMeshDetail *detail_mesh, Vector<float> &vertices, Vector<int> &indices); public: - static void bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node); - static void clear(Ref<NavigationMesh> p_nav_mesh); + static EditorNavigationMeshGenerator *get_singleton(); + + EditorNavigationMeshGenerator(); + ~EditorNavigationMeshGenerator(); + + void bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node); + void clear(Ref<NavigationMesh> p_nav_mesh); }; #endif // NAVIGATION_MESH_GENERATOR_H diff --git a/modules/recast/register_types.cpp b/modules/recast/register_types.cpp index f272cc4236..247d7f6144 100644 --- a/modules/recast/register_types.cpp +++ b/modules/recast/register_types.cpp @@ -32,8 +32,23 @@ #include "navigation_mesh_editor_plugin.h" +#ifdef TOOLS_ENABLED +EditorNavigationMeshGenerator *_nav_mesh_generator = NULL; +#endif + void register_recast_types() { +#ifdef TOOLS_ENABLED EditorPlugins::add_by_type<NavigationMeshEditorPlugin>(); + _nav_mesh_generator = memnew(EditorNavigationMeshGenerator); + ClassDB::register_class<EditorNavigationMeshGenerator>(); + Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", EditorNavigationMeshGenerator::get_singleton())); +#endif } -void unregister_recast_types() {} +void unregister_recast_types() { +#ifdef TOOLS_ENABLED + if (_nav_mesh_generator) { + memdelete(_nav_mesh_generator); + } +#endif +} diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp index 292ac5e97e..b5f4718c72 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -273,6 +273,7 @@ void AudioStreamOGGVorbis::_bind_methods() { AudioStreamOGGVorbis::AudioStreamOGGVorbis() { data = NULL; + data_len = 0; length = 0; sample_rate = 1; channels = 1; diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 8f311d11f4..85fc867901 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -46,15 +46,7 @@ bool VisualScriptNode::is_breakpoint() const { return breakpoint; } -void VisualScriptNode::_notification(int p_what) { - - if (p_what == NOTIFICATION_POSTINITIALIZE) { - validate_input_default_values(); - } -} - void VisualScriptNode::ports_changed_notify() { - validate_input_default_values(); emit_signal("ports_changed"); } @@ -273,11 +265,7 @@ void VisualScript::_node_ports_changed(int p_id) { Function &func = functions[function]; Ref<VisualScriptNode> vsn = func.nodes[p_id].node; - if (OS::get_singleton()->get_main_loop() && - Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop()) && - Engine::get_singleton()->is_editor_hint()) { - vsn->validate_input_default_values(); //force validate default values when editing on editor - } + vsn->validate_input_default_values(); //must revalidate all the functions @@ -353,6 +341,7 @@ void VisualScript::add_node(const StringName &p_func, int p_id, const Ref<Visual Ref<VisualScriptNode> vsn = p_node; vsn->connect("ports_changed", this, "_node_ports_changed", varray(p_id)); vsn->scripts_used.insert(this); + vsn->validate_input_default_values(); // Validate when fully loaded func.nodes[p_id] = nd; } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 91748d077b..89f32f54f7 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -54,7 +54,6 @@ class VisualScriptNode : public Resource { void validate_input_default_values(); protected: - void _notification(int p_what); void ports_changed_notify(); static void _bind_methods(); diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 5c408cf29e..6bbfb1ec5c 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -2218,7 +2218,7 @@ Control *VisualScriptEditor::get_edit_menu() { void VisualScriptEditor::_change_base_type() { - select_base_type->popup_create(true); + select_base_type->popup_create(true, true); } void VisualScriptEditor::clear_edit_menu() { @@ -2726,93 +2726,98 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri Ref<VisualScriptFunctionCall> vsfc = vsn; vsfc->set_function(p_text); - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - if (tg.type == Variant::OBJECT) { - vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - vsfc->set_base_type(String("")); - if (tg.gdclass != StringName()) { - vsfc->set_base_type(tg.gdclass); + if (p_connecting) { + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - } else if (script->get_node(edited_func, port_action_node).is_valid()) { - PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; - String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + if (tg.type == Variant::OBJECT) { + vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); + vsfc->set_base_type(String("")); + if (tg.gdclass != StringName()) { + vsfc->set_base_type(tg.gdclass); - if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { - vsfc->set_base_type(base_type); + } else if (script->get_node(edited_func, port_action_node).is_valid()) { + PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; + String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + + if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { + vsfc->set_base_type(base_type); + } + if (p_text == "call" || p_text == "call_deferred") { + vsfc->set_function(String("")); + } } - if (p_text == "call" || p_text == "call_deferred") { - vsfc->set_function(String("")); + if (tg.script.is_valid()) { + vsfc->set_base_script(tg.script->get_path()); } + } else if (tg.type == Variant::NIL) { + vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); + vsfc->set_base_type(String("")); + } else { + vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); + vsfc->set_basic_type(tg.type); } - if (tg.script.is_valid()) { - vsfc->set_base_script(tg.script->get_path()); - } - } else if (tg.type == Variant::NIL) { - vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - vsfc->set_base_type(String("")); - } else { - vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); - vsfc->set_basic_type(tg.type); } } - if (Object::cast_to<VisualScriptPropertySet>(vsn.ptr())) { + // if connecting from another node the call mode shouldn't be self + if (p_connecting) { + if (Object::cast_to<VisualScriptPropertySet>(vsn.ptr())) { + Ref<VisualScriptPropertySet> vsp = vsn; - Ref<VisualScriptPropertySet> vsp = vsn; - - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - if (tg.type == Variant::OBJECT) { - vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - vsp->set_base_type(String("")); - if (tg.gdclass != StringName()) { - vsp->set_base_type(tg.gdclass); + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); + if (tg.type == Variant::OBJECT) { + vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); + vsp->set_base_type(String("")); + if (tg.gdclass != StringName()) { + vsp->set_base_type(tg.gdclass); - } else if (script->get_node(edited_func, port_action_node).is_valid()) { - PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; - String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + } else if (script->get_node(edited_func, port_action_node).is_valid()) { + PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; + String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; - if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { - vsp->set_base_type(base_type); + if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { + vsp->set_base_type(base_type); + } } + if (tg.script.is_valid()) { + vsp->set_base_script(tg.script->get_path()); + } + } else if (tg.type == Variant::NIL) { + vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); + vsp->set_base_type(String("")); + } else { + vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE); + vsp->set_basic_type(tg.type); } - if (tg.script.is_valid()) { - vsp->set_base_script(tg.script->get_path()); - } - } else if (tg.type == Variant::NIL) { - vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - vsp->set_base_type(String("")); - } else { - vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE); - vsp->set_basic_type(tg.type); } - } - - if (Object::cast_to<VisualScriptPropertyGet>(vsn.ptr())) { - Ref<VisualScriptPropertyGet> vsp = vsn; - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - if (tg.type == Variant::OBJECT) { - vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - vsp->set_base_type(String("")); - if (tg.gdclass != StringName()) { - vsp->set_base_type(tg.gdclass); + if (Object::cast_to<VisualScriptPropertyGet>(vsn.ptr())) { + Ref<VisualScriptPropertyGet> vsp = vsn; - } else if (script->get_node(edited_func, port_action_node).is_valid()) { - PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; - String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; - if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { - vsp->set_base_type(base_type); + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); + if (tg.type == Variant::OBJECT) { + vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); + vsp->set_base_type(String("")); + if (tg.gdclass != StringName()) { + vsp->set_base_type(tg.gdclass); + + } else if (script->get_node(edited_func, port_action_node).is_valid()) { + PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; + String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { + vsp->set_base_type(base_type); + } } + if (tg.script.is_valid()) { + vsp->set_base_script(tg.script->get_path()); + } + } else if (tg.type == Variant::NIL) { + vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); + vsp->set_base_type(String("")); + } else { + vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE); + vsp->set_basic_type(tg.type); } - if (tg.script.is_valid()) { - vsp->set_base_script(tg.script->get_path()); - } - } else if (tg.type == Variant::NIL) { - vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - vsp->set_base_type(String("")); - } else { - vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE); - vsp->set_basic_type(tg.type); } } Ref<VisualScriptNode> vnode_old = script->get_node(edited_func, port_action_node); diff --git a/platform/android/detect.py b/platform/android/detect.py index ea70fefbc5..b7641172e4 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -214,13 +214,14 @@ def configure(env): lib_sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH'] ## Compile flags - - if env['android_stl']: + # Disable exceptions and rtti on non-tools (template) builds + if env['tools'] or env['android_stl']: env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/include"]) env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"]) env.Append(CXXFLAGS=['-frtti', "-std=gnu++14"]) else: env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions']) + # Don't use dynamic_cast, necessary with no-rtti. env.Append(CPPFLAGS=['-DNO_SAFE_CAST']) ndk_version = get_ndk_version(env["ANDROID_NDK_ROOT"]) diff --git a/platform/android/java/gradlew.bat b/platform/android/java/gradlew.bat index e95643d6a2..f9553162f1 100644 --- a/platform/android/java/gradlew.bat +++ b/platform/android/java/gradlew.bat @@ -1,84 +1,84 @@ -@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 374d40463a..0eeaf0701c 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -1059,4 +1059,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mProgressFraction.setText(Helpers.getDownloadProgressString(progress.mOverallProgress, progress.mOverallTotal)); } + public void initInputDevices() { + mView.initInputDevices(); + } } diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java index d7cd5b4360..ab28d9ec33 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/src/org/godotengine/godot/GodotView.java @@ -111,6 +111,18 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { init(translucent, depth, stencil); } + public void initInputDevices() { + /* initially add input devices*/ + int[] deviceIds = mInputManager.getInputDeviceIds(); + for (int deviceId : deviceIds) { + InputDevice device = mInputManager.getInputDevice(deviceId); + if (DEBUG) { + Log.v("GodotView", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName())); + } + onInputDeviceAdded(deviceId); + } + } + @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent event) { @@ -217,36 +229,42 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { // Check if the device has not been already added if (id < 0) { InputDevice device = mInputManager.getInputDevice(deviceId); + //device can be null if deviceId is not found + if (device != null) { + int sources = device.getSources(); + if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || + ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { + id = joy_devices.size(); + + joystick joy = new joystick(); + joy.device_id = deviceId; + joy.name = device.getName(); + joy.axes = new ArrayList<InputDevice.MotionRange>(); + joy.hats = new ArrayList<InputDevice.MotionRange>(); + + List<InputDevice.MotionRange> ranges = device.getMotionRanges(); + Collections.sort(ranges, new RangeComparator()); + + for (InputDevice.MotionRange range : ranges) { + if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) { + joy.hats.add(range); + } else { + joy.axes.add(range); + } + } - id = joy_devices.size(); - - joystick joy = new joystick(); - joy.device_id = deviceId; - joy.name = device.getName(); - joy.axes = new ArrayList<InputDevice.MotionRange>(); - joy.hats = new ArrayList<InputDevice.MotionRange>(); - - List<InputDevice.MotionRange> ranges = device.getMotionRanges(); - Collections.sort(ranges, new RangeComparator()); + joy_devices.add(joy); - for (InputDevice.MotionRange range : ranges) { - if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) { - joy.hats.add(range); - } else { - joy.axes.add(range); + final int device_id = id; + final String name = joy.name; + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.joyconnectionchanged(device_id, true, name); + } + }); } } - - joy_devices.add(joy); - - final int device_id = id; - final String name = joy.name; - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.joyconnectionchanged(device_id, true, name); - } - }); } } @@ -269,6 +287,8 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { @Override public void onInputDeviceChanged(int deviceId) { + onInputDeviceRemoved(deviceId); + onInputDeviceAdded(deviceId); } @Override public boolean onKeyUp(final int keyCode, KeyEvent event) { diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp index 101a1d76c6..e92d4437b1 100644 --- a/platform/android/java_godot_wrapper.cpp +++ b/platform/android/java_godot_wrapper.cpp @@ -59,6 +59,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) { _get_clipboard = p_env->GetMethodID(cls, "getClipboard", "()Ljava/lang/String;"); _set_clipboard = p_env->GetMethodID(cls, "setClipboard", "(Ljava/lang/String;)V"); _request_permission = p_env->GetMethodID(cls, "requestPermission", "(Ljava/lang/String;)Z"); + _init_input_devices = p_env->GetMethodID(cls, "initInputDevices", "()V"); } GodotJavaWrapper::~GodotJavaWrapper() { @@ -183,3 +184,10 @@ bool GodotJavaWrapper::request_permission(const String &p_name) { return false; } } + +void GodotJavaWrapper::init_input_devices() { + if (_init_input_devices) { + JNIEnv *env = ThreadAndroid::get_env(); + env->CallVoidMethod(godot_instance, _init_input_devices); + } +} diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h index 438aee019b..be4f109d8c 100644 --- a/platform/android/java_godot_wrapper.h +++ b/platform/android/java_godot_wrapper.h @@ -54,6 +54,7 @@ private: jmethodID _get_clipboard = 0; jmethodID _set_clipboard = 0; jmethodID _request_permission = 0; + jmethodID _init_input_devices = 0; public: GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance); @@ -76,6 +77,7 @@ public: bool has_set_clipboard(); void set_clipboard(const String &p_text); bool request_permission(const String &p_name); + void init_input_devices(); }; #endif /* !JAVA_GODOT_WRAPPER_H */ diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index ff1632cba8..f8076dfd2d 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -251,6 +251,10 @@ int OS_Android::get_mouse_button_state() const { } void OS_Android::set_window_title(const String &p_title) { + //This queries/updates the currently connected devices/joypads + //Set_window_title is called when initializing the main loop (main.cpp) + //therefore this place is found to be suitable (I found no better). + godot_java->init_input_devices(); } void OS_Android::set_video_mode(const VideoMode &p_video_mode, int p_screen) { diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index 3ed0a4ade7..d9f710e456 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -115,10 +115,12 @@ def configure(env): env.Append(CPPFLAGS=['-DNEED_LONG_INT']) env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON']) - if env['ios_exceptions']: - env.Append(CCFLAGS=['-fexceptions']) - else: - env.Append(CCFLAGS=['-fno-exceptions']) + # Disable exceptions on non-tools (template) builds + if not env['tools']: + if env['ios_exceptions']: + env.Append(CCFLAGS=['-fexceptions']) + else: + env.Append(CCFLAGS=['-fno-exceptions']) ## Link flags diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 145ce8d83d..145ac42863 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -110,10 +110,12 @@ def configure(env): # once feasible also consider memory buffer size issues. env.Append(CPPDEFINES=['NO_THREADS']) - # These flags help keep the file size down. - env.Append(CCFLAGS=['-fno-exceptions', '-fno-rtti']) - # Don't use dynamic_cast, necessary with no-rtti. - env.Append(CPPDEFINES=['NO_SAFE_CAST']) + # Disable exceptions and rtti on non-tools (template) builds + if not env['tools']: + # These flags help keep the file size down. + env.Append(CCFLAGS=['-fno-exceptions', '-fno-rtti']) + # Don't use dynamic_cast, necessary with no-rtti. + env.Append(CPPDEFINES=['NO_SAFE_CAST']) if env['javascript_eval']: env.Append(CPPDEFINES=['JAVASCRIPT_EVAL_ENABLED']) diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm index ed8a955ae5..e19fdf1b9f 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/osx/crash_handler_osx.mm @@ -77,7 +77,12 @@ static void handle_crash(int sig) { void *bt_buffer[256]; size_t size = backtrace(bt_buffer, 256); String _execpath = OS::get_singleton()->get_executable_path(); - String msg = GLOBAL_GET("debug/settings/crash_handler/message"); + + String msg; + const ProjectSettings *proj_settings = ProjectSettings::get_singleton(); + if (proj_settings) { + msg = proj_settings->get("debug/settings/crash_handler/message"); + } // Dump the backtrace to stderr with a message to the user fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index d2a6f38b01..212966af11 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -186,6 +186,7 @@ public: virtual Size2 get_window_size() const; virtual Size2 get_real_window_size() const; + virtual void set_native_icon(const String &p_filename); virtual void set_icon(const Ref<Image> &p_icon); virtual MainLoop *get_main_loop() const; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index fc97bd4a20..113c6636f0 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1858,6 +1858,31 @@ void OS_OSX::set_window_title(const String &p_title) { [window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]]; } +void OS_OSX::set_native_icon(const String &p_filename) { + + FileAccess *f = FileAccess::open(p_filename, FileAccess::READ); + ERR_FAIL_COND(!f); + + Vector<uint8_t> data; + uint32_t len = f->get_len(); + data.resize(len); + f->get_buffer((uint8_t *)&data.write[0], len); + memdelete(f); + + NSData *icon_data = [[[NSData alloc] initWithBytes:&data.write[0] length:len] autorelease]; + if (!icon_data) { + ERR_EXPLAIN("Error reading icon data"); + ERR_FAIL(); + } + NSImage *icon = [[[NSImage alloc] initWithData:icon_data] autorelease]; + if (!icon) { + ERR_EXPLAIN("Error loading icon"); + ERR_FAIL(); + } + + [NSApp setApplicationIconImage:icon]; +} + void OS_OSX::set_icon(const Ref<Image> &p_icon) { Ref<Image> img = p_icon; diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index 4006c4c60e..0716ee67f4 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -166,11 +166,16 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { line.SizeOfStruct = sizeof(line); IMAGE_NT_HEADERS *h = ImageNtHeader(base); DWORD image_type = h->FileHeader.Machine; - int n = 0; - String msg = GLOBAL_GET("debug/settings/crash_handler/message"); + + String msg; + const ProjectSettings *proj_settings = ProjectSettings::get_singleton(); + if (proj_settings) { + msg = proj_settings->get("debug/settings/crash_handler/message"); + } fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); + int n = 0; do { if (skip_first) { skip_first = false; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 4c6e4e96b5..6df2ad4821 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2475,7 +2475,13 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) { - argss += String(" \"") + E->get() + "\""; + argss += " \"" + E->get() + "\""; + } + + argss += "\""; + + if (read_stderr) { + argss += " 2>&1"; // Read stderr too } FILE *f = _wpopen(argss.c_str(), L"r"); @@ -2577,6 +2583,117 @@ String OS_Windows::get_executable_path() const { return s; } +void OS_Windows::set_native_icon(const String &p_filename) { + + FileAccess *f = FileAccess::open(p_filename, FileAccess::READ); + ERR_FAIL_COND(!f); + + ICONDIR *icon_dir = (ICONDIR *)memalloc(sizeof(ICONDIR)); + int pos = 0; + + icon_dir->idReserved = f->get_32(); + pos += sizeof(WORD); + f->seek(pos); + + icon_dir->idType = f->get_32(); + pos += sizeof(WORD); + f->seek(pos); + + if (icon_dir->idType != 1) { + ERR_EXPLAIN("Invalid icon file format!"); + ERR_FAIL(); + } + + icon_dir->idCount = f->get_32(); + pos += sizeof(WORD); + f->seek(pos); + + icon_dir = (ICONDIR *)memrealloc(icon_dir, 3 * sizeof(WORD) + icon_dir->idCount * sizeof(ICONDIRENTRY)); + f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY)); + + int small_icon_index = -1; // Select 16x16 with largest color count + int small_icon_cc = 0; + int big_icon_index = -1; // Select largest + int big_icon_width = 16; + int big_icon_cc = 0; + + for (int i = 0; i < icon_dir->idCount; i++) { + int colors = (icon_dir->idEntries[i].bColorCount == 0) ? 32768 : icon_dir->idEntries[i].bColorCount; + int width = (icon_dir->idEntries[i].bWidth == 0) ? 256 : icon_dir->idEntries[i].bWidth; + if (width == 16) { + if (colors >= small_icon_cc) { + small_icon_index = i; + small_icon_cc = colors; + } + } + if (width >= big_icon_width) { + if (colors >= big_icon_cc) { + big_icon_index = i; + big_icon_width = width; + big_icon_cc = colors; + } + } + } + + if (big_icon_index == -1) { + ERR_EXPLAIN("No valid icons found!"); + ERR_FAIL(); + } + + if (small_icon_index == -1) { + WARN_PRINTS("No small icon found, reusing " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon!"); + small_icon_index = big_icon_index; + small_icon_cc = big_icon_cc; + } + + // Read the big icon + DWORD bytecount_big = icon_dir->idEntries[big_icon_index].dwBytesInRes; + Vector<uint8_t> data_big; + data_big.resize(bytecount_big); + pos = icon_dir->idEntries[big_icon_index].dwImageOffset; + f->seek(pos); + f->get_buffer((uint8_t *)&data_big.write[0], bytecount_big); + HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000); + if (!icon_big) { + ERR_EXPLAIN("Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError())); + ERR_FAIL(); + } + + // Read the small icon + DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes; + Vector<uint8_t> data_small; + data_small.resize(bytecount_small); + pos = icon_dir->idEntries[small_icon_index].dwImageOffset; + f->seek(pos); + f->get_buffer((uint8_t *)&data_small.write[0], bytecount_small); + HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000); + if (!icon_small) { + ERR_EXPLAIN("Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError())); + ERR_FAIL(); + } + + // Online tradition says to be sure last error is cleared and set the small icon first + int err = 0; + SetLastError(err); + + SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_small); + err = GetLastError(); + if (err) { + ERR_EXPLAIN("Error setting ICON_SMALL: " + format_error_message(err)); + ERR_FAIL(); + } + + SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big); + err = GetLastError(); + if (err) { + ERR_EXPLAIN("Error setting ICON_BIG: " + format_error_message(err)); + ERR_FAIL(); + } + + memdelete(f); + memdelete(icon_dir); +} + void OS_Windows::set_icon(const Ref<Image> &p_icon) { ERR_FAIL_COND(!p_icon.is_valid()); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 59aeb01b51..0aacbcb9ff 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -58,6 +58,25 @@ /** @author Juan Linietsky <reduzio@gmail.com> */ + +typedef struct { + BYTE bWidth; // Width, in pixels, of the image + BYTE bHeight; // Height, in pixels, of the image + BYTE bColorCount; // Number of colors in image (0 if >=8bpp) + BYTE bReserved; // Reserved ( must be 0) + WORD wPlanes; // Color Planes + WORD wBitCount; // Bits per pixel + DWORD dwBytesInRes; // How many bytes in this resource? + DWORD dwImageOffset; // Where in the file is this image? +} ICONDIRENTRY, *LPICONDIRENTRY; + +typedef struct { + WORD idReserved; // Reserved (must be 0) + WORD idType; // Resource Type (1 for icons) + WORD idCount; // How many images? + ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em) +} ICONDIR, *LPICONDIR; + class JoypadWindows; class OS_Windows : public OS { @@ -276,6 +295,8 @@ public: CursorShape get_cursor_shape() const; 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_native_icon(const String &p_filename); void set_icon(const Ref<Image> &p_icon); virtual String get_executable_path() const; diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp index aadf7ee36d..9718b03164 100644 --- a/platform/x11/context_gl_x11.cpp +++ b/platform/x11/context_gl_x11.cpp @@ -191,6 +191,7 @@ Error ContextGL_X11::initialize() { swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa); + XStoreName(x11_display, x11_window, "Godot Engine"); ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED); set_class_hint(x11_display, x11_window); diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp index 44d3cf1910..ca7251078f 100644 --- a/platform/x11/crash_handler_x11.cpp +++ b/platform/x11/crash_handler_x11.cpp @@ -53,7 +53,12 @@ static void handle_crash(int sig) { void *bt_buffer[256]; size_t size = backtrace(bt_buffer, 256); String _execpath = OS::get_singleton()->get_executable_path(); - String msg = GLOBAL_GET("debug/settings/crash_handler/message"); + + String msg; + const ProjectSettings *proj_settings = ProjectSettings::get_singleton(); + if (proj_settings) { + msg = proj_settings->get("debug/settings/crash_handler/message"); + } // Dump the backtrace to stderr with a message to the user fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 56389578f7..f034b2389b 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -534,22 +534,26 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a } { - Pixmap cursormask; - XGCValues xgc; - GC gc; - XColor col; - Cursor cursor; + // Creating an empty/transparent cursor + + // Create 1x1 bitmap + Pixmap cursormask = XCreatePixmap(x11_display, + RootWindow(x11_display, DefaultScreen(x11_display)), 1, 1, 1); - cursormask = XCreatePixmap(x11_display, RootWindow(x11_display, DefaultScreen(x11_display)), 1, 1, 1); + // Fill with zero + XGCValues xgc; xgc.function = GXclear; - gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc); + GC gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc); XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1); - col.pixel = 0; - col.red = 0; - col.flags = 4; - cursor = XCreatePixmapCursor(x11_display, - cursormask, cursormask, + + // Color value doesn't matter. Mask zero means no foreground or background will be drawn + XColor col = {}; + + Cursor cursor = XCreatePixmapCursor(x11_display, + cursormask, // source (using cursor mask as placeholder, since it'll all be ignored) + cursormask, // mask &col, &col, 0, 0); + XFreePixmap(x11_display, cursormask); XFreeGC(x11_display, gc); diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index bd7bb97b03..009d664462 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -70,7 +70,7 @@ void CanvasModulate::_bind_methods() { void CanvasModulate::set_color(const Color &p_color) { color = p_color; - if (is_inside_tree()) { + if (is_visible_in_tree()) { VS::get_singleton()->canvas_set_modulate(get_canvas(), color); } } diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index 0f6af358bd..e389d5f98f 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -312,7 +312,7 @@ void NavigationPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines); ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines"); } diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 4097006b33..e062067248 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -264,7 +264,7 @@ void PathFollow2D::_validate_property(PropertyInfo &property) const { if (path && path->get_curve().is_valid()) max = path->get_curve()->get_baked_length(); - property.hint_string = "0," + rtos(max) + ",0.01,or_greater"; + property.hint_string = "0," + rtos(max) + ",0.01,or_lesser"; } } @@ -306,8 +306,8 @@ void PathFollow2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead); ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotate"), "set_rotate", "is_rotating"); @@ -319,8 +319,24 @@ void PathFollow2D::_bind_methods() { void PathFollow2D::set_offset(float p_offset) { offset = p_offset; - if (path) + if (path) { + if (path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { + float path_length = path->get_curve()->get_baked_length(); + + if (loop) { + while (offset > path_length) + offset -= path_length; + + while (offset < 0) + offset += path_length; + + } else { + offset = CLAMP(offset, 0, path_length); + } + } + _update_transform(); + } _change_notify("offset"); _change_notify("unit_offset"); } diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index cf9877e6f8..d24c0a1561 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -39,6 +39,9 @@ class Bone2D : public Node2D { GDCLASS(Bone2D, Node2D) friend class Skeleton2D; +#ifdef TOOLS_ENABLED + friend class AnimatedValuesBackup; +#endif Bone2D *parent_bone; Skeleton2D *skeleton; @@ -71,6 +74,9 @@ class Skeleton2D : public Node2D { GDCLASS(Skeleton2D, Node2D); friend class Bone2D; +#ifdef TOOLS_ENABLED + friend class AnimatedValuesBackup; +#endif struct Bone { bool operator<(const Bone &p_bone) const { diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 3dc0f46676..86be8762d4 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -202,47 +202,27 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Size2 s = p_sc; Vector2 offset = p_offset; - if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) - offset.y += cell_size.y; - else if (tile_origin == TILE_ORIGIN_CENTER) { - offset += cell_size / 2; - } - - if (s.y > s.x) { - if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose)) - offset.y += s.y - s.x; - } else if (s.y < s.x) { - if ((p_cell.flip_v && (p_cell.flip_h || p_cell.transpose)) || (p_cell.flip_h && !p_cell.transpose)) - offset.x += s.x - s.y; - } - if (p_cell.transpose) { SWAP(xform.elements[0].x, xform.elements[0].y); SWAP(xform.elements[1].x, xform.elements[1].y); SWAP(offset.x, offset.y); SWAP(s.x, s.y); } + if (p_cell.flip_h) { xform.elements[0].x = -xform.elements[0].x; xform.elements[1].x = -xform.elements[1].x; - if (tile_origin == TILE_ORIGIN_TOP_LEFT || tile_origin == TILE_ORIGIN_BOTTOM_LEFT) - offset.x = s.x - offset.x; - else if (tile_origin == TILE_ORIGIN_CENTER) - offset.x = s.x - offset.x / 2; + offset.x = s.x - offset.x; } + if (p_cell.flip_v) { xform.elements[0].y = -xform.elements[0].y; xform.elements[1].y = -xform.elements[1].y; - if (tile_origin == TILE_ORIGIN_TOP_LEFT) - offset.y = s.y - offset.y; - else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - offset.y += s.y; - } else if (tile_origin == TILE_ORIGIN_CENTER) { - offset.y += s.y; - } + offset.y = s.y - offset.y; } - xform.elements[2].x += offset.x; - xform.elements[2].y += offset.y; + + offset += cell_size / 2 - s / 2; + xform.elements[2] += offset; } void TileMap::update_dirty_quadrants() { @@ -390,64 +370,25 @@ void TileMap::update_dirty_quadrants() { rect.size.x += fp_adjust; rect.size.y += fp_adjust; - if (rect.size.y > rect.size.x) { - if ((c.flip_h && (c.flip_v || c.transpose)) || (c.flip_v && !c.transpose)) - tile_ofs.y += rect.size.y - rect.size.x; - } else if (rect.size.y < rect.size.x) { - if ((c.flip_v && (c.flip_h || c.transpose)) || (c.flip_h && !c.transpose)) - tile_ofs.x += rect.size.x - rect.size.y; - } - - /* rect.size.x+=fp_adjust; - rect.size.y+=fp_adjust;*/ - - if (c.transpose) + if (c.transpose) { SWAP(tile_ofs.x, tile_ofs.y); + rect.position.x += cell_size.x / 2 - rect.size.y / 2; + rect.position.y += cell_size.y / 2 - rect.size.x / 2; + } else { + rect.position += cell_size / 2 - rect.size / 2; + } if (c.flip_h) { rect.size.x = -rect.size.x; tile_ofs.x = -tile_ofs.x; } + if (c.flip_v) { rect.size.y = -rect.size.y; tile_ofs.y = -tile_ofs.y; } - Vector2 center_ofs; - - if (tile_origin == TILE_ORIGIN_TOP_LEFT) { - rect.position += tile_ofs; - - } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - - rect.position += tile_ofs; - - if (c.transpose) { - if (c.flip_h) - rect.position.x -= cell_size.x; - else - rect.position.x += cell_size.x; - } else { - if (c.flip_v) - rect.position.y -= cell_size.y; - else - rect.position.y += cell_size.y; - } - - } else if (tile_origin == TILE_ORIGIN_CENTER) { - - rect.position += tile_ofs; - - if (c.flip_h) - rect.position.x -= cell_size.x / 2; - else - rect.position.x += cell_size.x / 2; - - if (c.flip_v) - rect.position.y -= cell_size.y / 2; - else - rect.position.y += cell_size.y / 2; - } + rect.position += tile_ofs; Ref<Texture> normal_map = tile_set->tile_get_normal_map(c.id); Color modulate = tile_set->tile_get_modulate(c.id); @@ -471,7 +412,7 @@ void TileMap::update_dirty_quadrants() { Vector2 shape_ofs = shapes[j].shape_transform.get_origin(); - _fix_cell_transform(xform, c, shape_ofs + center_ofs, s); + _fix_cell_transform(xform, c, shape_ofs, s); xform *= shapes[j].shape_transform.untranslated(); @@ -523,7 +464,7 @@ void TileMap::update_dirty_quadrants() { if (navpoly.is_valid()) { Transform2D xform; xform.set_origin(offset.floor() + q.pos); - _fix_cell_transform(xform, c, npoly_ofs + center_ofs, s); + _fix_cell_transform(xform, c, npoly_ofs, s); int pid = navigation->navpoly_add(navpoly, nav_rel * xform); @@ -573,7 +514,7 @@ void TileMap::update_dirty_quadrants() { } Transform2D navxform; navxform.set_origin(offset.floor()); - _fix_cell_transform(navxform, c, npoly_ofs + center_ofs, s); + _fix_cell_transform(navxform, c, npoly_ofs, s); vs->canvas_item_set_transform(debug_navigation_item, navxform); vs->canvas_item_add_triangle_array(debug_navigation_item, indices, vertices, colors); @@ -593,7 +534,7 @@ void TileMap::update_dirty_quadrants() { Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id); Transform2D xform; xform.set_origin(offset.floor() + q.pos); - _fix_cell_transform(xform, c, occluder_ofs + center_ofs, s); + _fix_cell_transform(xform, c, occluder_ofs, s); RID orid = VS::get_singleton()->canvas_light_occluder_create(); VS::get_singleton()->canvas_light_occluder_set_transform(orid, get_global_transform() * xform); diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp index 52fa96ee4a..4e88948ce2 100644 --- a/scene/3d/arvr_nodes.cpp +++ b/scene/3d/arvr_nodes.cpp @@ -127,7 +127,7 @@ Point2 ARVRCamera::unproject_position(const Vector3 &p_pos) const { return res; }; -Vector3 ARVRCamera::project_position(const Point2 &p_point) const { +Vector3 ARVRCamera::project_position(const Point2 &p_point, float p_z_depth) const { // get our ARVRServer ARVRServer *arvr_server = ARVRServer::get_singleton(); ERR_FAIL_NULL_V(arvr_server, Vector3()); @@ -135,7 +135,7 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const { Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface(); if (arvr_interface.is_null()) { // we might be in the editor or have VR turned off, just call superclass - return Camera::project_position(p_point); + return Camera::project_position(p_point, p_z_depth); } if (!is_inside_tree()) { @@ -155,7 +155,7 @@ Vector3 ARVRCamera::project_position(const Point2 &p_point) const { point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0; point *= vp_size; - Vector3 p(point.x, point.y, -get_znear()); + Vector3 p(point.x, point.y, -p_z_depth); return get_camera_transform().xform(p); }; diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h index 0833e18d48..8e735f7110 100644 --- a/scene/3d/arvr_nodes.h +++ b/scene/3d/arvr_nodes.h @@ -55,7 +55,7 @@ public: virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; - virtual Vector3 project_position(const Point2 &p_point) const; + virtual Vector3 project_position(const Point2 &p_point, float p_z_depth = 0) const; virtual Vector<Plane> get_frustum() const; ARVRCamera(); diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 8b91f56344..29002c6701 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -391,13 +391,17 @@ Point2 Camera::unproject_position(const Vector3 &p_pos) const { return res; } -Vector3 Camera::project_position(const Point2 &p_point) const { +Vector3 Camera::project_position(const Point2 &p_point, float p_z_depth) const { if (!is_inside_tree()) { ERR_EXPLAIN("Camera is not inside scene."); ERR_FAIL_COND_V(!is_inside_tree(), Vector3()); } + if (p_z_depth == 0) { + return get_global_transform().origin; + } + Size2 viewport_size = get_viewport()->get_visible_rect().size; CameraMatrix cm; @@ -415,7 +419,7 @@ Vector3 Camera::project_position(const Point2 &p_point) const { point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0; point *= vp_size; - Vector3 p(point.x, point.y, -near); + Vector3 p(point.x, point.y, -p_z_depth); return get_camera_transform().xform(p); } @@ -490,7 +494,7 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("project_ray_origin", "screen_point"), &Camera::project_ray_origin); ClassDB::bind_method(D_METHOD("unproject_position", "world_point"), &Camera::unproject_position); ClassDB::bind_method(D_METHOD("is_position_behind", "world_point"), &Camera::is_position_behind); - ClassDB::bind_method(D_METHOD("project_position", "screen_point"), &Camera::project_position); + ClassDB::bind_method(D_METHOD("project_position", "screen_point", "z_depth"), &Camera::project_position, DEFVAL(0)); ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective); ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal); ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera::set_frustum); @@ -524,6 +528,7 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking); ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking); ClassDB::bind_method(D_METHOD("get_frustum"), &Camera::get_frustum); + ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera::get_camera); ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit); ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit); diff --git a/scene/3d/camera.h b/scene/3d/camera.h index fe8cb84f0d..cbcefbb0ae 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -143,7 +143,7 @@ public: virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; bool is_position_behind(const Vector3 &p_pos) const; - virtual Vector3 project_position(const Point2 &p_point) const; + virtual Vector3 project_position(const Point2 &p_point, float p_z_depth = 0) const; Vector<Vector3> get_near_plane_points() const; diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index d4e242dcb7..138c446fea 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -212,7 +212,7 @@ String CPUParticles::get_configuration_warning() const { get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) { if (warnings != String()) warnings += "\n"; - warnings += "- " + TTR("CPUParticles animation requires the usage of a SpatialMaterial with \"Billboard Particles\" enabled."); + warnings += "- " + TTR("CPUParticles animation requires the usage of a SpatialMaterial whose Billboard Mode is set to \"Particle Billboard\"."); } return warnings; diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 003f76664d..f82543b789 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -73,6 +73,41 @@ int NavigationMesh::get_sample_partition_type() const { return static_cast<int>(partition_type); } +void NavigationMesh::set_parsed_geometry_type(int p_value) { + ERR_FAIL_COND(p_value >= PARSED_GEOMETRY_MAX); + parsed_geometry_type = static_cast<ParsedGeometryType>(p_value); + _change_notify(); +} + +int NavigationMesh::get_parsed_geometry_type() const { + return parsed_geometry_type; +} + +void NavigationMesh::set_collision_mask(uint32_t p_mask) { + + collision_mask = p_mask; +} + +uint32_t NavigationMesh::get_collision_mask() const { + + return collision_mask; +} + +void NavigationMesh::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 NavigationMesh::get_collision_mask_bit(int p_bit) const { + + return get_collision_mask() & (1 << p_bit); +} + void NavigationMesh::set_cell_size(float p_value) { cell_size = p_value; } @@ -204,6 +239,7 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const { void NavigationMesh::set_vertices(const PoolVector<Vector3> &p_vertices) { vertices = p_vertices; + _change_notify(); } PoolVector<Vector3> NavigationMesh::get_vertices() const { @@ -217,6 +253,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) { for (int i = 0; i < p_array.size(); i++) { polygons.write[i].indices = p_array[i]; } + _change_notify(); } Array NavigationMesh::_get_polygons() const { @@ -235,6 +272,7 @@ void NavigationMesh::add_polygon(const Vector<int> &p_polygon) { Polygon polygon; polygon.indices = p_polygon; polygons.push_back(polygon); + _change_notify(); } int NavigationMesh::get_polygon_count() const { @@ -340,6 +378,15 @@ void NavigationMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type); ClassDB::bind_method(D_METHOD("get_sample_partition_type"), &NavigationMesh::get_sample_partition_type); + ClassDB::bind_method(D_METHOD("set_parsed_geometry_type", "geometry_type"), &NavigationMesh::set_parsed_geometry_type); + ClassDB::bind_method(D_METHOD("get_parsed_geometry_type"), &NavigationMesh::get_parsed_geometry_type); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &NavigationMesh::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &NavigationMesh::get_collision_mask); + + ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &NavigationMesh::set_collision_mask_bit); + ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &NavigationMesh::get_collision_mask_bit); + ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationMesh::set_cell_size); ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_cell_size); @@ -405,10 +452,16 @@ void NavigationMesh::_bind_methods() { BIND_CONSTANT(SAMPLE_PARTITION_MONOTONE); BIND_CONSTANT(SAMPLE_PARTITION_LAYERS); + BIND_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES); + BIND_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS); + BIND_CONSTANT(PARSED_GEOMETRY_BOTH); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height"); @@ -429,6 +482,15 @@ void NavigationMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans"); } +void NavigationMesh::_validate_property(PropertyInfo &property) const { + if (property.name == "geometry/collision_mask") { + if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) { + property.usage = 0; + return; + } + } +} + NavigationMesh::NavigationMesh() { cell_size = 0.3f; cell_height = 0.2f; @@ -445,7 +507,8 @@ NavigationMesh::NavigationMesh() { detail_sample_max_error = 1.0f; partition_type = SAMPLE_PARTITION_WATERSHED; - + parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES; + collision_mask = 0xFFFFFFFF; filter_low_hanging_obstacles = false; filter_ledge_spans = false; filter_walkable_low_height_spans = false; @@ -566,8 +629,17 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_na navigation->navmesh_remove(nav_id); nav_id = -1; } + + if (navmesh.is_valid()) { + navmesh->remove_change_receptor(this); + } + navmesh = p_navmesh; + if (navmesh.is_valid()) { + navmesh->add_change_receptor(this); + } + if (navigation && navmesh.is_valid() && enabled) { nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); } @@ -617,6 +689,11 @@ void NavigationMeshInstance::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); } +void NavigationMeshInstance::_changed_callback(Object *p_changed, const char *p_prop) { + update_gizmo(); + update_configuration_warning(); +} + NavigationMeshInstance::NavigationMeshInstance() { debug_view = NULL; @@ -625,3 +702,8 @@ NavigationMeshInstance::NavigationMeshInstance() { enabled = true; set_notify_transform(true); } + +NavigationMeshInstance::~NavigationMeshInstance() { + if (navmesh.is_valid()) + navmesh->remove_change_receptor(this); +} diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h index 74531e2423..5fbf3998ff 100644 --- a/scene/3d/navigation_mesh.h +++ b/scene/3d/navigation_mesh.h @@ -57,6 +57,7 @@ class NavigationMesh : public Resource { protected: static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const; void _set_polygons(const Array &p_array); Array _get_polygons() const; @@ -69,6 +70,13 @@ public: SAMPLE_PARTITION_MAX }; + enum ParsedGeometryType { + PARSED_GEOMETRY_MESH_INSTANCES = 0, + PARSED_GEOMETRY_STATIC_COLLIDERS, + PARSED_GEOMETRY_BOTH, + PARSED_GEOMETRY_MAX + }; + protected: float cell_size; float cell_height; @@ -85,6 +93,8 @@ protected: float detail_sample_max_error; SamplePartitionType partition_type; + ParsedGeometryType parsed_geometry_type; + uint32_t collision_mask; bool filter_low_hanging_obstacles; bool filter_ledge_spans; @@ -95,6 +105,15 @@ public: void set_sample_partition_type(int p_value); int get_sample_partition_type() const; + void set_parsed_geometry_type(int p_value); + int get_parsed_geometry_type() const; + + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; + + void set_collision_mask_bit(int p_bit, bool p_value); + bool get_collision_mask_bit(int p_bit) const; + void set_cell_size(float p_value); float get_cell_size() const; @@ -174,6 +193,7 @@ class NavigationMeshInstance : public Spatial { protected: void _notification(int p_what); static void _bind_methods(); + void _changed_callback(Object *p_changed, const char *p_prop); public: void set_enabled(bool p_enabled); @@ -185,6 +205,7 @@ public: String get_configuration_warning() const; NavigationMeshInstance(); + ~NavigationMeshInstance(); }; #endif // NAVIGATION_MESH_H diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 57ab01f7be..156560f802 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -268,7 +268,7 @@ String Particles::get_configuration_warning() const { process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { if (warnings != String()) warnings += "\n"; - warnings += "- " + TTR("Particles animation requires the usage of a SpatialMaterial with \"Billboard Particles\" enabled."); + warnings += "- " + TTR("Particles animation requires the usage of a SpatialMaterial whose Billboard Mode is set to \"Particle Billboard\"."); } } diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp index 12eab2e4e8..96dc3304f2 100644 --- a/scene/3d/proximity_group.cpp +++ b/scene/3d/proximity_group.cpp @@ -204,6 +204,7 @@ ProximityGroup::ProximityGroup() { group_version = 0; dispatch_mode = MODE_PROXY; + cell_size = 1.0; grid_radius = Vector3(1, 1, 1); set_notify_transform(true); }; diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 05fd984f93..efd418e3c7 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -676,28 +676,29 @@ void Spatial::set_identity() { void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) { - Transform lookat(get_global_transform()); - if (lookat.origin == p_target) { + Vector3 origin(get_global_transform().origin); + look_at_from_position(origin, p_target, p_up); +} + +void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { + + if (p_pos == p_target) { ERR_EXPLAIN("Node origin and target are in the same position, look_at() failed"); ERR_FAIL(); } - if (p_up.cross(p_target - lookat.origin) == Vector3()) { + if (p_up.cross(p_target - p_pos) == Vector3()) { ERR_EXPLAIN("Up vector and direction between node origin and target are aligned, look_at() failed"); ERR_FAIL(); } - Vector3 original_scale(lookat.basis.get_scale()); - lookat = lookat.looking_at(p_target, p_up); - // as basis was normalized, we just need to apply original scale back - lookat.basis.scale(original_scale); - set_global_transform(lookat); -} - -void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { Transform lookat; lookat.origin = p_pos; + + Vector3 original_scale(get_global_transform().basis.get_scale()); lookat = lookat.looking_at(p_target, p_up); + // as basis was normalized, we just need to apply original scale back + lookat.basis.scale(original_scale); set_global_transform(lookat); } diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index fde135c972..32b8219ee0 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -270,6 +270,8 @@ void VehicleWheel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_skidinfo"), &VehicleWheel::get_skidinfo); + ClassDB::bind_method(D_METHOD("get_rpm"), &VehicleWheel::get_rpm); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering"); ADD_GROUP("Wheel", "wheel_"); @@ -311,6 +313,11 @@ float VehicleWheel::get_skidinfo() const { return m_skidInfo; } +float VehicleWheel::get_rpm() const { + + return m_rpm; +} + VehicleWheel::VehicleWheel() { steers = false; @@ -865,12 +872,11 @@ void VehicleBody::_direct_state_changed(Object *p_state) { real_t proj2 = fwd.dot(vel); wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius); - wheel.m_rotation += wheel.m_deltaRotation; - - } else { - wheel.m_rotation += wheel.m_deltaRotation; } + wheel.m_rotation += wheel.m_deltaRotation; + wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math_TAU; + wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact } diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h index 7e7571df4d..9e3fe72282 100644 --- a/scene/3d/vehicle_body.h +++ b/scene/3d/vehicle_body.h @@ -68,6 +68,7 @@ class VehicleWheel : public Spatial { real_t m_steering; real_t m_rotation; real_t m_deltaRotation; + real_t m_rpm; real_t m_rollInfluence; //real_t m_engineForce; real_t m_brake; @@ -134,6 +135,8 @@ public: float get_skidinfo() const; + float get_rpm() const; + String get_configuration_warning() const; VehicleWheel(); diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 1aded826c0..99c86f0406 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -271,6 +271,11 @@ float GeometryInstance::get_extra_cull_margin() const { return extra_cull_margin; } +void GeometryInstance::set_custom_aabb(AABB aabb) { + + VS::get_singleton()->instance_set_custom_aabb(get_instance(), aabb); +} + void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance::set_material_override); @@ -297,6 +302,8 @@ void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance::set_extra_cull_margin); ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin); + ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance::set_custom_aabb); + ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb); ADD_GROUP("Geometry", ""); diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index f5b7479bb1..0e7d9be505 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -139,6 +139,8 @@ public: void set_extra_cull_margin(float p_margin); float get_extra_cull_margin() const; + void set_custom_aabb(AABB aabb); + GeometryInstance(); }; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 1e3470cd90..60f8806b25 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -314,8 +314,9 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, if (start_request_travel) { if (!playing) { + String node_name = start_request; start_request = StringName(); - ERR_EXPLAIN("Can't travel to '" + String(start_request) + "' if state machine is not active."); + ERR_EXPLAIN("Can't travel to '" + node_name + "' if state machine is not playing."); ERR_FAIL_V(0); } diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index a5955d57f7..75088c79fe 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -37,12 +37,20 @@ #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" +#include "scene/2d/skeleton_2d.h" void AnimatedValuesBackup::update_skeletons() { for (int i = 0; i < entries.size(); i++) { if (entries[i].bone_idx != -1) { + // 3D bone Object::cast_to<Skeleton>(entries[i].object)->notification(Skeleton::NOTIFICATION_UPDATE_SKELETON); + } else { + Bone2D *bone = Object::cast_to<Bone2D>(entries[i].object); + if (bone && bone->skeleton) { + // 2D bone + bone->skeleton->_update_transform(); + } } } } diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index d1d3582c9d..8247728b9d 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -1580,6 +1580,7 @@ AnimationTree::AnimationTree() { active = false; cache_valid = false; setup_pass = 1; + process_pass = 1; started = true; properties_dirty = true; last_animation_player = 0; diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index e95781c181..5ef2557383 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -56,185 +56,53 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) { if (status.disabled) // no interaction with disabled button return; - Ref<InputEventMouseButton> b = p_event; + Ref<InputEventMouseButton> mouse_button = p_event; + bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo(); - if (b.is_valid()) { - if (((1 << (b->get_button_index() - 1)) & button_mask) == 0) - return; - - if (status.pressing_button) - return; - - if (action_mode == ACTION_MODE_BUTTON_PRESS) { - - if (b->is_pressed()) { - - emit_signal("button_down"); - - if (!toggle_mode) { //mouse press attempt - - status.press_attempt = true; - status.pressing_inside = true; + bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) > 0; + if (button_masked || ui_accept) { + if (p_event->is_pressed()) { + status.press_attempt = true; + status.pressing_inside = true; + emit_signal("button_down"); + } - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); + if (status.press_attempt && status.pressing_inside) { + if (toggle_mode) { + if ((p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_PRESS) || (!p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_RELEASE)) { + if (action_mode == ACTION_MODE_BUTTON_PRESS) { + status.press_attempt = false; + status.pressing_inside = false; } - - _unpress_group(); - emit_signal("pressed"); - - } else { - status.pressed = !status.pressed; - pressed(); - _unpress_group(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); + _toggled(status.pressed); + _pressed(); } - } else { - - emit_signal("button_up"); - - /* this is pointless if (status.press_attempt && status.pressing_inside) { - //released(); - emit_signal("released"); + if (!p_event->is_pressed()) { + _pressed(); } -*/ - status.press_attempt = false; } - update(); - return; } - if (b->is_pressed()) { - - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - - } else { - + if (!p_event->is_pressed()) { // pressed state should be correct with button_up signal emit_signal("button_up"); - - if (status.press_attempt && status.pressing_inside) { - - if (!toggle_mode) { //mouse press attempt - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - _unpress_group(); - emit_signal("pressed"); - - } else { - - status.pressed = !status.pressed; - - pressed(); - _unpress_group(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } - } - status.press_attempt = false; } update(); + return; } - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - if (status.press_attempt && status.pressing_button == 0) { + Ref<InputEventMouseMotion> mouse_motion = p_event; + if (mouse_motion.is_valid()) { + if (status.press_attempt) { bool last_press_inside = status.pressing_inside; - status.pressing_inside = has_point(mm->get_position()); - if (last_press_inside != status.pressing_inside) + status.pressing_inside = has_point(mouse_motion->get_position()); + if (last_press_inside != status.pressing_inside) { update(); - } - } - - if (!mm.is_valid() && !b.is_valid()) { - - if (p_event->is_echo()) { - return; - } - - if (status.disabled) { - return; - } - - if (status.press_attempt && status.pressing_button == 0) { - return; - } - - if (p_event->is_action("ui_accept")) { - - if (p_event->is_pressed()) { - - status.pressing_button++; - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - - } else if (status.press_attempt) { - - if (status.pressing_button) - status.pressing_button--; - - if (status.pressing_button) - return; - - status.press_attempt = false; - status.pressing_inside = false; - - emit_signal("button_up"); - - if (!toggle_mode) { //mouse press attempt - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - _unpress_group(); - emit_signal("pressed"); - } else { - - status.pressed = !status.pressed; - - pressed(); - _unpress_group(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } } - - accept_event(); - update(); } } } @@ -255,7 +123,6 @@ void BaseButton::_notification(int p_what) { if (status.press_attempt) { status.press_attempt = false; - status.pressing_button = 0; update(); } } @@ -268,9 +135,8 @@ void BaseButton::_notification(int p_what) { if (p_what == NOTIFICATION_FOCUS_EXIT) { - if (status.pressing_button && status.press_attempt) { + if (status.press_attempt) { status.press_attempt = false; - status.pressing_button = 0; status.hovering = false; update(); } else if (status.hovering) { @@ -290,21 +156,31 @@ void BaseButton::_notification(int p_what) { status.hovering = false; status.press_attempt = false; status.pressing_inside = false; - status.pressing_button = 0; } } -void BaseButton::pressed() { +void BaseButton::_pressed() { - if (get_script_instance()) - get_script_instance()->call("pressed"); + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_pressed); + } + pressed(); + emit_signal("pressed"); } -void BaseButton::toggled(bool p_pressed) { +void BaseButton::_toggled(bool p_pressed) { if (get_script_instance()) { - get_script_instance()->call("toggled", p_pressed); + get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, p_pressed); } + toggled(p_pressed); + emit_signal("toggled", p_pressed); +} + +void BaseButton::pressed() { +} + +void BaseButton::toggled(bool p_pressed) { } void BaseButton::set_disabled(bool p_disabled) { @@ -318,7 +194,6 @@ void BaseButton::set_disabled(bool p_disabled) { } status.press_attempt = false; status.pressing_inside = false; - status.pressing_button = 0; } update(); _change_notify("disabled"); @@ -341,6 +216,10 @@ void BaseButton::set_pressed(bool p_pressed) { if (p_pressed) { _unpress_group(); } + if (toggle_mode) { + _toggled(status.pressed); + } + update(); } @@ -585,7 +464,6 @@ BaseButton::BaseButton() { status.hovering = false; status.pressing_inside = false; status.disabled = false; - status.pressing_button = 0; set_focus_mode(FOCUS_ALL); enabled_focus_mode = FOCUS_ALL; action_mode = ACTION_MODE_BUTTON_RELEASE; diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 22a8f6d8fe..abb3f58d6b 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -65,13 +65,14 @@ private: bool pressing_inside; bool disabled; - int pressing_button; } status; Ref<ButtonGroup> button_group; void _unpress_group(); + void _pressed(); + void _toggled(bool p_pressed); protected: virtual void pressed(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 026374ded1..406c8e4f48 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -470,6 +470,8 @@ Size2 ItemList::Item::get_icon_size() const { void ItemList::_gui_input(const Ref<InputEvent> &p_event) { + double prev_scroll = scroll_bar->get_value(); + Ref<InputEventMouseMotion> mm = p_event; if (defer_select_single >= 0 && mm.is_valid()) { defer_select_single = -1; @@ -767,6 +769,9 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * pan_gesture->get_delta().y / 8); } + + if (scroll_bar->get_value() != prev_scroll) + accept_event(); //accept event if scroll changed } void ItemList::ensure_current_is_visible() { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 2d18a80833..1f778bc516 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -68,6 +68,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { _reset_caret_blink_timer(); if (b->is_pressed()) { + accept_event(); //don't pass event further when clicked on text field if (!text.empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; clear_button_status.pressing_inside = true; @@ -159,6 +160,38 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (!k->is_pressed()) return; + +#ifdef APPLE_STYLE_KEYS + if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) { + uint32_t remap_key = KEY_UNKNOWN; + switch (k->get_scancode()) { + case KEY_F: { + remap_key = KEY_RIGHT; + } break; + case KEY_B: { + remap_key = KEY_LEFT; + } break; + case KEY_P: { + remap_key = KEY_UP; + } break; + case KEY_N: { + remap_key = KEY_DOWN; + } break; + case KEY_D: { + remap_key = KEY_DELETE; + } break; + case KEY_H: { + remap_key = KEY_BACKSPACE; + } break; + } + + if (remap_key != KEY_UNKNOWN) { + k->set_scancode(remap_key); + k->set_control(false); + } + } +#endif + unsigned int code = k->get_scancode(); if (k->get_command()) { @@ -1656,6 +1689,7 @@ LineEdit::LineEdit() { context_menu_enabled = true; menu = memnew(PopupMenu); add_child(menu); + editable = false; // initialise to opposite first, so we get past the early-out in set_editable set_editable(true); menu->connect("id_pressed", this, "menu_option"); expand_to_text_length = false; diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index b7601bdd3e..fdb1b65f77 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -115,6 +115,18 @@ void Popup::set_as_minsize() { set_size(total_minsize); } +void Popup::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) { + + Size2 popup_size = p_size; + Size2 window_size = get_viewport_rect().size; + + // clamp popup size in each dimension if window size is too small (using fallback ratio) + popup_size.x = MIN(window_size.x * p_fallback_ratio, popup_size.x); + popup_size.y = MIN(window_size.y * p_fallback_ratio, popup_size.y); + + popup_centered(popup_size); +} + void Popup::popup_centered_minsize(const Size2 &p_minsize) { set_custom_minimum_size(p_minsize); @@ -179,6 +191,7 @@ void Popup::_bind_methods() { ClassDB::bind_method(D_METHOD("popup_centered", "size"), &Popup::popup_centered, DEFVAL(Size2())); ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Popup::popup_centered_ratio, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("popup_centered_minsize", "minsize"), &Popup::popup_centered_minsize, DEFVAL(Size2())); + ClassDB::bind_method(D_METHOD("popup_centered_clamped", "size", "fallback_ratio"), &Popup::popup_centered_clamped, DEFVAL(Size2()), DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("popup", "bounds"), &Popup::popup, DEFVAL(Rect2())); ClassDB::bind_method(D_METHOD("set_exclusive", "enable"), &Popup::set_exclusive); ClassDB::bind_method(D_METHOD("is_exclusive"), &Popup::is_exclusive); diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 7ccefe1d75..6615c51ec5 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -64,6 +64,7 @@ public: void popup_centered(const Size2 &p_size = Size2()); void popup_centered_minsize(const Size2 &p_minsize = Size2()); void set_as_minsize(); + void popup_centered_clamped(const Size2 &p_size = Size2(), float p_fallback_ratio = 0.75); virtual void popup(const Rect2 &p_bounds = Rect2()); virtual String get_configuration_warning() const; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 101eb2ac88..da452e3f10 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2336,6 +2336,7 @@ RichTextLabel::RichTextLabel() { tab_size = 4; default_align = ALIGN_LEFT; underline_meta = true; + meta_hovering = NULL; override_selected_font_color = false; scroll_visible = false; diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 2938654ed9..686d1c96cc 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -53,29 +53,19 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) { if (b.is_valid()) { accept_event(); - if (b->get_button_index() == 5 && b->is_pressed()) { + if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) { - /* - if (orientation==VERTICAL) - set_val( get_val() + get_page() / 4.0 ); - else - */ set_value(get_value() + get_page() / 4.0); accept_event(); } - if (b->get_button_index() == 4 && b->is_pressed()) { + if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) { - /* - if (orientation==HORIZONTAL) - set_val( get_val() - get_page() / 4.0 ); - else - */ set_value(get_value() - get_page() / 4.0); accept_event(); } - if (b->get_button_index() != 1) + if (b->get_button_index() != BUTTON_LEFT) return; if (b->is_pressed()) { diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index e50a71b0ff..a1034937b5 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -88,13 +88,16 @@ void ScrollContainer::_cancel_drag() { void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { + double prev_v_scroll = v_scroll->get_value(); + double prev_h_scroll = h_scroll->get_value(); + Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { // only horizontal is enabled, scroll horizontally - if (h_scroll->is_visible() && !v_scroll->is_visible()) { + if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) { h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor()); } else if (v_scroll->is_visible_in_tree()) { v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() / 8 * mb->get_factor()); @@ -103,7 +106,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) { // only horizontal is enabled, scroll horizontally - if (h_scroll->is_visible() && !v_scroll->is_visible()) { + if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) { h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor()); } else if (v_scroll->is_visible()) { v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() / 8 * mb->get_factor()); @@ -122,6 +125,9 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + if (!OS::get_singleton()->has_touchscreen_ui_hint()) return; @@ -204,6 +210,9 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8); } } + + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed } void ScrollContainer::_update_scrollbar_position() { diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 028ca41cbf..b777e77bc3 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -295,6 +295,7 @@ Slider::Slider(Orientation p_orientation) { mouse_inside = false; grab.active = false; ticks = 0; + ticks_on_borders = false; custom_step = -1; editable = true; scrollable = true; diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index d21143739c..e778af3ceb 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -277,6 +277,7 @@ SpinBox::SpinBox() { add_child(line_edit); line_edit->set_anchors_and_margins_preset(Control::PRESET_WIDE); + line_edit->set_mouse_filter(MOUSE_FILTER_PASS); //connect("value_changed",this,"_value_changed"); line_edit->connect("text_entered", this, "_text_entered", Vector<Variant>(), CONNECT_DEFERRED); line_edit->connect("focus_exited", this, "_line_edit_focus_exit", Vector<Variant>(), CONNECT_DEFERRED); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1a000d8da5..3117d8c59f 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -104,6 +104,13 @@ static CharType _get_right_pair_symbol(CharType c) { return 0; } +static int _find_first_non_whitespace_column_of_line(const String &line) { + int left = 0; + while (left < line.length() && _is_whitespace(line[left])) + left++; + return left; +} + void TextEdit::Text::set_font(const Ref<Font> &p_font) { font = p_font; @@ -399,6 +406,7 @@ void TextEdit::_update_scrollbars() { cursor.line_ofs = 0; cursor.wrap_ofs = 0; v_scroll->set_value(0); + v_scroll->set_max(0); v_scroll->hide(); } @@ -417,6 +425,7 @@ void TextEdit::_update_scrollbars() { cursor.x_ofs = 0; h_scroll->set_value(0); + h_scroll->set_max(0); h_scroll->hide(); } @@ -1106,7 +1115,7 @@ void TextEdit::_notification(int p_what) { if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) { // draw the wrap indent offset highlight if (line_wrap_index != 0 && j == 0) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, (char_ofs + char_margin), get_row_height()), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, indent_px, get_row_height()), cache.current_line_color); } // if its the last char draw to end of the line if (j == str.length() - 1) { @@ -1645,31 +1654,25 @@ void TextEdit::backspace_at_cursor() { _consume_backspace_for_pair_symbol(prev_line, prev_column); } else { // handle space indentation - if (cursor.column - indent_size >= 0 && indent_using_spaces) { - - // if there is enough spaces to count as a tab + if (cursor.column != 0 && indent_using_spaces) { + // check if there are no other chars before cursor, just indentation bool unindent = true; - for (int i = 1; i <= indent_size; i++) { - if (text[cursor.line][cursor.column - i] != ' ') { - unindent = false; - break; - } - } - - // and it is before the first character int i = 0; while (i < cursor.column && i < text[cursor.line].length()) { - if (text[cursor.line][i] != ' ' && text[cursor.line][i] != '\t') { + if (!_is_whitespace(text[cursor.line][i])) { unindent = false; break; } i++; } - // then we can remove it as a single character. + // then we can remove all spaces as a single character. if (unindent) { - _remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column); - prev_column = cursor.column - indent_size; + // we want to remove spaces up to closest indent + // or whole indent if cursor is pointing at it + int spaces_to_delete = _calculate_spaces_till_next_left_indent(cursor.column); + prev_column = cursor.column - spaces_to_delete; + _remove_text(cursor.line, prev_column, cursor.line, cursor.column); } else { _remove_text(prev_line, prev_column, cursor.line, cursor.column); } @@ -1686,6 +1689,10 @@ void TextEdit::indent_right() { int start_line; int end_line; + + // this value informs us by how much we changed selection position by indenting right + // default is 1 for tab indentation + int selection_offset = 1; begin_complex_operation(); if (is_selection_active()) { @@ -1704,18 +1711,24 @@ void TextEdit::indent_right() { for (int i = start_line; i <= end_line; i++) { String line_text = get_line(i); if (indent_using_spaces) { - line_text = space_indent + line_text; + // we don't really care where selection is - we just need to know indentation level at the beginning of the line + int left = _find_first_non_whitespace_column_of_line(line_text); + int spaces_to_add = _calculate_spaces_till_next_right_indent(left); + // since we will add this much spaces we want move whole selection and cursor by this much + selection_offset = spaces_to_add; + for (int j = 0; j < spaces_to_add; j++) + line_text = ' ' + line_text; } else { line_text = '\t' + line_text; } set_line(i, line_text); } - // fix selection and cursor being off by one on the last line + // fix selection and cursor being off after shifting selection right if (is_selection_active()) { - select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1); + select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset); } - cursor_set_column(cursor.column + 1, false); + cursor_set_column(cursor.column + selection_offset, false); end_complex_operation(); update(); } @@ -1724,6 +1737,15 @@ void TextEdit::indent_left() { int start_line; int end_line; + + // moving cursor and selection after unindenting can get tricky + // because changing content of line can move cursor and selection on it's own (if new line ends before previous position of either) + // therefore we just remember initial values + // and at the end of the operation offset them by number of removed characters + int removed_characters = 0; + int initial_selection_end_column = selection.to_column; + int initial_cursor_column = cursor.column; + begin_complex_operation(); if (is_selection_active()) { @@ -1746,21 +1768,43 @@ void TextEdit::indent_left() { if (line_text.begins_with("\t")) { line_text = line_text.substr(1, line_text.length()); set_line(i, line_text); - } else if (line_text.begins_with(space_indent)) { - line_text = line_text.substr(indent_size, line_text.length()); + removed_characters = 1; + } else if (line_text.begins_with(" ")) { + // when unindenting we aim to remove spaces before line that has selection no matter what is selected + // so we start of by finding first non whitespace character of line + int left = _find_first_non_whitespace_column_of_line(line_text); + + // here we remove only enough spaces to align text to nearest full multiple of indentation_size + // in case where selection begins at the start of indentation_size multiple we remove whole indentation level + int spaces_to_remove = _calculate_spaces_till_next_left_indent(left); + + line_text = line_text.substr(spaces_to_remove, line_text.length()); set_line(i, line_text); + removed_characters = spaces_to_remove; } } // fix selection and cursor being off by one on the last line if (is_selection_active() && last_line_text != get_line(end_line)) { - select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1); + select(selection.from_line, selection.from_column - removed_characters, + selection.to_line, initial_selection_end_column - removed_characters); } - cursor_set_column(cursor.column - 1, false); + cursor_set_column(initial_cursor_column - removed_characters, false); end_complex_operation(); update(); } +int TextEdit::_calculate_spaces_till_next_left_indent(int column) { + int spaces_till_indent = column % indent_size; + if (spaces_till_indent == 0) + spaces_till_indent = indent_size; + return spaces_till_indent; +} + +int TextEdit::_calculate_spaces_till_next_right_indent(int column) { + return indent_size - column % indent_size; +} + void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const { float rows = p_mouse.y; @@ -1812,6 +1856,9 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { + double prev_v_scroll = v_scroll->get_value(); + double prev_h_scroll = h_scroll->get_value(); + Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { @@ -2066,6 +2113,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _scroll_down(delta); } h_scroll->set_value(h_scroll->get_value() + pan_gesture->get_delta().x * 100); + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + return; } @@ -2109,6 +2159,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) + accept_event(); //accept event if scroll changed + Ref<InputEventKey> k = p_gui_input; if (k.is_valid()) { @@ -2517,15 +2570,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (k->get_shift()) { - //simple unindent + // simple unindent int cc = cursor.column; - - const int len = text[cursor.line].length(); const String &line = text[cursor.line]; - int left = 0; // number of whitespace chars at beginning of line - while (left < len && (line[left] == '\t' || line[left] == ' ')) - left++; + int left = _find_first_non_whitespace_column_of_line(line); cc = MIN(cc, left); while (cc < indent_size && cc < left && line[cc] == ' ') @@ -2533,24 +2582,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc > 0 && cc <= text[cursor.line].length()) { if (text[cursor.line][cc - 1] == '\t') { + // tabs unindentation _remove_text(cursor.line, cc - 1, cursor.line, cc); if (cursor.column >= left) cursor_set_column(MAX(0, cursor.column - 1)); update(); } else { - int n = 0; - - for (int i = 1; i <= MIN(cc, indent_size); i++) { - if (line[cc - i] != ' ') { - break; - } - n++; - } - - if (n > 0) { - _remove_text(cursor.line, cc - n, cursor.line, cc); - if (cursor.column > left - n) // inside text? - cursor_set_column(MAX(0, cursor.column - n)); + // spaces unindentation + int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); + if (spaces_to_remove > 0) { + _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc); + if (cursor.column > left - spaces_to_remove) // inside text? + cursor_set_column(MAX(0, cursor.column - spaces_to_remove)); update(); } } @@ -2559,9 +2602,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { update(); } } else { - //simple indent + // simple indent if (indent_using_spaces) { - _insert_text_at_cursor(space_indent); + // insert only as much spaces as needed till next indentation level + int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column); + String indent_to_insert = String(); + for (int i = 0; i < spaces_to_add; i++) + indent_to_insert = ' ' + indent_to_insert; + _insert_text_at_cursor(indent_to_insert); } else { _insert_text_at_cursor("\t"); } @@ -4121,7 +4169,7 @@ void TextEdit::_scroll_moved(double p_to_val) { int v_scroll_i = floor(get_v_scroll()); int sc = 0; int n_line; - for (n_line = 0; n_line < text.size(); n_line++) { + for (n_line = 0; n_line < text.size() - 1; n_line++) { if (!is_line_hidden(n_line)) { sc++; sc += times_line_wraps(n_line); @@ -6661,6 +6709,7 @@ TextEdit::TextEdit() { context_menu_enabled = true; menu = memnew(PopupMenu); add_child(menu); + readonly = true; // initialise to opposite first, so we get past the early-out in set_readonly set_readonly(false); menu->connect("id_pressed", this, "menu_option"); first_draw = true; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 64cbafc717..68e590f1e6 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -437,6 +437,9 @@ private: void _confirm_completion(); void _update_completion_candidates(); + int _calculate_spaces_till_next_left_indent(int column); + int _calculate_spaces_till_next_right_indent(int column); + protected: virtual String get_tooltip(const Point2 &p_pos) const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 049cae9dd9..e5313061da 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1970,6 +1970,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool item_h += child_h; } } + if (p_item == root && p_button == BUTTON_RIGHT) { + emit_signal("empty_rmb", get_local_mouse_position()); + } } return item_h; // nothing found @@ -3853,6 +3856,7 @@ void Tree::_bind_methods() { ADD_SIGNAL(MethodInfo("cell_selected")); ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::BOOL, "selected"))); ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::VECTOR2, "position"))); + ADD_SIGNAL(MethodInfo("empty_rmb", PropertyInfo(Variant::VECTOR2, "position"))); ADD_SIGNAL(MethodInfo("empty_tree_rmb_selected", PropertyInfo(Variant::VECTOR2, "position"))); ADD_SIGNAL(MethodInfo("item_edited")); ADD_SIGNAL(MethodInfo("item_rmb_edited")); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index e80de68e3b..2f23c11748 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -949,6 +949,7 @@ void Node::set_name(const String &p_name) { if (is_inside_tree()) { emit_signal("renamed"); + get_tree()->node_renamed(this); get_tree()->tree_changed(); } } @@ -2076,7 +2077,9 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const } } - node->set_name(get_name()); + if (get_name() != String()) { + node->set_name(get_name()); + } #ifdef TOOLS_ENABLED if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap) diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index b81364e2f0..65cda73a23 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -105,6 +105,11 @@ void SceneTree::node_removed(Node *p_node) { call_skip.insert(p_node); } +void SceneTree::node_renamed(Node *p_node) { + + emit_signal(node_renamed_name, p_node); +} + SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_node) { Map<StringName, Group>::Element *E = group_map.find(p_group); @@ -1895,6 +1900,7 @@ void SceneTree::_bind_methods() { ADD_SIGNAL(MethodInfo("tree_changed")); ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("screen_resized")); ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); @@ -1983,6 +1989,7 @@ SceneTree::SceneTree() { tree_changed_name = "tree_changed"; node_added_name = "node_added"; node_removed_name = "node_removed"; + node_renamed_name = "node_renamed"; ugc_locked = false; call_lock = 0; root_lock = 0; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index e098b3d53c..0bcb724929 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -126,6 +126,7 @@ private: StringName tree_changed_name; StringName node_added_name; StringName node_removed_name; + StringName node_renamed_name; bool use_font_oversampling; int64_t current_frame; @@ -201,6 +202,7 @@ private: void tree_changed(); void node_added(Node *p_node); void node_removed(Node *p_node); + void node_renamed(Node *p_node); Group *add_to_group(const StringName &p_group, Node *p_node); void remove_from_group(const StringName &p_group, Node *p_node); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index ae2c571201..b5e5022e63 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2765,6 +2765,19 @@ Rect2 Viewport::get_attach_to_screen_rect() const { return to_screen_rect; } +void Viewport::set_use_render_direct_to_screen(bool p_render_direct_to_screen) { + + if (p_render_direct_to_screen == render_direct_to_screen) + return; + + render_direct_to_screen = p_render_direct_to_screen; + VS::get_singleton()->viewport_set_render_direct_to_screen(viewport, p_render_direct_to_screen); +} + +bool Viewport::is_using_render_direct_to_screen() const { + return render_direct_to_screen; +} + void Viewport::set_physics_object_picking(bool p_enable) { physics_object_picking = p_enable; @@ -3030,6 +3043,8 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d); ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d); ClassDB::bind_method(D_METHOD("set_attach_to_screen_rect", "rect"), &Viewport::set_attach_to_screen_rect); + ClassDB::bind_method(D_METHOD("set_use_render_direct_to_screen", "enable"), &Viewport::set_use_render_direct_to_screen); + ClassDB::bind_method(D_METHOD("is_using_render_direct_to_screen"), &Viewport::is_using_render_direct_to_screen); ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position); ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse); @@ -3084,6 +3099,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear"); ADD_PROPERTY(PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_ENUM, "2D,2D No-Sampling,3D,3D No-Effects"), "set_usage", "get_usage"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_direct_to_screen"), "set_use_render_direct_to_screen", "is_using_render_direct_to_screen"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); ADD_GROUP("Render Target", "render_target_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_target_v_flip"), "set_vflip", "get_vflip"); @@ -3166,6 +3182,8 @@ Viewport::Viewport() { texture_rid = VisualServer::get_singleton()->viewport_get_texture(viewport); texture_flags = 0; + render_direct_to_screen = false; + default_texture.instance(); default_texture->vp = const_cast<Viewport *>(this); viewport_textures.insert(default_texture.ptr()); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index d67b4ac348..b7160d5139 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -182,6 +182,7 @@ private: Size2 size; Rect2 to_screen_rect; + bool render_direct_to_screen; RID contact_2d_debug; RID contact_3d_debug_multimesh; @@ -481,6 +482,9 @@ public: void set_attach_to_screen_rect(const Rect2 &p_rect); Rect2 get_attach_to_screen_rect() const; + void set_use_render_direct_to_screen(bool p_render_direct_to_screen); + bool is_using_render_direct_to_screen() const; + Vector2 get_mouse_position() const; void warp_mouse(const Vector2 &p_pos); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 9c79b2ba3b..ebfcd51247 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2559,17 +2559,6 @@ bool Animation::has_loop() const { return loop; } -void Animation::track_move_up(int p_track) { - - if (p_track >= 0 && p_track < (tracks.size() - 1)) { - - SWAP(tracks.write[p_track], tracks.write[p_track + 1]); - } - - emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); -} - void Animation::track_set_imported(int p_track, bool p_imported) { ERR_FAIL_INDEX(p_track, tracks.size()); @@ -2595,12 +2584,40 @@ bool Animation::track_is_enabled(int p_track) const { return tracks[p_track]->enabled; } +void Animation::track_move_up(int p_track) { + + if (p_track >= 0 && p_track < (tracks.size() - 1)) { + + SWAP(tracks.write[p_track], tracks.write[p_track + 1]); + } + + emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); +} + void Animation::track_move_down(int p_track) { if (p_track > 0 && p_track < tracks.size()) { SWAP(tracks.write[p_track], tracks.write[p_track - 1]); } + + emit_changed(); + emit_signal(SceneStringNames::get_singleton()->tracks_changed); +} + +void Animation::track_move_to(int p_track, int p_to_index) { + + ERR_FAIL_INDEX(p_track, tracks.size()); + ERR_FAIL_INDEX(p_to_index, tracks.size() + 1); + if (p_track == p_to_index || p_track == p_to_index - 1) + return; + + Track *track = tracks.get(p_track); + tracks.remove(p_track); + // Take into account that the position of the tracks that come after the one removed will change. + tracks.insert(p_to_index > p_track ? p_to_index - 1 : p_to_index, track); + emit_changed(); emit_signal(SceneStringNames::get_singleton()->tracks_changed); } @@ -2612,6 +2629,7 @@ void Animation::track_swap(int p_track, int p_with_track) { if (p_track == p_with_track) return; SWAP(tracks.write[p_track], tracks.write[p_with_track]); + emit_changed(); emit_signal(SceneStringNames::get_singleton()->tracks_changed); } @@ -2656,6 +2674,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_move_up", "idx"), &Animation::track_move_up); ClassDB::bind_method(D_METHOD("track_move_down", "idx"), &Animation::track_move_down); + ClassDB::bind_method(D_METHOD("track_move_to", "idx", "to_idx"), &Animation::track_move_to); ClassDB::bind_method(D_METHOD("track_swap", "idx", "with_idx"), &Animation::track_swap); ClassDB::bind_method(D_METHOD("track_set_imported", "idx", "imported"), &Animation::track_set_imported); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 3d38a8902f..36ebaa25d5 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -293,6 +293,7 @@ public: void track_move_up(int p_track); void track_move_down(int p_track); + void track_move_to(int p_track, int p_to_index); void track_swap(int p_track, int p_with_track); void track_set_imported(int p_track, bool p_imported); diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index ece8ad4bb0..950518aa6e 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -782,7 +782,8 @@ Vector2 Curve2D::interpolate_baked(float p_offset, bool p_cubic) const { if (idx >= bpc - 1) { return r[bpc - 1]; } else if (idx == bpc - 2) { - frac /= Math::fmod(baked_max_ofs, bake_interval); + if (frac > 0) + frac /= Math::fmod(baked_max_ofs, bake_interval); } else { frac /= bake_interval; } @@ -1352,7 +1353,8 @@ Vector3 Curve3D::interpolate_baked(float p_offset, bool p_cubic) const { if (idx >= bpc - 1) { return r[bpc - 1]; } else if (idx == bpc - 2) { - frac /= Math::fmod(baked_max_ofs, bake_interval); + if (frac > 0) + frac /= Math::fmod(baked_max_ofs, bake_interval); } else { frac /= bake_interval; } @@ -1396,7 +1398,8 @@ float Curve3D::interpolate_baked_tilt(float p_offset) const { if (idx >= bpc - 1) { return r[bpc - 1]; } else if (idx == bpc - 2) { - frac /= Math::fmod(baked_max_ofs, bake_interval); + if (frac > 0) + frac /= Math::fmod(baked_max_ofs, bake_interval); } else { frac /= bake_interval; } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 128db3f109..627397f0ab 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -530,7 +530,13 @@ Size2 Font::get_wordwrap_string_size(const String &p_string, float p_width) cons void BitmapFont::set_fallback(const Ref<BitmapFont> &p_fallback) { - ERR_FAIL_COND(p_fallback == this); + for (Ref<BitmapFont> fallback_child = p_fallback; fallback_child != NULL; fallback_child = fallback_child->get_fallback()) { + if (fallback_child == this) { + ERR_EXPLAIN("Can't set as fallback one of its parents to prevent crashes due to recursive loop."); + ERR_FAIL_COND(fallback_child == this); + } + } + fallback = p_fallback; } diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 766c7bbd9f..ada0ac07a3 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -38,7 +38,12 @@ void Material::set_next_pass(const Ref<Material> &p_pass) { - ERR_FAIL_COND(p_pass == this); + for (Ref<Material> pass_child = p_pass; pass_child != NULL; pass_child = pass_child->get_next_pass()) { + if (pass_child == this) { + ERR_EXPLAIN("Can't set as next_pass one of its parents to prevent crashes due to recursive loop."); + ERR_FAIL_COND(pass_child == this); + } + } if (next_pass == p_pass) return; @@ -468,6 +473,9 @@ void SpatialMaterial::_update_shader() { if (flags[FLAG_ENSURE_CORRECT_NORMALS]) { code += ",ensure_correct_normals"; } + if (flags[FLAG_USE_SHADOW_TO_OPACITY]) { + code += ",shadow_to_opacity"; + } code += ";\n"; code += "uniform vec4 albedo : hint_color;\n"; @@ -849,7 +857,7 @@ void SpatialMaterial::_update_shader() { code += "\tALBEDO *= 1.0 - ref_amount;\n"; code += "\tALPHA = 1.0;\n"; - } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { + } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { code += "\tALPHA = albedo.a * albedo_tex.a;\n"; } @@ -1349,7 +1357,7 @@ void SpatialMaterial::set_flag(Flags p_flag, bool p_enabled) { return; flags[p_flag] = p_enabled; - if (p_flag == FLAG_USE_ALPHA_SCISSOR || p_flag == FLAG_UNSHADED) { + if ((p_flag == FLAG_USE_ALPHA_SCISSOR) || (p_flag == FLAG_UNSHADED) || (p_flag == FLAG_USE_SHADOW_TO_OPACITY)) { _change_notify(); } _queue_shader_change(); @@ -2060,6 +2068,7 @@ void SpatialMaterial::_bind_methods() { ADD_GROUP("Flags", "flags_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_transparent"), "set_feature", "get_feature", FEATURE_TRANSPARENT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_use_shadow_to_opacity"), "set_flag", "get_flag", FLAG_USE_SHADOW_TO_OPACITY); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_unshaded"), "set_flag", "get_flag", FLAG_UNSHADED); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_vertex_lighting"), "set_flag", "get_flag", FLAG_USE_VERTEX_LIGHTING); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST); @@ -2266,6 +2275,7 @@ void SpatialMaterial::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_DONT_RECEIVE_SHADOWS); BIND_ENUM_CONSTANT(FLAG_DISABLE_AMBIENT_LIGHT); BIND_ENUM_CONSTANT(FLAG_ENSURE_CORRECT_NORMALS); + BIND_ENUM_CONSTANT(FLAG_USE_SHADOW_TO_OPACITY); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(DIFFUSE_BURLEY); diff --git a/scene/resources/material.h b/scene/resources/material.h index 1f7fc267af..29b45f769b 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -196,6 +196,7 @@ public: FLAG_DONT_RECEIVE_SHADOWS, FLAG_ENSURE_CORRECT_NORMALS, FLAG_DISABLE_AMBIENT_LIGHT, + FLAG_USE_SHADOW_TO_OPACITY, FLAG_MAX }; diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp index 48945d4e63..292fdcdbd2 100644 --- a/scene/resources/sky.cpp +++ b/scene/resources/sky.cpp @@ -62,7 +62,7 @@ void Sky::_bind_methods() { } Sky::Sky() { - radiance_size = RADIANCE_SIZE_512; + radiance_size = RADIANCE_SIZE_128; } ///////////////////////////////////////// diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 8c0497e91a..496b1b2bdc 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -769,6 +769,26 @@ void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) { material = p_existing->surface_get_material(p_surface); } +void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String p_blend_shape_name) { + clear(); + primitive = p_existing->surface_get_primitive_type(p_surface); + Array arr = p_existing->surface_get_blend_shape_arrays(p_surface); + Array blend_shape_names; + int32_t shape_idx = -1; + for (int32_t i = 0; i < p_existing->get_blend_shape_count(); i++) { + String name = p_existing->get_blend_shape_name(i); + if (name == p_blend_shape_name) { + shape_idx = i; + break; + } + } + ERR_FAIL_COND(shape_idx == -1); + ERR_FAIL_COND(shape_idx >= arr.size()); + Array mesh = arr[shape_idx]; + ERR_FAIL_COND(mesh.size() != VS::ARRAY_MAX); + _create_list_from_arrays(arr[shape_idx], &vertex_array, &index_array, format); +} + void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform) { if (vertex_array.size() == 0) { @@ -1071,8 +1091,10 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear); ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from); + ClassDB::bind_method(D_METHOD("create_from_blend_shape", "existing", "surface", "blend_shape"), &SurfaceTool::create_from_blend_shape); ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from); ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT)); + ClassDB::bind_method(D_METHOD("commit_to_arrays"), &SurfaceTool::commit_to_arrays); } SurfaceTool::SurfaceTool() { diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index c55cade813..c4c71dca13 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -136,6 +136,7 @@ public: static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays); Array commit_to_arrays(); void create_from(const Ref<Mesh> &p_existing, int p_surface); + void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String p_blend_shape_name); void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform); Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 29998e6ba3..9b2e410985 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "visual_shader.h" + #include "core/vmap.h" #include "servers/visual/shader_types.h" @@ -2202,8 +2203,10 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad static Vector<String> post_symbols; if (post_symbols.empty()) { + post_symbols.push_back("\0"); post_symbols.push_back("\t"); post_symbols.push_back("\n"); + post_symbols.push_back(";"); post_symbols.push_back("}"); post_symbols.push_back("]"); post_symbols.push_back(")"); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index ea39d118e4..838c2c618d 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -32,6 +32,7 @@ #define VISUAL_SHADER_H #include "core/string_builder.h" +#include "scene/gui/control.h" #include "scene/resources/shader.h" class VisualShaderNodeUniform; diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp index 05cba416be..8e15e9288f 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -170,7 +170,7 @@ Vector2 AudioEffectSpectrumAnalyzerInstance::get_magnitude_for_frequency_range(f for (int i = begin_pos; i <= end_pos; i++) { max.x = MAX(max.x, r[i].l); - max.y = MAX(max.x, r[i].r); + max.y = MAX(max.y, r[i].r); } return max; diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index 66d2dcd417..0043b948b0 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -240,12 +240,7 @@ bool SegmentShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 & real_t SegmentShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { - Vector2 s[2] = { a * p_scale, b * p_scale }; - - real_t l = s[1].distance_to(s[0]); - Vector2 ofs = (s[0] + s[1]) * 0.5; - - return p_mass * (l * l / 12.0 + ofs.length_squared()); + return p_mass * ((a * p_scale).distance_squared_to(b * p_scale)) / 12; } void SegmentShape2DSW::set_data(const Variant &p_data) { @@ -318,7 +313,9 @@ bool CircleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p real_t CircleShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { - return (radius * radius) * (p_scale.x * 0.5 + p_scale.y * 0.5); + real_t a = radius * p_scale.x; + real_t b = radius * p_scale.y; + return p_mass * (a * a + b * b) / 4; } void CircleShape2DSW::set_data(const Variant &p_data) { @@ -637,7 +634,7 @@ real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 aabb.expand_to(points[i].pos * p_scale); } - return p_mass * aabb.size.dot(aabb.size) / 12.0 + p_mass * (aabb.position + aabb.size * 0.5).length_squared(); + return p_mass * aabb.size.dot(aabb.size) / 12.0; } void ConvexPolygonShape2DSW::set_data(const Variant &p_data) { diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index a02f52f034..31888261ec 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -550,10 +550,12 @@ public: RENDER_TARGET_NO_SAMPLING, RENDER_TARGET_HDR, RENDER_TARGET_KEEP_3D_LINEAR, + RENDER_TARGET_DIRECT_TO_SCREEN, RENDER_TARGET_FLAG_MAX }; virtual RID render_target_create() = 0; + virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0; virtual RID render_target_get_texture(RID p_render_target) const = 0; virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index cb3a744730..6efd05593e 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2968,6 +2968,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons member_type = DataType(dt - 1); } else if (l == 2) { member_type = dt; + } else if (l == 3) { + member_type = DataType(dt + 1); + } else if (l == 4) { + member_type = DataType(dt + 2); } else { ok = false; break; @@ -3001,6 +3005,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons member_type = DataType(dt - 1); } else if (l == 3) { member_type = dt; + } else if (l == 4) { + member_type = DataType(dt + 1); } else { ok = false; break; diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 8fd5dfc738..bc6010117c 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -147,6 +147,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["light"].can_discard = true; @@ -187,6 +188,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].modes.push_back("shadows_disabled"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("ambient_light_disabled"); + shader_modes[VS::SHADER_SPATIAL].modes.push_back("shadow_to_opacity"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("vertex_lighting"); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index a9ca920178..310aa16130 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -201,8 +201,10 @@ VisualServerRaster::VisualServerRaster() { VSG::canvas_render = VSG::rasterizer->get_canvas(); VSG::scene_render = VSG::rasterizer->get_scene(); - for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { black_margin[i] = 0; + black_image[i] = RID(); + } } VisualServerRaster::~VisualServerRaster() { diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 3ec428d687..921d55556d 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -454,6 +454,7 @@ public: BIND2(viewport_set_clear_mode, RID, ViewportClearMode) BIND3(viewport_attach_to_screen, RID, const Rect2 &, int) + BIND2(viewport_set_render_direct_to_screen, RID, bool) BIND1(viewport_detach, RID) BIND2(viewport_set_update_mode, RID, ViewportUpdateMode) diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index e7f60c2c1f..b7c54caffd 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -343,7 +343,7 @@ void VisualServerViewport::draw_viewports() { vp->render_info[VS::VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_SURFACE_CHANGES_IN_FRAME); vp->render_info[VS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_DRAW_CALLS_IN_FRAME); - if (vp->viewport_to_screen_rect != Rect2()) { + if (vp->viewport_to_screen_rect != Rect2() && (!vp->viewport_render_direct_to_screen || !VSG::rasterizer->is_low_end())) { //copy to screen if set as such VSG::rasterizer->set_current_render_target(RID()); VSG::rasterizer->blit_render_target_to_screen(vp->render_target, vp->viewport_to_screen_rect, vp->viewport_to_screen); @@ -368,6 +368,7 @@ RID VisualServerViewport::viewport_create() { viewport->hide_canvas = false; viewport->render_target = VSG::storage->render_target_create(); viewport->shadow_atlas = VSG::scene_render->shadow_atlas_create(); + viewport->viewport_render_direct_to_screen = false; return rid; } @@ -424,14 +425,55 @@ void VisualServerViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); + // If using GLES2 we can optimize this operation by rendering directly to system_fbo + // instead of rendering to fbo and copying to system_fbo after + if (VSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { + + VSG::storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y); + VSG::storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y); + } + viewport->viewport_to_screen_rect = p_rect; viewport->viewport_to_screen = p_screen; } + +void VisualServerViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) { + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + if (p_enable == viewport->viewport_render_direct_to_screen) + return; + + // if disabled, reset render_target size and position + if (!p_enable) { + + VSG::storage->render_target_set_position(viewport->render_target, 0, 0); + VSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y); + } + + VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable); + viewport->viewport_render_direct_to_screen = p_enable; + + // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unneccesary buffer allocation + if (VSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) { + + VSG::storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y); + VSG::storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y); + } +} + void VisualServerViewport::viewport_detach(RID p_viewport) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); + // if render_direct_to_screen was used, reset size and position + if (VSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { + + VSG::storage->render_target_set_position(viewport->render_target, 0, 0); + VSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y); + } + viewport->viewport_to_screen_rect = Rect2(); viewport->viewport_to_screen = 0; } diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index 555b40a103..43bbcb66c3 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -58,6 +58,7 @@ public: int viewport_to_screen; Rect2 viewport_to_screen_rect; + bool viewport_render_direct_to_screen; bool hide_scenario; bool hide_canvas; @@ -158,6 +159,7 @@ public: void viewport_set_size(RID p_viewport, int p_width, int p_height); void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), int p_screen = 0); + void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable); void viewport_detach(RID p_viewport); void viewport_set_active(RID p_viewport, bool p_active); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index b2753369b8..cd24deb60c 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -381,6 +381,7 @@ public: FUNC2(viewport_set_clear_mode, RID, ViewportClearMode) FUNC3(viewport_attach_to_screen, RID, const Rect2 &, int) + FUNC2(viewport_set_render_direct_to_screen, RID, bool) FUNC1(viewport_detach, RID) FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index b39b400a53..0fe00ad61a 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1876,6 +1876,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_active", "viewport", "active"), &VisualServer::viewport_set_active); ClassDB::bind_method(D_METHOD("viewport_set_parent_viewport", "viewport", "parent_viewport"), &VisualServer::viewport_set_parent_viewport); ClassDB::bind_method(D_METHOD("viewport_attach_to_screen", "viewport", "rect", "screen"), &VisualServer::viewport_attach_to_screen, DEFVAL(Rect2()), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("viewport_set_render_direct_to_screen", "viewport", "enabled"), &VisualServer::viewport_set_render_direct_to_screen); ClassDB::bind_method(D_METHOD("viewport_detach", "viewport"), &VisualServer::viewport_detach); ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &VisualServer::viewport_set_update_mode); ClassDB::bind_method(D_METHOD("viewport_set_vflip", "viewport", "enabled"), &VisualServer::viewport_set_vflip); diff --git a/servers/visual_server.h b/servers/visual_server.h index 5146ca47f1..01be996bfc 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -610,6 +610,7 @@ public: virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0; virtual void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), int p_screen = 0) = 0; + virtual void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) = 0; virtual void viewport_detach(RID p_viewport) = 0; enum ViewportUpdateMode { diff --git a/thirdparty/README.md b/thirdparty/README.md index bc820634bb..732c08fdea 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -346,7 +346,7 @@ Collection of single-file libraries used in Godot components. * License: Public Domain - `clipper.{cpp,hpp}` * Upstream: https://sourceforge.net/projects/polyclipping - * Version: 6.4.2 + * Version: 6.4.2 + Godot changes (added optional exceptions handling) * License: BSL-1.0 - `fastlz.{c,h}` * Upstream: https://github.com/ariya/FastLZ diff --git a/thirdparty/assimp/code/res/resource.h b/thirdparty/assimp/code/res/resource.h deleted file mode 100644 index 37d39284fe..0000000000 --- a/thirdparty/assimp/code/res/resource.h +++ /dev/null @@ -1,14 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by assimp.rc - -// Nächste Standardwerte für neue Objekte -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/thirdparty/cvtt/LICENSE.txt b/thirdparty/cvtt/LICENSE.txt index 6964f6e43f..d79aec44e3 100644 --- a/thirdparty/cvtt/LICENSE.txt +++ b/thirdparty/cvtt/LICENSE.txt @@ -1,45 +1,45 @@ -Convection Texture Tools Stand-Alone Kernels
-
-Copyright (c) 2018 Eric Lasota
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject
-to the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-**************************************************************************
-
-Based on DirectX Texture Library
-
-Copyright (c) 2018 Microsoft Corp
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this
-software and associated documentation files (the "Software"), to deal in the Software
-without restriction, including without limitation the rights to use, copy, modify,
-merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be included in all copies
-or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
-CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+Convection Texture Tools Stand-Alone Kernels + +Copyright (c) 2018 Eric Lasota + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject +to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +************************************************************************** + +Based on DirectX Texture Library + +Copyright (c) 2018 Microsoft Corp + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/thirdparty/misc/clipper-exceptions.patch b/thirdparty/misc/clipper-exceptions.patch new file mode 100644 index 0000000000..537afd59b3 --- /dev/null +++ b/thirdparty/misc/clipper-exceptions.patch @@ -0,0 +1,154 @@ +diff --git a/thirdparty/misc/clipper.cpp b/thirdparty/misc/clipper.cpp +index 8c3a59c4ca..c67045d113 100644 +--- a/thirdparty/misc/clipper.cpp ++++ b/thirdparty/misc/clipper.cpp +@@ -48,6 +48,38 @@ + #include <ostream> + #include <functional> + ++//Explicitly disables exceptions handling for target platform ++//#define CLIPPER_NOEXCEPTION ++ ++#define CLIPPER_THROW(exception) std::abort() ++#define CLIPPER_TRY if(true) ++#define CLIPPER_CATCH(exception) if(false) ++ ++#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) ++ #ifndef CLIPPER_NOEXCEPTION ++ #undef CLIPPER_THROW ++ #define CLIPPER_THROW(exception) throw exception ++ #undef CLIPPER_TRY ++ #define CLIPPER_TRY try ++ #undef CLIPPER_CATCH ++ #define CLIPPER_CATCH(exception) catch(exception) ++ #endif ++#endif ++ ++//Optionally allows to override exception macros ++#if defined(CLIPPER_THROW_USER) ++ #undef CLIPPER_THROW ++ #define CLIPPER_THROW CLIPPER_THROW_USER ++#endif ++#if defined(CLIPPER_TRY_USER) ++ #undef CLIPPER_TRY ++ #define CLIPPER_TRY CLIPPER_TRY_USER ++#endif ++#if defined(CLIPPER_CATCH_USER) ++ #undef CLIPPER_CATCH ++ #define CLIPPER_CATCH CLIPPER_CATCH_USER ++#endif ++ + namespace ClipperLib { + + static double const pi = 3.141592653589793238; +@@ -898,7 +930,7 @@ void RangeTest(const IntPoint& Pt, bool& useFullRange) + if (useFullRange) + { + if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) +- throw clipperException("Coordinate outside allowed range"); ++ CLIPPER_THROW(clipperException("Coordinate outside allowed range")); + } + else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) + { +@@ -1046,10 +1078,10 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) + { + #ifdef use_lines + if (!Closed && PolyTyp == ptClip) +- throw clipperException("AddPath: Open paths must be subject."); ++ CLIPPER_THROW(clipperException("AddPath: Open paths must be subject.")); + #else + if (!Closed) +- throw clipperException("AddPath: Open paths have been disabled."); ++ CLIPPER_THROW(clipperException("AddPath: Open paths have been disabled.")); + #endif + + int highI = (int)pg.size() -1; +@@ -1062,7 +1094,7 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) + + bool IsFlat = true; + //1. Basic (first) edge initialization ... +- try ++ CLIPPER_TRY + { + edges[1].Curr = pg[1]; + RangeTest(pg[0], m_UseFullRange); +@@ -1075,10 +1107,10 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) + InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]); + } + } +- catch(...) ++ CLIPPER_CATCH(...) + { + delete [] edges; +- throw; //range test fails ++ CLIPPER_THROW(); //range test fails + } + TEdge *eStart = &edges[0]; + +@@ -1442,7 +1474,7 @@ void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) + void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e) + { + if (!e->NextInLML) +- throw clipperException("UpdateEdgeIntoAEL: invalid call"); ++ CLIPPER_THROW(clipperException("UpdateEdgeIntoAEL: invalid call")); + + e->NextInLML->OutIdx = e->OutIdx; + TEdge* AelPrev = e->PrevInAEL; +@@ -1510,7 +1542,7 @@ bool Clipper::Execute(ClipType clipType, Paths &solution, + { + if( m_ExecuteLocked ) return false; + if (m_HasOpenPaths) +- throw clipperException("Error: PolyTree struct is needed for open path clipping."); ++ CLIPPER_THROW(clipperException("Error: PolyTree struct is needed for open path clipping.")); + m_ExecuteLocked = true; + solution.resize(0); + m_SubjFillType = subjFillType; +@@ -1560,7 +1592,7 @@ void Clipper::FixHoleLinkage(OutRec &outrec) + bool Clipper::ExecuteInternal() + { + bool succeeded = true; +- try { ++ CLIPPER_TRY { + Reset(); + m_Maxima = MaximaList(); + m_SortedEdges = 0; +@@ -1583,7 +1615,7 @@ bool Clipper::ExecuteInternal() + InsertLocalMinimaIntoAEL(botY); + } + } +- catch(...) ++ CLIPPER_CATCH(...) + { + succeeded = false; + } +@@ -2827,18 +2859,18 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge) + bool Clipper::ProcessIntersections(const cInt topY) + { + if( !m_ActiveEdges ) return true; +- try { ++ CLIPPER_TRY { + BuildIntersectList(topY); + size_t IlSize = m_IntersectList.size(); + if (IlSize == 0) return true; + if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList(); + else return false; + } +- catch(...) ++ CLIPPER_CATCH(...) + { + m_SortedEdges = 0; + DisposeIntersectNodes(); +- throw clipperException("ProcessIntersections error"); ++ CLIPPER_THROW(clipperException("ProcessIntersections error")); + } + m_SortedEdges = 0; + return true; +@@ -3002,7 +3034,7 @@ void Clipper::DoMaxima(TEdge *e) + DeleteFromAEL(eMaxPair); + } + #endif +- else throw clipperException("DoMaxima error"); ++ else CLIPPER_THROW(clipperException("DoMaxima error")); + } + //------------------------------------------------------------------------------ + diff --git a/thirdparty/misc/clipper.cpp b/thirdparty/misc/clipper.cpp index d3143fe5ab..c67045d113 100644 --- a/thirdparty/misc/clipper.cpp +++ b/thirdparty/misc/clipper.cpp @@ -48,6 +48,38 @@ #include <ostream> #include <functional> +//Explicitly disables exceptions handling for target platform +//#define CLIPPER_NOEXCEPTION + +#define CLIPPER_THROW(exception) std::abort() +#define CLIPPER_TRY if(true) +#define CLIPPER_CATCH(exception) if(false) + +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) + #ifndef CLIPPER_NOEXCEPTION + #undef CLIPPER_THROW + #define CLIPPER_THROW(exception) throw exception + #undef CLIPPER_TRY + #define CLIPPER_TRY try + #undef CLIPPER_CATCH + #define CLIPPER_CATCH(exception) catch(exception) + #endif +#endif + +//Optionally allows to override exception macros +#if defined(CLIPPER_THROW_USER) + #undef CLIPPER_THROW + #define CLIPPER_THROW CLIPPER_THROW_USER +#endif +#if defined(CLIPPER_TRY_USER) + #undef CLIPPER_TRY + #define CLIPPER_TRY CLIPPER_TRY_USER +#endif +#if defined(CLIPPER_CATCH_USER) + #undef CLIPPER_CATCH + #define CLIPPER_CATCH CLIPPER_CATCH_USER +#endif + namespace ClipperLib { static double const pi = 3.141592653589793238; @@ -898,7 +930,7 @@ void RangeTest(const IntPoint& Pt, bool& useFullRange) if (useFullRange) { if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) - throw clipperException("Coordinate outside allowed range"); + CLIPPER_THROW(clipperException("Coordinate outside allowed range")); } else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) { @@ -1046,10 +1078,10 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) { #ifdef use_lines if (!Closed && PolyTyp == ptClip) - throw clipperException("AddPath: Open paths must be subject."); + CLIPPER_THROW(clipperException("AddPath: Open paths must be subject.")); #else if (!Closed) - throw clipperException("AddPath: Open paths have been disabled."); + CLIPPER_THROW(clipperException("AddPath: Open paths have been disabled.")); #endif int highI = (int)pg.size() -1; @@ -1062,7 +1094,7 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) bool IsFlat = true; //1. Basic (first) edge initialization ... - try + CLIPPER_TRY { edges[1].Curr = pg[1]; RangeTest(pg[0], m_UseFullRange); @@ -1075,10 +1107,10 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]); } } - catch(...) + CLIPPER_CATCH(...) { delete [] edges; - throw; //range test fails + CLIPPER_THROW(); //range test fails } TEdge *eStart = &edges[0]; @@ -1442,7 +1474,7 @@ void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e) { if (!e->NextInLML) - throw clipperException("UpdateEdgeIntoAEL: invalid call"); + CLIPPER_THROW(clipperException("UpdateEdgeIntoAEL: invalid call")); e->NextInLML->OutIdx = e->OutIdx; TEdge* AelPrev = e->PrevInAEL; @@ -1510,7 +1542,7 @@ bool Clipper::Execute(ClipType clipType, Paths &solution, { if( m_ExecuteLocked ) return false; if (m_HasOpenPaths) - throw clipperException("Error: PolyTree struct is needed for open path clipping."); + CLIPPER_THROW(clipperException("Error: PolyTree struct is needed for open path clipping.")); m_ExecuteLocked = true; solution.resize(0); m_SubjFillType = subjFillType; @@ -1560,7 +1592,7 @@ void Clipper::FixHoleLinkage(OutRec &outrec) bool Clipper::ExecuteInternal() { bool succeeded = true; - try { + CLIPPER_TRY { Reset(); m_Maxima = MaximaList(); m_SortedEdges = 0; @@ -1583,7 +1615,7 @@ bool Clipper::ExecuteInternal() InsertLocalMinimaIntoAEL(botY); } } - catch(...) + CLIPPER_CATCH(...) { succeeded = false; } @@ -2827,18 +2859,18 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge) bool Clipper::ProcessIntersections(const cInt topY) { if( !m_ActiveEdges ) return true; - try { + CLIPPER_TRY { BuildIntersectList(topY); size_t IlSize = m_IntersectList.size(); if (IlSize == 0) return true; if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList(); else return false; } - catch(...) + CLIPPER_CATCH(...) { m_SortedEdges = 0; DisposeIntersectNodes(); - throw clipperException("ProcessIntersections error"); + CLIPPER_THROW(clipperException("ProcessIntersections error")); } m_SortedEdges = 0; return true; @@ -3002,7 +3034,7 @@ void Clipper::DoMaxima(TEdge *e) DeleteFromAEL(eMaxPair); } #endif - else throw clipperException("DoMaxima error"); + else CLIPPER_THROW(clipperException("DoMaxima error")); } //------------------------------------------------------------------------------ @@ -4329,10 +4361,10 @@ double DistanceFromLineSqrd( const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2) { //The equation of a line in general form (Ax + By + C = 0) - //given 2 points (x¹,y¹) & (x²,y²) is ... - //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0 - //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹ - //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) + //given 2 points (x¹,y¹) & (x²,y²) is ... + //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0 + //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹ + //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) //see http://en.wikipedia.org/wiki/Perpendicular_distance double A = double(ln1.Y - ln2.Y); double B = double(ln2.X - ln1.X); diff --git a/thirdparty/xatlas/xatlas.cpp b/thirdparty/xatlas/xatlas.cpp index eb0824a517..2cc2905eee 100644 --- a/thirdparty/xatlas/xatlas.cpp +++ b/thirdparty/xatlas/xatlas.cpp @@ -4388,7 +4388,7 @@ private: class Solver { public: - // Solve the symmetric system: At·A·x = At·b + // Solve the symmetric system: At·A·x = At·b static bool LeastSquaresSolver(const sparse::Matrix &A, const FullVector &b, FullVector &x, float epsilon = 1e-5f) { xaDebugAssert(A.width() == x.dimension()); @@ -4477,22 +4477,22 @@ private: * Gradient method. * * Solving sparse linear systems: - * (1) A·x = b + * (1) A·x = b * * The conjugate gradient algorithm solves (1) only in the case that A is * symmetric and positive definite. It is based on the idea of minimizing the * function * - * (2) f(x) = 1/2·x·A·x - b·x + * (2) f(x) = 1/2·x·A·x - b·x * * This function is minimized when its gradient * - * (3) df = A·x - b + * (3) df = A·x - b * * is zero, which is equivalent to (1). The minimization is carried out by * generating a succession of search directions p.k and improved minimizers x.k. - * At each stage a quantity alfa.k is found that minimizes f(x.k + alfa.k·p.k), - * and x.k+1 is set equal to the new point x.k + alfa.k·p.k. The p.k and x.k are + * At each stage a quantity alfa.k is found that minimizes f(x.k + alfa.k·p.k), + * and x.k+1 is set equal to the new point x.k + alfa.k·p.k. The p.k and x.k are * built up in such a way that x.k+1 is also the minimizer of f over the whole * vector space of directions already taken, {p.1, p.2, . . . , p.k}. After N * iterations you arrive at the minimizer over the entire vector space, i.e., the @@ -4520,7 +4520,7 @@ private: float delta_new; float alpha; float beta; - // r = b - A·x; + // r = b - A·x; sparse::copy(b, r); sparse::sgemv(-1, A, x, 1, r); // p = r; @@ -4529,24 +4529,24 @@ private: delta_0 = delta_new; while (i < i_max && delta_new > epsilon * epsilon * delta_0) { i++; - // q = A·p + // q = A·p mult(A, p, q); - // alpha = delta_new / p·q + // alpha = delta_new / p·q alpha = delta_new / sparse::dot( p, q ); - // x = alfa·p + x + // x = alfa·p + x sparse::saxpy(alpha, p, x); if ((i & 31) == 0) { // recompute r after 32 steps - // r = b - A·x + // r = b - A·x sparse::copy(b, r); sparse::sgemv(-1, A, x, 1, r); } else { - // r = r - alpha·q + // r = r - alpha·q sparse::saxpy(-alpha, q, r); } delta_old = delta_new; delta_new = sparse::dot( r, r ); beta = delta_new / delta_old; - // p = beta·p + r + // p = beta·p + r sparse::scal(beta, p); sparse::saxpy(1, r, p); } @@ -4572,35 +4572,35 @@ private: float delta_new; float alpha; float beta; - // r = b - A·x + // r = b - A·x sparse::copy(b, r); sparse::sgemv(-1, A, x, 1, r); - // p = M^-1 · r + // p = M^-1 · r preconditioner.apply(r, p); delta_new = sparse::dot(r, p); delta_0 = delta_new; while (i < i_max && delta_new > epsilon * epsilon * delta_0) { i++; - // q = A·p + // q = A·p mult(A, p, q); - // alpha = delta_new / p·q + // alpha = delta_new / p·q alpha = delta_new / sparse::dot(p, q); - // x = alfa·p + x + // x = alfa·p + x sparse::saxpy(alpha, p, x); if ((i & 31) == 0) { // recompute r after 32 steps - // r = b - A·x + // r = b - A·x sparse::copy(b, r); sparse::sgemv(-1, A, x, 1, r); } else { - // r = r - alfa·q + // r = r - alfa·q sparse::saxpy(-alpha, q, r); } - // s = M^-1 · r + // s = M^-1 · r preconditioner.apply(r, s); delta_old = delta_new; delta_new = sparse::dot( r, s ); beta = delta_new / delta_old; - // p = s + beta·p + // p = s + beta·p sparse::scal(beta, p); sparse::saxpy(1, s, p); } diff --git a/version.py b/version.py index 3d7def727d..09219f60ad 100644 --- a/version.py +++ b/version.py @@ -5,3 +5,4 @@ minor = 2 status = "dev" module_config = "" year = 2019 +website = "https://godotengine.org" |