diff options
185 files changed, 3817 insertions, 2354 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 626d41dca0..26ba28370f 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -658,7 +658,7 @@ Dictionary _OS::get_time(bool utc) const { * * @return epoch calculated */ -uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { +int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { // Bunch of conversion constants static const unsigned int SECONDS_PER_MINUTE = 60; @@ -703,13 +703,18 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { // Calculate all the seconds from months past in this year uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY; - uint64_t SECONDS_FROM_YEARS_PAST = 0; - for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { - - SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY; + int64_t SECONDS_FROM_YEARS_PAST = 0; + if (year >= EPOCH_YR) { + for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { + SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY; + } + } else { + for (unsigned int iyear = EPOCH_YR - 1; iyear >= year; iyear--) { + SECONDS_FROM_YEARS_PAST -= YEARSIZE(iyear) * SECONDS_PER_DAY; + } } - uint64_t epoch = + int64_t epoch = second + minute * SECONDS_PER_MINUTE + hour * SECONDS_PER_HOUR + @@ -732,34 +737,36 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { * * @return dictionary of date and time values */ -Dictionary _OS::get_datetime_from_unix_time(uint64_t unix_time_val) const { - - // Just fail if unix time is negative (when interpreted as an int). - // This means the user passed in a negative value by accident - ERR_EXPLAIN("unix_time_val was really huge!" + itos(unix_time_val) + " You probably passed in a negative value!"); - ERR_FAIL_COND_V((int64_t)unix_time_val < 0, Dictionary()); +Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const { OS::Date date; OS::Time time; - unsigned long dayclock, dayno; + long dayclock, dayno; int year = EPOCH_YR; - dayclock = (unsigned long)unix_time_val % SECS_DAY; - dayno = (unsigned long)unix_time_val / SECS_DAY; + if (unix_time_val >= 0) { + dayno = unix_time_val / SECS_DAY; + dayclock = unix_time_val % SECS_DAY; + /* day 0 was a thursday */ + date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7); + while (dayno >= YEARSIZE(year)) { + dayno -= YEARSIZE(year); + year++; + } + } else { + dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY; + dayclock = unix_time_val - dayno * SECS_DAY; + date.weekday = static_cast<OS::Weekday>((dayno - 3) % 7 + 7); + do { + year--; + dayno += YEARSIZE(year); + } while (dayno < 0); + } time.sec = dayclock % 60; time.min = (dayclock % 3600) / 60; time.hour = dayclock / 3600; - - /* day 0 was a thursday */ - date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7); - - while (dayno >= YEARSIZE(year)) { - dayno -= YEARSIZE(year); - year++; - } - date.year = year; size_t imonth = 0; diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 311372aeca..b587b9257f 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -270,8 +270,8 @@ public: Dictionary get_date(bool utc) const; Dictionary get_time(bool utc) const; Dictionary get_datetime(bool utc) const; - Dictionary get_datetime_from_unix_time(uint64_t unix_time_val) const; - uint64_t get_unix_time_from_datetime(Dictionary datetime) const; + Dictionary get_datetime_from_unix_time(int64_t unix_time_val) const; + int64_t get_unix_time_from_datetime(Dictionary datetime) const; Dictionary get_time_zone_info() const; uint64_t get_unix_time() const; uint64_t get_system_time_secs() const; diff --git a/core/dictionary.cpp b/core/dictionary.cpp index 42d9eab310..9cc913fa0d 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -135,12 +135,7 @@ bool Dictionary::has_all(const Array &p_keys) const { return true; } -void Dictionary::erase(const Variant &p_key) { - - _p->variant_map.erase(p_key); -} - -bool Dictionary::erase_checked(const Variant &p_key) { +bool Dictionary::erase(const Variant &p_key) { return _p->variant_map.erase(p_key); } diff --git a/core/dictionary.h b/core/dictionary.h index 00ec67fb99..dbf2233819 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -65,8 +65,7 @@ public: bool has(const Variant &p_key) const; bool has_all(const Array &p_keys) const; - void erase(const Variant &p_key); - bool erase_checked(const Variant &p_key); + bool erase(const Variant &p_key); bool operator==(const Dictionary &p_dictionary) const; diff --git a/core/image.cpp b/core/image.cpp index 65905c83e8..c94f2c3534 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -36,8 +36,8 @@ #include "math_funcs.h" #include "print_string.h" +#include "io/resource_loader.h" #include "thirdparty/misc/hq2x.h" - #include <stdio.h> const char *Image::format_names[Image::FORMAT_MAX] = { @@ -1582,7 +1582,11 @@ Image::AlphaMode Image::detect_alpha() const { } Error Image::load(const String &p_path) { - +#ifdef DEBUG_ENABLED + if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) { + WARN_PRINTS("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource."); + } +#endif return ImageLoader::load_image(p_path, this); } diff --git a/core/image.h b/core/image.h index c8dd647c31..c450e88290 100644 --- a/core/image.h +++ b/core/image.h @@ -33,7 +33,7 @@ #include "color.h" #include "dvector.h" -#include "math_2d.h" +#include "rect2.h" #include "resource.h" /** diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 226b4d572b..a689c7238a 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -31,7 +31,7 @@ #ifndef CAMERA_MATRIX_H #define CAMERA_MATRIX_H -#include "math_2d.h" +#include "rect2.h" #include "transform.h" /** @author Juan Linietsky <reduzio@gmail.com> diff --git a/core/math/delaunay.h b/core/math/delaunay.h index 13fbc0c6ae..46535d5ce9 100644 --- a/core/math/delaunay.h +++ b/core/math/delaunay.h @@ -1,7 +1,7 @@ #ifndef DELAUNAY_H #define DELAUNAY_H -#include "math_2d.h" +#include "rect2.h" class Delaunay2D { public: diff --git a/core/math/geometry.h b/core/math/geometry.h index 186a05fb37..83b9467a30 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -33,9 +33,9 @@ #include "dvector.h" #include "face3.h" -#include "math_2d.h" #include "object.h" #include "print_string.h" +#include "rect2.h" #include "triangulate.h" #include "vector.h" #include "vector3.h" diff --git a/core/math/math_2d.h b/core/math/math_2d.h deleted file mode 100644 index 25c39e5d7a..0000000000 --- a/core/math/math_2d.h +++ /dev/null @@ -1,1002 +0,0 @@ -/*************************************************************************/ -/* math_2d.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "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. */ -/*************************************************************************/ - -#ifndef MATH_2D_H -#define MATH_2D_H - -#include "math_funcs.h" -#include "ustring.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ -enum Margin { - - MARGIN_LEFT, - MARGIN_TOP, - MARGIN_RIGHT, - MARGIN_BOTTOM -}; - -enum Corner { - - CORNER_TOP_LEFT, - CORNER_TOP_RIGHT, - CORNER_BOTTOM_RIGHT, - CORNER_BOTTOM_LEFT -}; - -enum Orientation { - - HORIZONTAL, - VERTICAL -}; - -enum HAlign { - - HALIGN_LEFT, - HALIGN_CENTER, - HALIGN_RIGHT -}; - -enum VAlign { - - VALIGN_TOP, - VALIGN_CENTER, - VALIGN_BOTTOM -}; - -struct Vector2 { - - union { - real_t x; - real_t width; - }; - union { - real_t y; - real_t height; - }; - - _FORCE_INLINE_ real_t &operator[](int p_idx) { - return p_idx ? y : x; - } - _FORCE_INLINE_ const real_t &operator[](int p_idx) const { - return p_idx ? y : x; - } - - void normalize(); - Vector2 normalized() const; - bool is_normalized() const; - - real_t length() const; - real_t length_squared() const; - - real_t distance_to(const Vector2 &p_vector2) const; - real_t distance_squared_to(const Vector2 &p_vector2) const; - real_t angle_to(const Vector2 &p_vector2) const; - real_t angle_to_point(const Vector2 &p_vector2) const; - - real_t dot(const Vector2 &p_other) const; - real_t cross(const Vector2 &p_other) const; - Vector2 project(const Vector2 &p_vec) const; - - Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; - - Vector2 clamped(real_t p_len) const; - - _FORCE_INLINE_ static Vector2 linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t); - _FORCE_INLINE_ Vector2 linear_interpolate(const Vector2 &p_b, real_t p_t) const; - _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_b, real_t p_t) const; - Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const; - - Vector2 slide(const Vector2 &p_normal) const; - Vector2 bounce(const Vector2 &p_normal) const; - Vector2 reflect(const Vector2 &p_normal) const; - - Vector2 operator+(const Vector2 &p_v) const; - void operator+=(const Vector2 &p_v); - Vector2 operator-(const Vector2 &p_v) const; - void operator-=(const Vector2 &p_v); - Vector2 operator*(const Vector2 &p_v1) const; - - Vector2 operator*(const real_t &rvalue) const; - void operator*=(const real_t &rvalue); - void operator*=(const Vector2 &rvalue) { *this = *this * rvalue; } - - Vector2 operator/(const Vector2 &p_v1) const; - - Vector2 operator/(const real_t &rvalue) const; - - void operator/=(const real_t &rvalue); - - Vector2 operator-() const; - - bool operator==(const Vector2 &p_vec2) const; - bool operator!=(const Vector2 &p_vec2) const; - - bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); } - - real_t angle() const; - - void set_rotation(real_t p_radians) { - - x = Math::cos(p_radians); - y = Math::sin(p_radians); - } - - _FORCE_INLINE_ Vector2 abs() const { - - return Vector2(Math::abs(x), Math::abs(y)); - } - - Vector2 rotated(real_t p_by) const; - Vector2 tangent() const { - - return Vector2(y, -x); - } - - Vector2 floor() const; - Vector2 ceil() const; - Vector2 round() const; - Vector2 snapped(const Vector2 &p_by) const; - real_t aspect() const { return width / height; } - - operator String() const { return String::num(x) + ", " + String::num(y); } - - _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { - x = p_x; - y = p_y; - } - _FORCE_INLINE_ Vector2() { - x = 0; - y = 0; - } -}; - -_FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const { - - return p_vec - *this * (dot(p_vec) - p_d); -} - -_FORCE_INLINE_ Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) { - - return p_vec * p_scalar; -} - -_FORCE_INLINE_ Vector2 Vector2::operator+(const Vector2 &p_v) const { - - return Vector2(x + p_v.x, y + p_v.y); -} -_FORCE_INLINE_ void Vector2::operator+=(const Vector2 &p_v) { - - x += p_v.x; - y += p_v.y; -} -_FORCE_INLINE_ Vector2 Vector2::operator-(const Vector2 &p_v) const { - - return Vector2(x - p_v.x, y - p_v.y); -} -_FORCE_INLINE_ void Vector2::operator-=(const Vector2 &p_v) { - - x -= p_v.x; - y -= p_v.y; -} - -_FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const { - - return Vector2(x * p_v1.x, y * p_v1.y); -}; - -_FORCE_INLINE_ Vector2 Vector2::operator*(const real_t &rvalue) const { - - return Vector2(x * rvalue, y * rvalue); -}; -_FORCE_INLINE_ void Vector2::operator*=(const real_t &rvalue) { - - x *= rvalue; - y *= rvalue; -}; - -_FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const { - - return Vector2(x / p_v1.x, y / p_v1.y); -}; - -_FORCE_INLINE_ Vector2 Vector2::operator/(const real_t &rvalue) const { - - return Vector2(x / rvalue, y / rvalue); -}; - -_FORCE_INLINE_ void Vector2::operator/=(const real_t &rvalue) { - - x /= rvalue; - y /= rvalue; -}; - -_FORCE_INLINE_ Vector2 Vector2::operator-() const { - - return Vector2(-x, -y); -} - -_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const { - - return x == p_vec2.x && y == p_vec2.y; -} -_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { - - return x != p_vec2.x || y != p_vec2.y; -} - -Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const { - - Vector2 res = *this; - - res.x += (p_t * (p_b.x - x)); - res.y += (p_t * (p_b.y - y)); - - return res; -} - -Vector2 Vector2::slerp(const Vector2 &p_b, real_t p_t) const { -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Vector2()); -#endif - real_t theta = angle_to(p_b); - return rotated(theta * p_t); -} - -Vector2 Vector2::linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t) { - - Vector2 res = p_a; - - res.x += (p_t * (p_b.x - p_a.x)); - res.y += (p_t * (p_b.y - p_a.y)); - - return res; -} - -typedef Vector2 Size2; -typedef Vector2 Point2; - -struct Transform2D; - -struct Rect2 { - - Point2 position; - Size2 size; - - const Vector2 &get_position() const { return position; } - void set_position(const Vector2 &p_pos) { position = p_pos; } - const Vector2 &get_size() const { return size; } - void set_size(const Vector2 &p_size) { size = p_size; } - - real_t get_area() const { return size.width * size.height; } - - inline bool intersects(const Rect2 &p_rect) const { - if (position.x >= (p_rect.position.x + p_rect.size.width)) - return false; - if ((position.x + size.width) <= p_rect.position.x) - return false; - if (position.y >= (p_rect.position.y + p_rect.size.height)) - return false; - if ((position.y + size.height) <= p_rect.position.y) - return false; - - return true; - } - - inline real_t distance_to(const Vector2 &p_point) const { - - real_t dist = 0.0; - bool inside = true; - - if (p_point.x < position.x) { - real_t d = position.x - p_point.x; - dist = inside ? d : MIN(dist, d); - inside = false; - } - if (p_point.y < position.y) { - real_t d = position.y - p_point.y; - dist = inside ? d : MIN(dist, d); - inside = false; - } - if (p_point.x >= (position.x + size.x)) { - real_t d = p_point.x - (position.x + size.x); - dist = inside ? d : MIN(dist, d); - inside = false; - } - if (p_point.y >= (position.y + size.y)) { - real_t d = p_point.y - (position.y + size.y); - dist = inside ? d : MIN(dist, d); - inside = false; - } - - if (inside) - return 0; - else - return dist; - } - - _FORCE_INLINE_ bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const; - - bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = NULL, Point2 *r_normal = NULL) const; - - inline bool encloses(const Rect2 &p_rect) const { - - return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && - ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) && - ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); - } - - inline bool has_no_area() const { - - return (size.x <= 0 || size.y <= 0); - } - inline Rect2 clip(const Rect2 &p_rect) const { /// return a clipped rect - - Rect2 new_rect = p_rect; - - if (!intersects(new_rect)) - return Rect2(); - - new_rect.position.x = MAX(p_rect.position.x, position.x); - new_rect.position.y = MAX(p_rect.position.y, position.y); - - Point2 p_rect_end = p_rect.position + p_rect.size; - Point2 end = position + size; - - new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; - new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; - - return new_rect; - } - - inline Rect2 merge(const Rect2 &p_rect) const { ///< return a merged rect - - Rect2 new_rect; - - new_rect.position.x = MIN(p_rect.position.x, position.x); - new_rect.position.y = MIN(p_rect.position.y, position.y); - - new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); - new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); - - new_rect.size = new_rect.size - new_rect.position; //make relative again - - return new_rect; - }; - inline bool has_point(const Point2 &p_point) const { - if (p_point.x < position.x) - return false; - if (p_point.y < position.y) - return false; - - if (p_point.x >= (position.x + size.x)) - return false; - if (p_point.y >= (position.y + size.y)) - return false; - - return true; - } - - inline bool no_area() const { return (size.width <= 0 || size.height <= 0); } - - bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } - bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } - - inline Rect2 grow(real_t p_by) const { - - Rect2 g = *this; - g.position.x -= p_by; - g.position.y -= p_by; - g.size.width += p_by * 2; - g.size.height += p_by * 2; - return g; - } - - inline Rect2 grow_margin(Margin p_margin, real_t p_amount) const { - Rect2 g = *this; - g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0, - (MARGIN_TOP == p_margin) ? p_amount : 0, - (MARGIN_RIGHT == p_margin) ? p_amount : 0, - (MARGIN_BOTTOM == p_margin) ? p_amount : 0); - return g; - } - - inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const { - - Rect2 g = *this; - g.position.x -= p_left; - g.position.y -= p_top; - g.size.width += p_left + p_right; - g.size.height += p_top + p_bottom; - - return g; - } - - inline Rect2 expand(const Vector2 &p_vector) const { - - Rect2 r = *this; - r.expand_to(p_vector); - return r; - } - - inline void expand_to(const Vector2 &p_vector) { //in place function for speed - - Vector2 begin = position; - Vector2 end = position + size; - - if (p_vector.x < begin.x) - begin.x = p_vector.x; - if (p_vector.y < begin.y) - begin.y = p_vector.y; - - if (p_vector.x > end.x) - end.x = p_vector.x; - if (p_vector.y > end.y) - end.y = p_vector.y; - - position = begin; - size = end - begin; - } - - inline Rect2 abs() const { - - return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); - } - - operator String() const { return String(position) + ", " + String(size); } - - Rect2() {} - Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : - position(Point2(p_x, p_y)), - size(Size2(p_width, p_height)) { - } - Rect2(const Point2 &p_pos, const Size2 &p_size) : - position(p_pos), - size(p_size) { - } -}; - -/* INTEGER STUFF */ - -struct Point2i { - - union { - int x; - int width; - }; - union { - int y; - int height; - }; - - _FORCE_INLINE_ int &operator[](int p_idx) { - return p_idx ? y : x; - } - _FORCE_INLINE_ const int &operator[](int p_idx) const { - return p_idx ? y : x; - } - - Point2i operator+(const Point2i &p_v) const; - void operator+=(const Point2i &p_v); - Point2i operator-(const Point2i &p_v) const; - void operator-=(const Point2i &p_v); - Point2i operator*(const Point2i &p_v1) const; - - Point2i operator*(const int &rvalue) const; - void operator*=(const int &rvalue); - - Point2i operator/(const Point2i &p_v1) const; - - Point2i operator/(const int &rvalue) const; - - void operator/=(const int &rvalue); - - Point2i operator-() const; - bool operator<(const Point2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator>(const Point2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } - - bool operator==(const Point2i &p_vec2) const; - bool operator!=(const Point2i &p_vec2) const; - - real_t get_aspect() const { return width / (real_t)height; } - - operator String() const { return String::num(x) + ", " + String::num(y); } - - operator Vector2() const { return Vector2(x, y); } - inline Point2i(const Vector2 &p_vec2) { - x = (int)p_vec2.x; - y = (int)p_vec2.y; - } - inline Point2i(int p_x, int p_y) { - x = p_x; - y = p_y; - } - inline Point2i() { - x = 0; - y = 0; - } -}; - -typedef Point2i Size2i; - -struct Rect2i { - - Point2i position; - Size2i size; - - const Point2i &get_position() const { return position; } - void set_position(const Point2i &p_pos) { position = p_pos; } - const Point2i &get_size() const { return size; } - void set_size(const Point2i &p_size) { size = p_size; } - - int get_area() const { return size.width * size.height; } - - inline bool intersects(const Rect2i &p_rect) const { - if (position.x > (p_rect.position.x + p_rect.size.width)) - return false; - if ((position.x + size.width) < p_rect.position.x) - return false; - if (position.y > (p_rect.position.y + p_rect.size.height)) - return false; - if ((position.y + size.height) < p_rect.position.y) - return false; - - return true; - } - - inline bool encloses(const Rect2i &p_rect) const { - - return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && - ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) && - ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); - } - - inline bool has_no_area() const { - - return (size.x <= 0 || size.y <= 0); - } - inline Rect2i clip(const Rect2i &p_rect) const { /// return a clipped rect - - Rect2i new_rect = p_rect; - - if (!intersects(new_rect)) - return Rect2i(); - - new_rect.position.x = MAX(p_rect.position.x, position.x); - new_rect.position.y = MAX(p_rect.position.y, position.y); - - Point2 p_rect_end = p_rect.position + p_rect.size; - Point2 end = position + size; - - new_rect.size.x = (int)(MIN(p_rect_end.x, end.x) - new_rect.position.x); - new_rect.size.y = (int)(MIN(p_rect_end.y, end.y) - new_rect.position.y); - - return new_rect; - } - - inline Rect2i merge(const Rect2i &p_rect) const { ///< return a merged rect - - Rect2i new_rect; - - new_rect.position.x = MIN(p_rect.position.x, position.x); - new_rect.position.y = MIN(p_rect.position.y, position.y); - - new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); - new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); - - new_rect.size = new_rect.size - new_rect.position; //make relative again - - return new_rect; - }; - bool has_point(const Point2 &p_point) const { - if (p_point.x < position.x) - return false; - if (p_point.y < position.y) - return false; - - if (p_point.x >= (position.x + size.x)) - return false; - if (p_point.y >= (position.y + size.y)) - return false; - - return true; - } - - bool no_area() { return (size.width <= 0 || size.height <= 0); } - - bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } - bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } - - Rect2i grow(int p_by) const { - - Rect2i g = *this; - g.position.x -= p_by; - g.position.y -= p_by; - g.size.width += p_by * 2; - g.size.height += p_by * 2; - return g; - } - - inline void expand_to(const Point2i &p_vector) { - - Point2i begin = position; - Point2i end = position + size; - - if (p_vector.x < begin.x) - begin.x = p_vector.x; - if (p_vector.y < begin.y) - begin.y = p_vector.y; - - if (p_vector.x > end.x) - end.x = p_vector.x; - if (p_vector.y > end.y) - end.y = p_vector.y; - - position = begin; - size = end - begin; - } - - operator String() const { return String(position) + ", " + String(size); } - - operator Rect2() const { return Rect2(position, size); } - Rect2i(const Rect2 &p_r2) : - position(p_r2.position), - size(p_r2.size) { - } - Rect2i() {} - Rect2i(int p_x, int p_y, int p_width, int p_height) : - position(Point2(p_x, p_y)), - size(Size2(p_width, p_height)) { - } - Rect2i(const Point2 &p_pos, const Size2 &p_size) : - position(p_pos), - size(p_size) { - } -}; - -struct Transform2D { - // Warning #1: basis of Transform2D is stored differently from Basis. In terms of elements array, the basis matrix looks like "on paper": - // M = (elements[0][0] elements[1][0]) - // (elements[0][1] elements[1][1]) - // This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as elements[i]. - // Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to elements[1][0] here. - // This requires additional care when working with explicit indices. - // See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading. - - // Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down, - // and angle is measure from +X to +Y in a clockwise-fashion. - - Vector2 elements[3]; - - _FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return elements[0][0] * v.x + elements[1][0] * v.y; } - _FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return elements[0][1] * v.x + elements[1][1] * v.y; } - - const Vector2 &operator[](int p_idx) const { return elements[p_idx]; } - Vector2 &operator[](int p_idx) { return elements[p_idx]; } - - _FORCE_INLINE_ Vector2 get_axis(int p_axis) const { - ERR_FAIL_INDEX_V(p_axis, 3, Vector2()); - return elements[p_axis]; - } - _FORCE_INLINE_ void set_axis(int p_axis, const Vector2 &p_vec) { - ERR_FAIL_INDEX(p_axis, 3); - elements[p_axis] = p_vec; - } - - void invert(); - Transform2D inverse() const; - - void affine_invert(); - Transform2D affine_inverse() const; - - void set_rotation(real_t p_rot); - real_t get_rotation() const; - _FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale); - void rotate(real_t p_phi); - - void scale(const Size2 &p_scale); - void scale_basis(const Size2 &p_scale); - void translate(real_t p_tx, real_t p_ty); - void translate(const Vector2 &p_translation); - - real_t basis_determinant() const; - - Size2 get_scale() const; - - _FORCE_INLINE_ const Vector2 &get_origin() const { return elements[2]; } - _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; } - - Transform2D scaled(const Size2 &p_scale) const; - Transform2D basis_scaled(const Size2 &p_scale) const; - Transform2D translated(const Vector2 &p_offset) const; - Transform2D rotated(real_t p_phi) const; - - Transform2D untranslated() const; - - void orthonormalize(); - Transform2D orthonormalized() const; - - bool operator==(const Transform2D &p_transform) const; - bool operator!=(const Transform2D &p_transform) const; - - void operator*=(const Transform2D &p_transform); - Transform2D operator*(const Transform2D &p_transform) const; - - Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; - - _FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const; - _FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const; - _FORCE_INLINE_ Vector2 xform(const Vector2 &p_vec) const; - _FORCE_INLINE_ Vector2 xform_inv(const Vector2 &p_vec) const; - _FORCE_INLINE_ Rect2 xform(const Rect2 &p_rect) const; - _FORCE_INLINE_ Rect2 xform_inv(const Rect2 &p_rect) const; - - operator String() const; - - Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy) { - - elements[0][0] = xx; - elements[0][1] = xy; - elements[1][0] = yx; - elements[1][1] = yy; - elements[2][0] = ox; - elements[2][1] = oy; - } - - Transform2D(real_t p_rot, const Vector2 &p_pos); - Transform2D() { - elements[0][0] = 1.0; - elements[1][1] = 1.0; - } -}; - -bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const { - - //SAT intersection between local and transformed rect2 - - Vector2 xf_points[4] = { - p_xform.xform(p_rect.position), - p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y)), - p_xform.xform(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)), - p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)), - }; - - real_t low_limit; - - //base rect2 first (faster) - - if (xf_points[0].y > position.y) - goto next1; - if (xf_points[1].y > position.y) - goto next1; - if (xf_points[2].y > position.y) - goto next1; - if (xf_points[3].y > position.y) - goto next1; - - return false; - -next1: - - low_limit = position.y + size.y; - - if (xf_points[0].y < low_limit) - goto next2; - if (xf_points[1].y < low_limit) - goto next2; - if (xf_points[2].y < low_limit) - goto next2; - if (xf_points[3].y < low_limit) - goto next2; - - return false; - -next2: - - if (xf_points[0].x > position.x) - goto next3; - if (xf_points[1].x > position.x) - goto next3; - if (xf_points[2].x > position.x) - goto next3; - if (xf_points[3].x > position.x) - goto next3; - - return false; - -next3: - - low_limit = position.x + size.x; - - if (xf_points[0].x < low_limit) - goto next4; - if (xf_points[1].x < low_limit) - goto next4; - if (xf_points[2].x < low_limit) - goto next4; - if (xf_points[3].x < low_limit) - goto next4; - - return false; - -next4: - - Vector2 xf_points2[4] = { - position, - Vector2(position.x + size.x, position.y), - Vector2(position.x, position.y + size.y), - Vector2(position.x + size.x, position.y + size.y), - }; - - real_t maxa = p_xform.elements[0].dot(xf_points2[0]); - real_t mina = maxa; - - real_t dp = p_xform.elements[0].dot(xf_points2[1]); - maxa = MAX(dp, maxa); - mina = MIN(dp, mina); - - dp = p_xform.elements[0].dot(xf_points2[2]); - maxa = MAX(dp, maxa); - mina = MIN(dp, mina); - - dp = p_xform.elements[0].dot(xf_points2[3]); - maxa = MAX(dp, maxa); - mina = MIN(dp, mina); - - real_t maxb = p_xform.elements[0].dot(xf_points[0]); - real_t minb = maxb; - - dp = p_xform.elements[0].dot(xf_points[1]); - maxb = MAX(dp, maxb); - minb = MIN(dp, minb); - - dp = p_xform.elements[0].dot(xf_points[2]); - maxb = MAX(dp, maxb); - minb = MIN(dp, minb); - - dp = p_xform.elements[0].dot(xf_points[3]); - maxb = MAX(dp, maxb); - minb = MIN(dp, minb); - - if (mina > maxb) - return false; - if (minb > maxa) - return false; - - maxa = p_xform.elements[1].dot(xf_points2[0]); - mina = maxa; - - dp = p_xform.elements[1].dot(xf_points2[1]); - maxa = MAX(dp, maxa); - mina = MIN(dp, mina); - - dp = p_xform.elements[1].dot(xf_points2[2]); - maxa = MAX(dp, maxa); - mina = MIN(dp, mina); - - dp = p_xform.elements[1].dot(xf_points2[3]); - maxa = MAX(dp, maxa); - mina = MIN(dp, mina); - - maxb = p_xform.elements[1].dot(xf_points[0]); - minb = maxb; - - dp = p_xform.elements[1].dot(xf_points[1]); - maxb = MAX(dp, maxb); - minb = MIN(dp, minb); - - dp = p_xform.elements[1].dot(xf_points[2]); - maxb = MAX(dp, maxb); - minb = MIN(dp, minb); - - dp = p_xform.elements[1].dot(xf_points[3]); - maxb = MAX(dp, maxb); - minb = MIN(dp, minb); - - if (mina > maxb) - return false; - if (minb > maxa) - return false; - - return true; -} - -Vector2 Transform2D::basis_xform(const Vector2 &p_vec) const { - - return Vector2( - tdotx(p_vec), - tdoty(p_vec)); -} - -Vector2 Transform2D::basis_xform_inv(const Vector2 &p_vec) const { - - return Vector2( - elements[0].dot(p_vec), - elements[1].dot(p_vec)); -} - -Vector2 Transform2D::xform(const Vector2 &p_vec) const { - - return Vector2( - tdotx(p_vec), - tdoty(p_vec)) + - elements[2]; -} -Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const { - - Vector2 v = p_vec - elements[2]; - - return Vector2( - elements[0].dot(v), - elements[1].dot(v)); -} -Rect2 Transform2D::xform(const Rect2 &p_rect) const { - - Vector2 x = elements[0] * p_rect.size.x; - Vector2 y = elements[1] * p_rect.size.y; - Vector2 pos = xform(p_rect.position); - - Rect2 new_rect; - new_rect.position = pos; - new_rect.expand_to(pos + x); - new_rect.expand_to(pos + y); - new_rect.expand_to(pos + x + y); - return new_rect; -} - -void Transform2D::set_rotation_and_scale(real_t p_rot, const Size2 &p_scale) { - - elements[0][0] = Math::cos(p_rot) * p_scale.x; - elements[1][1] = Math::cos(p_rot) * p_scale.y; - elements[1][0] = -Math::sin(p_rot) * p_scale.y; - elements[0][1] = Math::sin(p_rot) * p_scale.x; -} - -Rect2 Transform2D::xform_inv(const Rect2 &p_rect) const { - - Vector2 ends[4] = { - xform_inv(p_rect.position), - xform_inv(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)), - xform_inv(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)), - xform_inv(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y)) - }; - - Rect2 new_rect; - new_rect.position = ends[0]; - new_rect.expand_to(ends[1]); - new_rect.expand_to(ends[2]); - new_rect.expand_to(ends[3]); - - return new_rect; -} - -#endif diff --git a/core/math/math_defs.h b/core/math/math_defs.h index d3484d8d02..a5feee6eb5 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -36,30 +36,71 @@ #define CMP_NORMALIZE_TOLERANCE 0.000001 #define CMP_POINT_IN_PLANE_EPSILON 0.00001 +#define Math_SQRT12 0.7071067811865475244008443621048490 +#define Math_SQRT2 1.4142135623730950488016887242 +#define Math_LN2 0.6931471805599453094172321215 +#define Math_TAU 6.2831853071795864769252867666 +#define Math_PI 3.1415926535897932384626433833 +#define Math_E 2.7182818284590452353602874714 +#define Math_INF INFINITY +#define Math_NAN NAN + #ifdef DEBUG_ENABLED #define MATH_CHECKS #endif #define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0) -/** - * "Real" is a type that will be translated to either floats or fixed depending - * on the compilation setting - */ enum ClockDirection { - CLOCKWISE, COUNTERCLOCKWISE }; -#ifdef REAL_T_IS_DOUBLE +enum Orientation { -typedef double real_t; + HORIZONTAL, + VERTICAL +}; -#else +enum HAlign { -typedef float real_t; + HALIGN_LEFT, + HALIGN_CENTER, + HALIGN_RIGHT +}; + +enum VAlign { + + VALIGN_TOP, + VALIGN_CENTER, + VALIGN_BOTTOM +}; +enum Margin { + + MARGIN_LEFT, + MARGIN_TOP, + MARGIN_RIGHT, + MARGIN_BOTTOM +}; + +enum Corner { + + CORNER_TOP_LEFT, + CORNER_TOP_RIGHT, + CORNER_BOTTOM_RIGHT, + CORNER_BOTTOM_LEFT +}; + +/** + * The "Real" type is an abstract type used for real numbers, such as 1.5, + * in contrast to integer numbers. Precision can be controlled with the + * presence or absence of the REAL_T_IS_DOUBLE define. + */ +#ifdef REAL_T_IS_DOUBLE +typedef double real_t; +#else +typedef float real_t; #endif #endif // MATH_DEFS_H diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index f0c0268f31..992084a653 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -39,13 +39,6 @@ #include <float.h> #include <math.h> -#define Math_PI 3.14159265358979323846 -#define Math_TAU 6.28318530717958647692 -#define Math_SQRT12 0.7071067811865475244008443621048490 -#define Math_LN2 0.693147180559945309417 -#define Math_INF INFINITY -#define Math_NAN NAN - class Math { static pcg32_random_t default_pcg; diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp new file mode 100644 index 0000000000..480bccdff1 --- /dev/null +++ b/core/math/rect2.cpp @@ -0,0 +1,240 @@ +/*************************************************************************/ +/* rect2.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "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. */ +/*************************************************************************/ + +#include "transform_2d.h" // Includes rect2.h but Rect2 needs Transform2D + +bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const { + + real_t min = 0, max = 1; + int axis = 0; + real_t sign = 0; + + for (int i = 0; i < 2; i++) { + real_t seg_from = p_from[i]; + real_t seg_to = p_to[i]; + real_t box_begin = position[i]; + real_t box_end = box_begin + size[i]; + real_t cmin, cmax; + real_t csign; + + if (seg_from < seg_to) { + + if (seg_from > box_end || seg_to < box_begin) + return false; + real_t length = seg_to - seg_from; + cmin = (seg_from < box_begin) ? ((box_begin - seg_from) / length) : 0; + cmax = (seg_to > box_end) ? ((box_end - seg_from) / length) : 1; + csign = -1.0; + + } else { + + if (seg_to > box_end || seg_from < box_begin) + return false; + real_t length = seg_to - seg_from; + cmin = (seg_from > box_end) ? (box_end - seg_from) / length : 0; + cmax = (seg_to < box_begin) ? (box_begin - seg_from) / length : 1; + csign = 1.0; + } + + if (cmin > min) { + min = cmin; + axis = i; + sign = csign; + } + if (cmax < max) + max = cmax; + if (max < min) + return false; + } + + Vector2 rel = p_to - p_from; + + if (r_normal) { + Vector2 normal; + normal[axis] = sign; + *r_normal = normal; + } + + if (r_pos) + *r_pos = p_from + rel * min; + + return true; +} + +bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const { + + //SAT intersection between local and transformed rect2 + + Vector2 xf_points[4] = { + p_xform.xform(p_rect.position), + p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y)), + p_xform.xform(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)), + p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)), + }; + + real_t low_limit; + + //base rect2 first (faster) + + if (xf_points[0].y > position.y) + goto next1; + if (xf_points[1].y > position.y) + goto next1; + if (xf_points[2].y > position.y) + goto next1; + if (xf_points[3].y > position.y) + goto next1; + + return false; + +next1: + + low_limit = position.y + size.y; + + if (xf_points[0].y < low_limit) + goto next2; + if (xf_points[1].y < low_limit) + goto next2; + if (xf_points[2].y < low_limit) + goto next2; + if (xf_points[3].y < low_limit) + goto next2; + + return false; + +next2: + + if (xf_points[0].x > position.x) + goto next3; + if (xf_points[1].x > position.x) + goto next3; + if (xf_points[2].x > position.x) + goto next3; + if (xf_points[3].x > position.x) + goto next3; + + return false; + +next3: + + low_limit = position.x + size.x; + + if (xf_points[0].x < low_limit) + goto next4; + if (xf_points[1].x < low_limit) + goto next4; + if (xf_points[2].x < low_limit) + goto next4; + if (xf_points[3].x < low_limit) + goto next4; + + return false; + +next4: + + Vector2 xf_points2[4] = { + position, + Vector2(position.x + size.x, position.y), + Vector2(position.x, position.y + size.y), + Vector2(position.x + size.x, position.y + size.y), + }; + + real_t maxa = p_xform.elements[0].dot(xf_points2[0]); + real_t mina = maxa; + + real_t dp = p_xform.elements[0].dot(xf_points2[1]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + dp = p_xform.elements[0].dot(xf_points2[2]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + dp = p_xform.elements[0].dot(xf_points2[3]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + real_t maxb = p_xform.elements[0].dot(xf_points[0]); + real_t minb = maxb; + + dp = p_xform.elements[0].dot(xf_points[1]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + dp = p_xform.elements[0].dot(xf_points[2]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + dp = p_xform.elements[0].dot(xf_points[3]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + if (mina > maxb) + return false; + if (minb > maxa) + return false; + + maxa = p_xform.elements[1].dot(xf_points2[0]); + mina = maxa; + + dp = p_xform.elements[1].dot(xf_points2[1]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + dp = p_xform.elements[1].dot(xf_points2[2]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + dp = p_xform.elements[1].dot(xf_points2[3]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + maxb = p_xform.elements[1].dot(xf_points[0]); + minb = maxb; + + dp = p_xform.elements[1].dot(xf_points[1]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + dp = p_xform.elements[1].dot(xf_points[2]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + dp = p_xform.elements[1].dot(xf_points[3]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + if (mina > maxb) + return false; + if (minb > maxa) + return false; + + return true; +} diff --git a/core/math/rect2.h b/core/math/rect2.h new file mode 100644 index 0000000000..20329bee0d --- /dev/null +++ b/core/math/rect2.h @@ -0,0 +1,371 @@ +/*************************************************************************/ +/* rect2.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "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. */ +/*************************************************************************/ + +#ifndef RECT2_H +#define RECT2_H + +#include "vector2.h" // also includes math_funcs and ustring + +struct Transform2D; + +struct Rect2 { + + Point2 position; + Size2 size; + + const Vector2 &get_position() const { return position; } + void set_position(const Vector2 &p_pos) { position = p_pos; } + const Vector2 &get_size() const { return size; } + void set_size(const Vector2 &p_size) { size = p_size; } + + real_t get_area() const { return size.width * size.height; } + + inline bool intersects(const Rect2 &p_rect) const { + if (position.x >= (p_rect.position.x + p_rect.size.width)) + return false; + if ((position.x + size.width) <= p_rect.position.x) + return false; + if (position.y >= (p_rect.position.y + p_rect.size.height)) + return false; + if ((position.y + size.height) <= p_rect.position.y) + return false; + + return true; + } + + inline real_t distance_to(const Vector2 &p_point) const { + + real_t dist = 0.0; + bool inside = true; + + if (p_point.x < position.x) { + real_t d = position.x - p_point.x; + dist = inside ? d : MIN(dist, d); + inside = false; + } + if (p_point.y < position.y) { + real_t d = position.y - p_point.y; + dist = inside ? d : MIN(dist, d); + inside = false; + } + if (p_point.x >= (position.x + size.x)) { + real_t d = p_point.x - (position.x + size.x); + dist = inside ? d : MIN(dist, d); + inside = false; + } + if (p_point.y >= (position.y + size.y)) { + real_t d = p_point.y - (position.y + size.y); + dist = inside ? d : MIN(dist, d); + inside = false; + } + + if (inside) + return 0; + else + return dist; + } + + bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const; + + bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = NULL, Point2 *r_normal = NULL) const; + + inline bool encloses(const Rect2 &p_rect) const { + + return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && + ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) && + ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); + } + + inline bool has_no_area() const { + + return (size.x <= 0 || size.y <= 0); + } + inline Rect2 clip(const Rect2 &p_rect) const { /// return a clipped rect + + Rect2 new_rect = p_rect; + + if (!intersects(new_rect)) + return Rect2(); + + new_rect.position.x = MAX(p_rect.position.x, position.x); + new_rect.position.y = MAX(p_rect.position.y, position.y); + + Point2 p_rect_end = p_rect.position + p_rect.size; + Point2 end = position + size; + + new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; + new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; + + return new_rect; + } + + inline Rect2 merge(const Rect2 &p_rect) const { ///< return a merged rect + + Rect2 new_rect; + + new_rect.position.x = MIN(p_rect.position.x, position.x); + new_rect.position.y = MIN(p_rect.position.y, position.y); + + new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); + new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); + + new_rect.size = new_rect.size - new_rect.position; //make relative again + + return new_rect; + }; + inline bool has_point(const Point2 &p_point) const { + if (p_point.x < position.x) + return false; + if (p_point.y < position.y) + return false; + + if (p_point.x >= (position.x + size.x)) + return false; + if (p_point.y >= (position.y + size.y)) + return false; + + return true; + } + + inline bool no_area() const { return (size.width <= 0 || size.height <= 0); } + + bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } + bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } + + inline Rect2 grow(real_t p_by) const { + + Rect2 g = *this; + g.position.x -= p_by; + g.position.y -= p_by; + g.size.width += p_by * 2; + g.size.height += p_by * 2; + return g; + } + + inline Rect2 grow_margin(Margin p_margin, real_t p_amount) const { + Rect2 g = *this; + g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0, + (MARGIN_TOP == p_margin) ? p_amount : 0, + (MARGIN_RIGHT == p_margin) ? p_amount : 0, + (MARGIN_BOTTOM == p_margin) ? p_amount : 0); + return g; + } + + inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const { + + Rect2 g = *this; + g.position.x -= p_left; + g.position.y -= p_top; + g.size.width += p_left + p_right; + g.size.height += p_top + p_bottom; + + return g; + } + + inline Rect2 expand(const Vector2 &p_vector) const { + + Rect2 r = *this; + r.expand_to(p_vector); + return r; + } + + inline void expand_to(const Vector2 &p_vector) { //in place function for speed + + Vector2 begin = position; + Vector2 end = position + size; + + if (p_vector.x < begin.x) + begin.x = p_vector.x; + if (p_vector.y < begin.y) + begin.y = p_vector.y; + + if (p_vector.x > end.x) + end.x = p_vector.x; + if (p_vector.y > end.y) + end.y = p_vector.y; + + position = begin; + size = end - begin; + } + + inline Rect2 abs() const { + + return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); + } + + operator String() const { return String(position) + ", " + String(size); } + + Rect2() {} + Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : + position(Point2(p_x, p_y)), + size(Size2(p_width, p_height)) { + } + Rect2(const Point2 &p_pos, const Size2 &p_size) : + position(p_pos), + size(p_size) { + } +}; + +struct Rect2i { + + Point2i position; + Size2i size; + + const Point2i &get_position() const { return position; } + void set_position(const Point2i &p_position) { position = p_position; } + const Size2i &get_size() const { return size; } + void set_size(const Size2i &p_size) { size = p_size; } + + int get_area() const { return size.width * size.height; } + + inline bool intersects(const Rect2i &p_rect) const { + if (position.x > (p_rect.position.x + p_rect.size.width)) + return false; + if ((position.x + size.width) < p_rect.position.x) + return false; + if (position.y > (p_rect.position.y + p_rect.size.height)) + return false; + if ((position.y + size.height) < p_rect.position.y) + return false; + + return true; + } + + inline bool encloses(const Rect2i &p_rect) const { + + return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && + ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) && + ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); + } + + inline bool has_no_area() const { + + return (size.x <= 0 || size.y <= 0); + } + inline Rect2i clip(const Rect2i &p_rect) const { /// return a clipped rect + + Rect2i new_rect = p_rect; + + if (!intersects(new_rect)) + return Rect2i(); + + new_rect.position.x = MAX(p_rect.position.x, position.x); + new_rect.position.y = MAX(p_rect.position.y, position.y); + + Point2 p_rect_end = p_rect.position + p_rect.size; + Point2 end = position + size; + + new_rect.size.x = (int)(MIN(p_rect_end.x, end.x) - new_rect.position.x); + new_rect.size.y = (int)(MIN(p_rect_end.y, end.y) - new_rect.position.y); + + return new_rect; + } + + inline Rect2i merge(const Rect2i &p_rect) const { ///< return a merged rect + + Rect2i new_rect; + + new_rect.position.x = MIN(p_rect.position.x, position.x); + new_rect.position.y = MIN(p_rect.position.y, position.y); + + new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); + new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); + + new_rect.size = new_rect.size - new_rect.position; //make relative again + + return new_rect; + }; + bool has_point(const Point2 &p_point) const { + if (p_point.x < position.x) + return false; + if (p_point.y < position.y) + return false; + + if (p_point.x >= (position.x + size.x)) + return false; + if (p_point.y >= (position.y + size.y)) + return false; + + return true; + } + + bool no_area() { return (size.width <= 0 || size.height <= 0); } + + bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } + bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } + + Rect2i grow(int p_by) const { + + Rect2i g = *this; + g.position.x -= p_by; + g.position.y -= p_by; + g.size.width += p_by * 2; + g.size.height += p_by * 2; + return g; + } + + inline void expand_to(const Point2i &p_vector) { + + Point2i begin = position; + Point2i end = position + size; + + if (p_vector.x < begin.x) + begin.x = p_vector.x; + if (p_vector.y < begin.y) + begin.y = p_vector.y; + + if (p_vector.x > end.x) + end.x = p_vector.x; + if (p_vector.y > end.y) + end.y = p_vector.y; + + position = begin; + size = end - begin; + } + + operator String() const { return String(position) + ", " + String(size); } + + operator Rect2() const { return Rect2(position, size); } + Rect2i(const Rect2 &p_r2) : + position(p_r2.position), + size(p_r2.size) { + } + Rect2i() {} + Rect2i(int p_x, int p_y, int p_width, int p_height) : + position(Point2(p_x, p_y)), + size(Size2(p_width, p_height)) { + } + Rect2i(const Point2 &p_pos, const Size2 &p_size) : + position(p_pos), + size(p_size) { + } +}; + +#endif // RECT2_H diff --git a/core/math/math_2d.cpp b/core/math/transform_2d.cpp index a053ffbd93..4bb763c879 100644 --- a/core/math/math_2d.cpp +++ b/core/math/transform_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* math_2d.cpp */ +/* transform_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,287 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "math_2d.h" - -real_t Vector2::angle() const { - - return Math::atan2(y, x); -} - -real_t Vector2::length() const { - - return Math::sqrt(x * x + y * y); -} - -real_t Vector2::length_squared() const { - - return x * x + y * y; -} - -void Vector2::normalize() { - - real_t l = x * x + y * y; - if (l != 0) { - - l = Math::sqrt(l); - x /= l; - y /= l; - } -} - -Vector2 Vector2::normalized() const { - - Vector2 v = *this; - v.normalize(); - return v; -} - -bool Vector2::is_normalized() const { - // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. - return Math::is_equal_approx(length_squared(), 1.0); -} - -real_t Vector2::distance_to(const Vector2 &p_vector2) const { - - return Math::sqrt((x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y)); -} - -real_t Vector2::distance_squared_to(const Vector2 &p_vector2) const { - - return (x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y); -} - -real_t Vector2::angle_to(const Vector2 &p_vector2) const { - - return Math::atan2(cross(p_vector2), dot(p_vector2)); -} - -real_t Vector2::angle_to_point(const Vector2 &p_vector2) const { - - return Math::atan2(y - p_vector2.y, x - p_vector2.x); -} - -real_t Vector2::dot(const Vector2 &p_other) const { - - return x * p_other.x + y * p_other.y; -} - -real_t Vector2::cross(const Vector2 &p_other) const { - - return x * p_other.y - y * p_other.x; -} - -Vector2 Vector2::floor() const { - - return Vector2(Math::floor(x), Math::floor(y)); -} - -Vector2 Vector2::ceil() const { - - return Vector2(Math::ceil(x), Math::ceil(y)); -} - -Vector2 Vector2::round() const { - - return Vector2(Math::round(x), Math::round(y)); -} - -Vector2 Vector2::rotated(real_t p_by) const { - - Vector2 v; - v.set_rotation(angle() + p_by); - v *= length(); - return v; -} - -Vector2 Vector2::project(const Vector2 &p_vec) const { - - Vector2 v1 = p_vec; - Vector2 v2 = *this; - return v2 * (v1.dot(v2) / v2.dot(v2)); -} - -Vector2 Vector2::snapped(const Vector2 &p_by) const { - - return Vector2( - Math::stepify(x, p_by.x), - Math::stepify(y, p_by.y)); -} - -Vector2 Vector2::clamped(real_t p_len) const { - - real_t l = length(); - Vector2 v = *this; - if (l > 0 && p_len < l) { - - v /= l; - v *= p_len; - } - - return v; -} - -Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const { - - Vector2 p0 = p_pre_a; - Vector2 p1 = *this; - Vector2 p2 = p_b; - Vector2 p3 = p_post_b; - - real_t t = p_t; - real_t t2 = t * t; - real_t t3 = t2 * t; - - Vector2 out; - out = 0.5 * ((p1 * 2.0) + - (-p0 + p2) * t + - (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + - (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); - return out; -} - -// slide returns the component of the vector along the given plane, specified by its normal vector. -Vector2 Vector2::slide(const Vector2 &p_normal) const { -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(p_normal.is_normalized() == false, Vector2()); -#endif - return *this - p_normal * this->dot(p_normal); -} - -Vector2 Vector2::bounce(const Vector2 &p_normal) const { - return -reflect(p_normal); -} - -Vector2 Vector2::reflect(const Vector2 &p_normal) const { -#ifdef MATH_CHECKS - ERR_FAIL_COND_V(p_normal.is_normalized() == false, Vector2()); -#endif - return 2.0 * p_normal * this->dot(p_normal) - *this; -} - -bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const { - - real_t min = 0, max = 1; - int axis = 0; - real_t sign = 0; - - for (int i = 0; i < 2; i++) { - real_t seg_from = p_from[i]; - real_t seg_to = p_to[i]; - real_t box_begin = position[i]; - real_t box_end = box_begin + size[i]; - real_t cmin, cmax; - real_t csign; - - if (seg_from < seg_to) { - - if (seg_from > box_end || seg_to < box_begin) - return false; - real_t length = seg_to - seg_from; - cmin = (seg_from < box_begin) ? ((box_begin - seg_from) / length) : 0; - cmax = (seg_to > box_end) ? ((box_end - seg_from) / length) : 1; - csign = -1.0; - - } else { - - if (seg_to > box_end || seg_from < box_begin) - return false; - real_t length = seg_to - seg_from; - cmin = (seg_from > box_end) ? (box_end - seg_from) / length : 0; - cmax = (seg_to < box_begin) ? (box_begin - seg_from) / length : 1; - csign = 1.0; - } - - if (cmin > min) { - min = cmin; - axis = i; - sign = csign; - } - if (cmax < max) - max = cmax; - if (max < min) - return false; - } - - Vector2 rel = p_to - p_from; - - if (r_normal) { - Vector2 normal; - normal[axis] = sign; - *r_normal = normal; - } - - if (r_pos) - *r_pos = p_from + rel * min; - - return true; -} - -/* Point2i */ - -Point2i Point2i::operator+(const Point2i &p_v) const { - - return Point2i(x + p_v.x, y + p_v.y); -} -void Point2i::operator+=(const Point2i &p_v) { - - x += p_v.x; - y += p_v.y; -} -Point2i Point2i::operator-(const Point2i &p_v) const { - - return Point2i(x - p_v.x, y - p_v.y); -} -void Point2i::operator-=(const Point2i &p_v) { - - x -= p_v.x; - y -= p_v.y; -} - -Point2i Point2i::operator*(const Point2i &p_v1) const { - - return Point2i(x * p_v1.x, y * p_v1.y); -}; - -Point2i Point2i::operator*(const int &rvalue) const { - - return Point2i(x * rvalue, y * rvalue); -}; -void Point2i::operator*=(const int &rvalue) { - - x *= rvalue; - y *= rvalue; -}; - -Point2i Point2i::operator/(const Point2i &p_v1) const { - - return Point2i(x / p_v1.x, y / p_v1.y); -}; - -Point2i Point2i::operator/(const int &rvalue) const { - - return Point2i(x / rvalue, y / rvalue); -}; - -void Point2i::operator/=(const int &rvalue) { - - x /= rvalue; - y /= rvalue; -}; - -Point2i Point2i::operator-() const { - - return Point2i(-x, -y); -} - -bool Point2i::operator==(const Point2i &p_vec2) const { - - return x == p_vec2.x && y == p_vec2.y; -} -bool Point2i::operator!=(const Point2i &p_vec2) const { - - return x != p_vec2.x || y != p_vec2.y; -} +#include "transform_2d.h" void Transform2D::invert() { // FIXME: this function assumes the basis is a rotation matrix, with no scaling. diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h new file mode 100644 index 0000000000..bf73755f0d --- /dev/null +++ b/core/math/transform_2d.h @@ -0,0 +1,201 @@ +/*************************************************************************/ +/* transform_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "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. */ +/*************************************************************************/ + +#ifndef TRANSFORM_2D_H +#define TRANSFORM_2D_H + +#include "rect2.h" // also includes vector2, math_funcs, and ustring + +struct Transform2D { + // Warning #1: basis of Transform2D is stored differently from Basis. In terms of elements array, the basis matrix looks like "on paper": + // M = (elements[0][0] elements[1][0]) + // (elements[0][1] elements[1][1]) + // This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as elements[i]. + // Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to elements[1][0] here. + // This requires additional care when working with explicit indices. + // See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading. + + // Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down, + // and angle is measure from +X to +Y in a clockwise-fashion. + + Vector2 elements[3]; + + _FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return elements[0][0] * v.x + elements[1][0] * v.y; } + _FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return elements[0][1] * v.x + elements[1][1] * v.y; } + + const Vector2 &operator[](int p_idx) const { return elements[p_idx]; } + Vector2 &operator[](int p_idx) { return elements[p_idx]; } + + _FORCE_INLINE_ Vector2 get_axis(int p_axis) const { + ERR_FAIL_INDEX_V(p_axis, 3, Vector2()); + return elements[p_axis]; + } + _FORCE_INLINE_ void set_axis(int p_axis, const Vector2 &p_vec) { + ERR_FAIL_INDEX(p_axis, 3); + elements[p_axis] = p_vec; + } + + void invert(); + Transform2D inverse() const; + + void affine_invert(); + Transform2D affine_inverse() const; + + void set_rotation(real_t p_rot); + real_t get_rotation() const; + _FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale); + void rotate(real_t p_phi); + + void scale(const Size2 &p_scale); + void scale_basis(const Size2 &p_scale); + void translate(real_t p_tx, real_t p_ty); + void translate(const Vector2 &p_translation); + + real_t basis_determinant() const; + + Size2 get_scale() const; + + _FORCE_INLINE_ const Vector2 &get_origin() const { return elements[2]; } + _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; } + + Transform2D scaled(const Size2 &p_scale) const; + Transform2D basis_scaled(const Size2 &p_scale) const; + Transform2D translated(const Vector2 &p_offset) const; + Transform2D rotated(real_t p_phi) const; + + Transform2D untranslated() const; + + void orthonormalize(); + Transform2D orthonormalized() const; + + bool operator==(const Transform2D &p_transform) const; + bool operator!=(const Transform2D &p_transform) const; + + void operator*=(const Transform2D &p_transform); + Transform2D operator*(const Transform2D &p_transform) const; + + Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; + + _FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const; + _FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const; + _FORCE_INLINE_ Vector2 xform(const Vector2 &p_vec) const; + _FORCE_INLINE_ Vector2 xform_inv(const Vector2 &p_vec) const; + _FORCE_INLINE_ Rect2 xform(const Rect2 &p_rect) const; + _FORCE_INLINE_ Rect2 xform_inv(const Rect2 &p_rect) const; + + operator String() const; + + Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy) { + + elements[0][0] = xx; + elements[0][1] = xy; + elements[1][0] = yx; + elements[1][1] = yy; + elements[2][0] = ox; + elements[2][1] = oy; + } + + Transform2D(real_t p_rot, const Vector2 &p_pos); + Transform2D() { + elements[0][0] = 1.0; + elements[1][1] = 1.0; + } +}; + +Vector2 Transform2D::basis_xform(const Vector2 &p_vec) const { + + return Vector2( + tdotx(p_vec), + tdoty(p_vec)); +} + +Vector2 Transform2D::basis_xform_inv(const Vector2 &p_vec) const { + + return Vector2( + elements[0].dot(p_vec), + elements[1].dot(p_vec)); +} + +Vector2 Transform2D::xform(const Vector2 &p_vec) const { + + return Vector2( + tdotx(p_vec), + tdoty(p_vec)) + + elements[2]; +} +Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const { + + Vector2 v = p_vec - elements[2]; + + return Vector2( + elements[0].dot(v), + elements[1].dot(v)); +} +Rect2 Transform2D::xform(const Rect2 &p_rect) const { + + Vector2 x = elements[0] * p_rect.size.x; + Vector2 y = elements[1] * p_rect.size.y; + Vector2 pos = xform(p_rect.position); + + Rect2 new_rect; + new_rect.position = pos; + new_rect.expand_to(pos + x); + new_rect.expand_to(pos + y); + new_rect.expand_to(pos + x + y); + return new_rect; +} + +void Transform2D::set_rotation_and_scale(real_t p_rot, const Size2 &p_scale) { + + elements[0][0] = Math::cos(p_rot) * p_scale.x; + elements[1][1] = Math::cos(p_rot) * p_scale.y; + elements[1][0] = -Math::sin(p_rot) * p_scale.y; + elements[0][1] = Math::sin(p_rot) * p_scale.x; +} + +Rect2 Transform2D::xform_inv(const Rect2 &p_rect) const { + + Vector2 ends[4] = { + xform_inv(p_rect.position), + xform_inv(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)), + xform_inv(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)), + xform_inv(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y)) + }; + + Rect2 new_rect; + new_rect.position = ends[0]; + new_rect.expand_to(ends[1]); + new_rect.expand_to(ends[2]); + new_rect.expand_to(ends[3]); + + return new_rect; +} + +#endif // TRANSFORM_2D_H diff --git a/core/math/triangulate.h b/core/math/triangulate.h index b1a583d0c5..a0f56f5f27 100644 --- a/core/math/triangulate.h +++ b/core/math/triangulate.h @@ -31,7 +31,7 @@ #ifndef TRIANGULATE_H #define TRIANGULATE_H -#include "math_2d.h" +#include "vector2.h" /* http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp new file mode 100644 index 0000000000..75d9b8b311 --- /dev/null +++ b/core/math/vector2.cpp @@ -0,0 +1,250 @@ +/*************************************************************************/ +/* vector2.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "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. */ +/*************************************************************************/ + +#include "vector2.h" + +real_t Vector2::angle() const { + + return Math::atan2(y, x); +} + +real_t Vector2::length() const { + + return Math::sqrt(x * x + y * y); +} + +real_t Vector2::length_squared() const { + + return x * x + y * y; +} + +void Vector2::normalize() { + + real_t l = x * x + y * y; + if (l != 0) { + + l = Math::sqrt(l); + x /= l; + y /= l; + } +} + +Vector2 Vector2::normalized() const { + + Vector2 v = *this; + v.normalize(); + return v; +} + +bool Vector2::is_normalized() const { + // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. + return Math::is_equal_approx(length_squared(), 1.0); +} + +real_t Vector2::distance_to(const Vector2 &p_vector2) const { + + return Math::sqrt((x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y)); +} + +real_t Vector2::distance_squared_to(const Vector2 &p_vector2) const { + + return (x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y); +} + +real_t Vector2::angle_to(const Vector2 &p_vector2) const { + + return Math::atan2(cross(p_vector2), dot(p_vector2)); +} + +real_t Vector2::angle_to_point(const Vector2 &p_vector2) const { + + return Math::atan2(y - p_vector2.y, x - p_vector2.x); +} + +real_t Vector2::dot(const Vector2 &p_other) const { + + return x * p_other.x + y * p_other.y; +} + +real_t Vector2::cross(const Vector2 &p_other) const { + + return x * p_other.y - y * p_other.x; +} + +Vector2 Vector2::floor() const { + + return Vector2(Math::floor(x), Math::floor(y)); +} + +Vector2 Vector2::ceil() const { + + return Vector2(Math::ceil(x), Math::ceil(y)); +} + +Vector2 Vector2::round() const { + + return Vector2(Math::round(x), Math::round(y)); +} + +Vector2 Vector2::rotated(real_t p_by) const { + + Vector2 v; + v.set_rotation(angle() + p_by); + v *= length(); + return v; +} + +Vector2 Vector2::project(const Vector2 &p_b) const { + return p_b * (dot(p_b) / p_b.dot(p_b)); +} + +Vector2 Vector2::snapped(const Vector2 &p_by) const { + + return Vector2( + Math::stepify(x, p_by.x), + Math::stepify(y, p_by.y)); +} + +Vector2 Vector2::clamped(real_t p_len) const { + + real_t l = length(); + Vector2 v = *this; + if (l > 0 && p_len < l) { + + v /= l; + v *= p_len; + } + + return v; +} + +Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const { + + Vector2 p0 = p_pre_a; + Vector2 p1 = *this; + Vector2 p2 = p_b; + Vector2 p3 = p_post_b; + + real_t t = p_t; + real_t t2 = t * t; + real_t t3 = t2 * t; + + Vector2 out; + out = 0.5 * ((p1 * 2.0) + + (-p0 + p2) * t + + (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); + return out; +} + +// slide returns the component of the vector along the given plane, specified by its normal vector. +Vector2 Vector2::slide(const Vector2 &p_normal) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(p_normal.is_normalized() == false, Vector2()); +#endif + return *this - p_normal * this->dot(p_normal); +} + +Vector2 Vector2::bounce(const Vector2 &p_normal) const { + return -reflect(p_normal); +} + +Vector2 Vector2::reflect(const Vector2 &p_normal) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(p_normal.is_normalized() == false, Vector2()); +#endif + return 2.0 * p_normal * this->dot(p_normal) - *this; +} + +/* Vector2i */ + +Vector2i Vector2i::operator+(const Vector2i &p_v) const { + + return Vector2i(x + p_v.x, y + p_v.y); +} +void Vector2i::operator+=(const Vector2i &p_v) { + + x += p_v.x; + y += p_v.y; +} +Vector2i Vector2i::operator-(const Vector2i &p_v) const { + + return Vector2i(x - p_v.x, y - p_v.y); +} +void Vector2i::operator-=(const Vector2i &p_v) { + + x -= p_v.x; + y -= p_v.y; +} + +Vector2i Vector2i::operator*(const Vector2i &p_v1) const { + + return Vector2i(x * p_v1.x, y * p_v1.y); +}; + +Vector2i Vector2i::operator*(const int &rvalue) const { + + return Vector2i(x * rvalue, y * rvalue); +}; +void Vector2i::operator*=(const int &rvalue) { + + x *= rvalue; + y *= rvalue; +}; + +Vector2i Vector2i::operator/(const Vector2i &p_v1) const { + + return Vector2i(x / p_v1.x, y / p_v1.y); +}; + +Vector2i Vector2i::operator/(const int &rvalue) const { + + return Vector2i(x / rvalue, y / rvalue); +}; + +void Vector2i::operator/=(const int &rvalue) { + + x /= rvalue; + y /= rvalue; +}; + +Vector2i Vector2i::operator-() const { + + return Vector2i(-x, -y); +} + +bool Vector2i::operator==(const Vector2i &p_vec2) const { + + return x == p_vec2.x && y == p_vec2.y; +} +bool Vector2i::operator!=(const Vector2i &p_vec2) const { + + return x != p_vec2.x || y != p_vec2.y; +} diff --git a/core/math/vector2.h b/core/math/vector2.h new file mode 100644 index 0000000000..fbcdc80b60 --- /dev/null +++ b/core/math/vector2.h @@ -0,0 +1,316 @@ +/*************************************************************************/ +/* vector2.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "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. */ +/*************************************************************************/ + +#ifndef VECTOR2_H +#define VECTOR2_H + +#include "math_funcs.h" +#include "ustring.h" + +struct Vector2i; + +struct Vector2 { + + union { + real_t x; + real_t width; + }; + union { + real_t y; + real_t height; + }; + + _FORCE_INLINE_ real_t &operator[](int p_idx) { + return p_idx ? y : x; + } + _FORCE_INLINE_ const real_t &operator[](int p_idx) const { + return p_idx ? y : x; + } + + void normalize(); + Vector2 normalized() const; + bool is_normalized() const; + + real_t length() const; + real_t length_squared() const; + + real_t distance_to(const Vector2 &p_vector2) const; + real_t distance_squared_to(const Vector2 &p_vector2) const; + real_t angle_to(const Vector2 &p_vector2) const; + real_t angle_to_point(const Vector2 &p_vector2) const; + + real_t dot(const Vector2 &p_other) const; + real_t cross(const Vector2 &p_other) const; + Vector2 project(const Vector2 &p_b) const; + + Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; + + Vector2 clamped(real_t p_len) const; + + _FORCE_INLINE_ static Vector2 linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t); + _FORCE_INLINE_ Vector2 linear_interpolate(const Vector2 &p_b, real_t p_t) const; + _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_b, real_t p_t) const; + Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const; + + Vector2 slide(const Vector2 &p_normal) const; + Vector2 bounce(const Vector2 &p_normal) const; + Vector2 reflect(const Vector2 &p_normal) const; + + Vector2 operator+(const Vector2 &p_v) const; + void operator+=(const Vector2 &p_v); + Vector2 operator-(const Vector2 &p_v) const; + void operator-=(const Vector2 &p_v); + Vector2 operator*(const Vector2 &p_v1) const; + + Vector2 operator*(const real_t &rvalue) const; + void operator*=(const real_t &rvalue); + void operator*=(const Vector2 &rvalue) { *this = *this * rvalue; } + + Vector2 operator/(const Vector2 &p_v1) const; + + Vector2 operator/(const real_t &rvalue) const; + + void operator/=(const real_t &rvalue); + + Vector2 operator-() const; + + bool operator==(const Vector2 &p_vec2) const; + bool operator!=(const Vector2 &p_vec2) const; + + bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } + bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); } + + real_t angle() const; + + void set_rotation(real_t p_radians) { + + x = Math::cos(p_radians); + y = Math::sin(p_radians); + } + + _FORCE_INLINE_ Vector2 abs() const { + + return Vector2(Math::abs(x), Math::abs(y)); + } + + Vector2 rotated(real_t p_by) const; + Vector2 tangent() const { + + return Vector2(y, -x); + } + + Vector2 floor() const; + Vector2 ceil() const; + Vector2 round() const; + Vector2 snapped(const Vector2 &p_by) const; + real_t aspect() const { return width / height; } + + operator String() const { return String::num(x) + ", " + String::num(y); } + + _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { + x = p_x; + y = p_y; + } + _FORCE_INLINE_ Vector2() { + x = 0; + y = 0; + } +}; + +_FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const { + + return p_vec - *this * (dot(p_vec) - p_d); +} + +_FORCE_INLINE_ Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) { + + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector2 Vector2::operator+(const Vector2 &p_v) const { + + return Vector2(x + p_v.x, y + p_v.y); +} +_FORCE_INLINE_ void Vector2::operator+=(const Vector2 &p_v) { + + x += p_v.x; + y += p_v.y; +} +_FORCE_INLINE_ Vector2 Vector2::operator-(const Vector2 &p_v) const { + + return Vector2(x - p_v.x, y - p_v.y); +} +_FORCE_INLINE_ void Vector2::operator-=(const Vector2 &p_v) { + + x -= p_v.x; + y -= p_v.y; +} + +_FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const { + + return Vector2(x * p_v1.x, y * p_v1.y); +}; + +_FORCE_INLINE_ Vector2 Vector2::operator*(const real_t &rvalue) const { + + return Vector2(x * rvalue, y * rvalue); +}; +_FORCE_INLINE_ void Vector2::operator*=(const real_t &rvalue) { + + x *= rvalue; + y *= rvalue; +}; + +_FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const { + + return Vector2(x / p_v1.x, y / p_v1.y); +}; + +_FORCE_INLINE_ Vector2 Vector2::operator/(const real_t &rvalue) const { + + return Vector2(x / rvalue, y / rvalue); +}; + +_FORCE_INLINE_ void Vector2::operator/=(const real_t &rvalue) { + + x /= rvalue; + y /= rvalue; +}; + +_FORCE_INLINE_ Vector2 Vector2::operator-() const { + + return Vector2(-x, -y); +} + +_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const { + + return x == p_vec2.x && y == p_vec2.y; +} +_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { + + return x != p_vec2.x || y != p_vec2.y; +} + +Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const { + + Vector2 res = *this; + + res.x += (p_t * (p_b.x - x)); + res.y += (p_t * (p_b.y - y)); + + return res; +} + +Vector2 Vector2::slerp(const Vector2 &p_b, real_t p_t) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(is_normalized() == false, Vector2()); +#endif + real_t theta = angle_to(p_b); + return rotated(theta * p_t); +} + +Vector2 Vector2::linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t) { + + Vector2 res = p_a; + + res.x += (p_t * (p_b.x - p_a.x)); + res.y += (p_t * (p_b.y - p_a.y)); + + return res; +} + +typedef Vector2 Size2; +typedef Vector2 Point2; + +/* INTEGER STUFF */ + +struct Vector2i { + + union { + int x; + int width; + }; + union { + int y; + int height; + }; + + _FORCE_INLINE_ int &operator[](int p_idx) { + return p_idx ? y : x; + } + _FORCE_INLINE_ const int &operator[](int p_idx) const { + return p_idx ? y : x; + } + + Vector2i operator+(const Vector2i &p_v) const; + void operator+=(const Vector2i &p_v); + Vector2i operator-(const Vector2i &p_v) const; + void operator-=(const Vector2i &p_v); + Vector2i operator*(const Vector2i &p_v1) const; + + Vector2i operator*(const int &rvalue) const; + void operator*=(const int &rvalue); + + Vector2i operator/(const Vector2i &p_v1) const; + + Vector2i operator/(const int &rvalue) const; + + void operator/=(const int &rvalue); + + Vector2i operator-() const; + bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } + bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } + + bool operator==(const Vector2i &p_vec2) const; + bool operator!=(const Vector2i &p_vec2) const; + + real_t get_aspect() const { return width / (real_t)height; } + + operator String() const { return String::num(x) + ", " + String::num(y); } + + operator Vector2() const { return Vector2(x, y); } + inline Vector2i(const Vector2 &p_vec2) { + x = (int)p_vec2.x; + y = (int)p_vec2.y; + } + inline Vector2i(int p_x, int p_y) { + x = p_x; + y = p_y; + } + inline Vector2i() { + x = 0; + y = 0; + } +}; + +typedef Vector2i Size2i; +typedef Vector2i Point2i; + +#endif // VECTOR2_H diff --git a/core/math/vector3.h b/core/math/vector3.h index 433adf09ee..a719e3965d 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -109,6 +109,8 @@ struct Vector3 { _FORCE_INLINE_ real_t distance_to(const Vector3 &p_b) const; _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_b) const; + _FORCE_INLINE_ Vector3 project(const Vector3 &p_b) const; + _FORCE_INLINE_ real_t angle_to(const Vector3 &p_b) const; _FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const; @@ -238,6 +240,10 @@ real_t Vector3::distance_squared_to(const Vector3 &p_b) const { return (p_b - *this).length_squared(); } +Vector3 Vector3::project(const Vector3 &p_b) const { + return p_b * (dot(p_b) / p_b.dot(p_b)); +} + real_t Vector3::angle_to(const Vector3 &p_b) const { return Math::atan2(cross(p_b).length(), dot(p_b)); diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h index 2f6dcb3178..6a33cf4d70 100644 --- a/core/method_ptrcall.h +++ b/core/method_ptrcall.h @@ -31,7 +31,7 @@ #ifndef METHOD_PTRCALL_H #define METHOD_PTRCALL_H -#include "math_2d.h" +#include "transform_2d.h" #include "typedefs.h" #include "variant.h" diff --git a/core/object.cpp b/core/object.cpp index a0c64feb09..ba8b710a84 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -450,16 +450,41 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid *r_valid = true; return; #endif - } else { - //something inside the object... :| - bool success = _setv(p_name, p_value); - if (success) { + } + + //something inside the object... :| + bool success = _setv(p_name, p_value); + if (success) { + if (r_valid) + *r_valid = true; + return; + } + + { + bool valid; + setvar(p_name, p_value, &valid); + if (valid) { + if (r_valid) + *r_valid = true; + return; + } + } + +#ifdef TOOLS_ENABLED + if (script_instance) { + bool valid; + script_instance->property_set_fallback(p_name, p_value, &valid); + if (valid) { if (r_valid) *r_valid = true; return; } - setvar(p_name, p_value, r_valid); } +#endif + + if (r_valid) + *r_valid = false; + return; } Variant Object::get(const StringName &p_name, bool *r_valid) const { @@ -513,8 +538,33 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { *r_valid = true; return ret; } + //if nothing else, use getvar - return getvar(p_name, r_valid); + { + bool valid; + ret = getvar(p_name, &valid); + if (valid) { + if (r_valid) + *r_valid = true; + return ret; + } + } + +#ifdef TOOLS_ENABLED + if (script_instance) { + bool valid; + ret = script_instance->property_get_fallback(p_name, &valid); + if (valid) { + if (r_valid) + *r_valid = true; + return ret; + } + } +#endif + + if (r_valid) + *r_valid = false; + return Variant(); } } @@ -979,9 +1029,14 @@ void Object::set_script(const RefPtr &p_script) { script = p_script; Ref<Script> s(script); - if (!s.is_null() && s->can_instance()) { - OBJ_DEBUG_LOCK - script_instance = s->instance_create(this); + if (!s.is_null()) { + if (s->can_instance()) { + OBJ_DEBUG_LOCK + script_instance = s->instance_create(this); + } else if (Engine::get_singleton()->is_editor_hint()) { + OBJ_DEBUG_LOCK + script_instance = s->placeholder_instance_create(this); + } } _change_notify("script"); diff --git a/core/os/input_event.h b/core/os/input_event.h index 07df81488b..8732c7e377 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -31,9 +31,9 @@ #ifndef INPUT_EVENT_H #define INPUT_EVENT_H -#include "math_2d.h" #include "os/copymem.h" #include "resource.h" +#include "transform_2d.h" #include "typedefs.h" #include "ustring.h" /** diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 146b4870e8..87a5c3e493 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -953,7 +953,8 @@ ProjectSettings::ProjectSettings() { disable_feature_overrides = false; registering_order = true; - Array va; + Array events; + Dictionary action; Ref<InputEventKey> key; Ref<InputEventJoypadButton> joyb; @@ -965,122 +966,162 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("application/config/use_custom_user_dir", false); GLOBAL_DEF("application/config/custom_user_dir_name", ""); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_ENTER); - va.push_back(key); + events.push_back(key); key.instance(); key->set_scancode(KEY_KP_ENTER); - va.push_back(key); + events.push_back(key); key.instance(); key->set_scancode(KEY_SPACE); - va.push_back(key); + events.push_back(key); joyb.instance(); joyb->set_button_index(JOY_BUTTON_0); - va.push_back(joyb); - GLOBAL_DEF("input/ui_accept", va); + events.push_back(joyb); + action["events"] = events; + GLOBAL_DEF("input/ui_accept", action); input_presets.push_back("input/ui_accept"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_SPACE); - va.push_back(key); + events.push_back(key); joyb.instance(); joyb->set_button_index(JOY_BUTTON_3); - va.push_back(joyb); - GLOBAL_DEF("input/ui_select", va); + events.push_back(joyb); + action["events"] = events; + GLOBAL_DEF("input/ui_select", action); input_presets.push_back("input/ui_select"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_ESCAPE); - va.push_back(key); + events.push_back(key); joyb.instance(); joyb->set_button_index(JOY_BUTTON_1); - va.push_back(joyb); - GLOBAL_DEF("input/ui_cancel", va); + events.push_back(joyb); + action["events"] = events; + GLOBAL_DEF("input/ui_cancel", action); input_presets.push_back("input/ui_cancel"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_TAB); - va.push_back(key); - GLOBAL_DEF("input/ui_focus_next", va); + events.push_back(key); + action["events"] = events; + GLOBAL_DEF("input/ui_focus_next", action); input_presets.push_back("input/ui_focus_next"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_TAB); key->set_shift(true); - va.push_back(key); - GLOBAL_DEF("input/ui_focus_prev", va); + events.push_back(key); + action["events"] = events; + GLOBAL_DEF("input/ui_focus_prev", action); input_presets.push_back("input/ui_focus_prev"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_LEFT); - va.push_back(key); + events.push_back(key); joyb.instance(); joyb->set_button_index(JOY_DPAD_LEFT); - va.push_back(joyb); - GLOBAL_DEF("input/ui_left", va); + events.push_back(joyb); + action["events"] = events; + GLOBAL_DEF("input/ui_left", action); input_presets.push_back("input/ui_left"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_RIGHT); - va.push_back(key); + events.push_back(key); joyb.instance(); joyb->set_button_index(JOY_DPAD_RIGHT); - va.push_back(joyb); - GLOBAL_DEF("input/ui_right", va); + events.push_back(joyb); + action["events"] = events; + GLOBAL_DEF("input/ui_right", action); input_presets.push_back("input/ui_right"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_UP); - va.push_back(key); + events.push_back(key); joyb.instance(); joyb->set_button_index(JOY_DPAD_UP); - va.push_back(joyb); - GLOBAL_DEF("input/ui_up", va); + events.push_back(joyb); + action["events"] = events; + GLOBAL_DEF("input/ui_up", action); input_presets.push_back("input/ui_up"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_DOWN); - va.push_back(key); + events.push_back(key); joyb.instance(); joyb->set_button_index(JOY_DPAD_DOWN); - va.push_back(joyb); - GLOBAL_DEF("input/ui_down", va); + events.push_back(joyb); + action["events"] = events; + GLOBAL_DEF("input/ui_down", action); input_presets.push_back("input/ui_down"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_PAGEUP); - va.push_back(key); - GLOBAL_DEF("input/ui_page_up", va); + events.push_back(key); + action["events"] = events; + GLOBAL_DEF("input/ui_page_up", action); input_presets.push_back("input/ui_page_up"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_PAGEDOWN); - va.push_back(key); - GLOBAL_DEF("input/ui_page_down", va); + events.push_back(key); + action["events"] = events; + GLOBAL_DEF("input/ui_page_down", action); input_presets.push_back("input/ui_page_down"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_HOME); - va.push_back(key); - GLOBAL_DEF("input/ui_home", va); + events.push_back(key); + action["events"] = events; + GLOBAL_DEF("input/ui_home", action); input_presets.push_back("input/ui_home"); - va = Array(); + action = Dictionary(); + action["deadzone"] = Variant(0.5f); + events = Array(); key.instance(); key->set_scancode(KEY_END); - va.push_back(key); - GLOBAL_DEF("input/ui_end", va); + events.push_back(key); + action["events"] = events; + GLOBAL_DEF("input/ui_end", action); input_presets.push_back("input/ui_end"); //GLOBAL_DEF("display/window/handheld/orientation", "landscape"); diff --git a/core/script_language.cpp b/core/script_language.cpp index 37ba3cfc62..e146fb773c 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -255,6 +255,17 @@ void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls } +void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) { + if (r_valid) + *r_valid = false; +} + +Variant ScriptInstance::property_get_fallback(const StringName &, bool *r_valid) { + if (r_valid) + *r_valid = false; + return Variant(); +} + void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DECLARE) { VARIANT_ARGPTRS; @@ -364,6 +375,9 @@ ScriptDebugger::ScriptDebugger() { bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) { + if (build_failed) + return false; + if (values.has(p_name)) { Variant defval; if (script->get_property_default_value(p_name, defval)) { @@ -392,22 +406,31 @@ bool PlaceHolderScriptInstance::get(const StringName &p_name, Variant &r_ret) co return true; } - Variant defval; - if (script->get_property_default_value(p_name, defval)) { - r_ret = defval; - return true; + if (!build_failed) { + Variant defval; + if (script->get_property_default_value(p_name, defval)) { + r_ret = defval; + return true; + } } + return false; } void PlaceHolderScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { - for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - PropertyInfo pinfo = E->get(); - if (!values.has(pinfo.name)) { - pinfo.usage |= PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE; + if (build_failed) { + for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + p_properties->push_back(E->get()); + } + } else { + for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + PropertyInfo pinfo = E->get(); + if (!values.has(pinfo.name)) { + pinfo.usage |= PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE; + } + p_properties->push_back(E->get()); } - p_properties->push_back(E->get()); } } @@ -426,12 +449,18 @@ Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName &p_n void PlaceHolderScriptInstance::get_method_list(List<MethodInfo> *p_list) const { + if (build_failed) + return; + if (script.is_valid()) { script->get_script_method_list(p_list); } } bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const { + if (build_failed) + return false; + if (script.is_valid()) { return script->has_method(p_method); } @@ -440,6 +469,8 @@ bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const { void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values) { + build_failed = false; + Set<StringName> new_values; for (const List<PropertyInfo>::Element *E = p_properties.front(); E; E = E->next()) { @@ -483,6 +514,51 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, c //change notify } +void PlaceHolderScriptInstance::property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid) { + + if (build_failed) { + Map<StringName, Variant>::Element *E = values.find(p_name); + + if (E) { + E->value() = p_value; + } else { + values.insert(p_name, p_value); + } + + bool found = false; + for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().name == p_name) { + found = true; + break; + } + } + if (!found) { + properties.push_back(PropertyInfo(p_value.get_type(), p_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE)); + } + } + + if (r_valid) + *r_valid = false; // Cannot change the value in either case +} + +Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_name, bool *r_valid) { + + if (build_failed) { + const Map<StringName, Variant>::Element *E = values.find(p_name); + + if (E) { + if (r_valid) + *r_valid = true; + return E->value(); + } + } + + if (r_valid) + *r_valid = false; + + return Variant(); +} + PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) : owner(p_owner), language(p_language), diff --git a/core/script_language.h b/core/script_language.h index 71d550d404..71b705e960 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -115,6 +115,7 @@ public: virtual StringName get_instance_base_type() const = 0; // this may not work in all scripts, will return empty if so virtual ScriptInstance *instance_create(Object *p_this) = 0; + virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) { return NULL; } virtual bool instance_has(const Object *p_this) const = 0; virtual bool has_source_code() const = 0; @@ -176,6 +177,9 @@ public: virtual bool is_placeholder() const { return false; } + virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid); + virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid); + virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; @@ -311,7 +315,7 @@ public: virtual void frame(); virtual bool handles_global_class_type(const String &p_type) const { return false; } - virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const { return String(); } + virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const { return String(); } virtual ~ScriptLanguage() {} }; @@ -326,6 +330,8 @@ class PlaceHolderScriptInstance : public ScriptInstance { ScriptLanguage *language; Ref<Script> script; + bool build_failed; + public: virtual bool set(const StringName &p_name, const Variant &p_value); virtual bool get(const StringName &p_name, Variant &r_ret) const; @@ -351,8 +357,14 @@ public: void update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values); //likely changed in editor + void set_build_failed(bool p_build_failed) { build_failed = p_build_failed; } + bool get_build_failed() const { return build_failed; } + virtual bool is_placeholder() const { return true; } + virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid); + virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid); + virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; } virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; } diff --git a/core/typedefs.h b/core/typedefs.h index 57afa3bdb4..094f1bbfd5 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -33,7 +33,7 @@ #include <stddef.h> /** - * Basic definitions and simple functions to be used everywhere.. + * Basic definitions and simple functions to be used everywhere. */ #include "platform_config.h" @@ -71,7 +71,7 @@ T *_nullptr() { #define OFFSET_OF(st, m) \ ((size_t)((char *)&(_nullptr<st>()->m) - (char *)0)) /** - * Some platforms (devices) not define NULL + * Some platforms (devices) don't define NULL */ #ifndef NULL @@ -79,7 +79,7 @@ T *_nullptr() { #endif /** - * Windows defines a lot of badly stuff we'll never ever use. undefine it. + * Windows badly defines a lot of stuff we'll never use. Undefine it. */ #ifdef _WIN32 @@ -296,4 +296,4 @@ struct _GlobalLock { #define unlikely(x) x #endif -#endif /* typedefs.h */ +#endif // TYPEDEFS_H diff --git a/core/ustring.cpp b/core/ustring.cpp index 96d142d85b..35cd27f7f3 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -148,7 +148,7 @@ void String::copy_from(const char *p_cstr) { } } -void String::copy_from(const CharType *p_cstr, int p_clip_to) { +void String::copy_from(const CharType *p_cstr, const int p_clip_to) { if (!p_cstr) { @@ -158,12 +158,9 @@ void String::copy_from(const CharType *p_cstr, int p_clip_to) { int len = 0; const CharType *ptr = p_cstr; - while (*(ptr++) != 0) + while ((p_clip_to < 0 || len < p_clip_to) && *(ptr++) != 0) len++; - if (p_clip_to >= 0 && len > p_clip_to) - len = p_clip_to; - if (len == 0) { resize(0); @@ -177,7 +174,7 @@ void String::copy_from(const CharType *p_cstr, int p_clip_to) { // p_char != NULL // p_length > 0 // p_length <= p_char strlen -void String::copy_from_unchecked(const CharType *p_char, int p_length) { +void String::copy_from_unchecked(const CharType *p_char, const int p_length) { resize(p_length + 1); set(p_length, 0); @@ -2791,7 +2788,11 @@ String String::format(const Variant &values, String placeholder) const { val = val.substr(1, val.length() - 2); } - new_string = new_string.replace(placeholder.replace("_", i_as_str), val); + if (placeholder.find("_") > -1) { + new_string = new_string.replace(placeholder.replace("_", i_as_str), val); + } else { + new_string = new_string.replace_first(placeholder, val); + } } } } else if (values.get_type() == Variant::DICTIONARY) { diff --git a/core/ustring.h b/core/ustring.h index 3b4405833c..01397f6912 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -84,9 +84,9 @@ class String { CowData<CharType> _cowdata; void copy_from(const char *p_cstr); - void copy_from(const CharType *p_cstr, int p_clip_to = -1); + void copy_from(const CharType *p_cstr, const int p_clip_to = -1); void copy_from(const CharType &p_char); - void copy_from_unchecked(const CharType *p_char, int p_length); + void copy_from_unchecked(const CharType *p_char, const int p_length); bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const; public: diff --git a/core/variant.cpp b/core/variant.cpp index e4be5520bc..b0e97900a2 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1192,7 +1192,7 @@ Variant::operator int64_t() const { case BOOL: return _data._bool ? 1 : 0; case INT: return _data._int; case REAL: return _data._real; - case STRING: return operator String().to_int(); + case STRING: return operator String().to_int64(); default: { return 0; @@ -1460,7 +1460,7 @@ Variant::operator String() const { const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem); //const String *K=NULL; - String str; + String str("{"); List<Variant> keys; d.get_key_list(&keys); @@ -1479,8 +1479,9 @@ Variant::operator String() const { for (int i = 0; i < pairs.size(); i++) { if (i > 0) str += ", "; - str += "(" + pairs[i].key + ":" + pairs[i].value + ")"; + str += pairs[i].key + ":" + pairs[i].value; } + str += "}"; return str; } break; diff --git a/core/variant.h b/core/variant.h index b48a0b3e73..577a33aa4d 100644 --- a/core/variant.h +++ b/core/variant.h @@ -42,7 +42,6 @@ #include "dvector.h" #include "face3.h" #include "io/ip_address.h" -#include "math_2d.h" #include "matrix3.h" #include "node_path.h" #include "plane.h" @@ -50,6 +49,7 @@ #include "ref_ptr.h" #include "rid.h" #include "transform.h" +#include "transform_2d.h" #include "ustring.h" #include "vector3.h" diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 19308ff683..ea51419233 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -339,6 +339,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector2, is_normalized); VCALL_LOCALMEM1R(Vector2, distance_to); VCALL_LOCALMEM1R(Vector2, distance_squared_to); + VCALL_LOCALMEM1R(Vector2, project); VCALL_LOCALMEM1R(Vector2, angle_to); VCALL_LOCALMEM1R(Vector2, angle_to_point); VCALL_LOCALMEM2R(Vector2, linear_interpolate); @@ -395,6 +396,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector3, round); VCALL_LOCALMEM1R(Vector3, distance_to); VCALL_LOCALMEM1R(Vector3, distance_squared_to); + VCALL_LOCALMEM1R(Vector3, project); VCALL_LOCALMEM1R(Vector3, angle_to); VCALL_LOCALMEM1R(Vector3, slide); VCALL_LOCALMEM1R(Vector3, bounce); @@ -1159,7 +1161,7 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i return Variant(bool(*p_args[0])); } case INT: { - return (int(*p_args[0])); + return (int64_t(*p_args[0])); } case REAL: { return real_t(*p_args[0]); @@ -1551,6 +1553,7 @@ void register_variant_methods() { ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, project, VECTOR2, "b", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to_point, VECTOR2, "to", varray()); ADDFUNC2R(VECTOR2, VECTOR2, Vector2, linear_interpolate, VECTOR2, "b", REAL, "t", varray()); @@ -1606,6 +1609,7 @@ void register_variant_methods() { ADDFUNC0R(VECTOR3, VECTOR3, Vector3, round, varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, project, VECTOR3, "b", varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, slide, VECTOR3, "n", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, bounce, VECTOR3, "n", varray()); @@ -1668,7 +1672,7 @@ void register_variant_methods() { ADDFUNC0NC(DICTIONARY, NIL, Dictionary, clear, varray()); ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has, NIL, "key", varray()); ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has_all, ARRAY, "keys", varray()); - ADDFUNC1(DICTIONARY, NIL, Dictionary, erase, NIL, "key", varray()); + ADDFUNC1R(DICTIONARY, BOOL, Dictionary, erase, NIL, "key", varray()); ADDFUNC0R(DICTIONARY, INT, Dictionary, hash, varray()); ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, keys, varray()); ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, values, varray()); diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml index 20d8bebd6b..7e871d68cb 100644 --- a/doc/classes/AcceptDialog.xml +++ b/doc/classes/AcceptDialog.xml @@ -60,7 +60,8 @@ </methods> <members> <member name="dialog_hide_on_ok" type="bool" setter="set_hide_on_ok" getter="get_hide_on_ok"> - If [code]true[/code] the dialog is hidden when accepted. Default value: [code]true[/code]. + If [code]true[/code] the dialog is hidden when the OK button is pressed. You can set it to [code]false[/code] if you want to do e.g. input validation when receiving the [signal confirmed] signal, and handle hiding the dialog in your own logic. Default value: [code]true[/code]. + Note: Some nodes derived from this class can have a different default value, and potentially their own built-in logic overriding this setting. For example [FileDialog] defaults to [code]false[/code], and has its own input validation code that is called when you press OK, which eventually hides the dialog if the input is valid. As such this property can't be used in [FileDialog] to disable hiding the dialog when pressing OK. </member> <member name="dialog_text" type="String" setter="set_text" getter="get_text"> The text displayed by this dialog. @@ -69,7 +70,7 @@ <signals> <signal name="confirmed"> <description> - Emitted when the dialog is accepted. + Emitted when the dialog is accepted, i.e. the OK button is pressed. </description> </signal> <signal name="custom_action"> diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index f93590bb9d..6dc91a234a 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -283,5 +283,8 @@ <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode"> Process animation during the idle process. </constant> + <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessMode"> + Do not process animation. Use the 'advance' method to process the animation manually. + </constant> </constants> </class> diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index a8e3a821b1..9b3679ae93 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -9,6 +9,14 @@ <demos> </demos> <methods> + <method name="advance"> + <return type="void"> + </return> + <argument index="0" name="delta" type="float"> + </argument> + <description> + </description> + </method> <method name="get_root_motion_transform" qualifiers="const"> <return type="Transform"> </return> @@ -33,5 +41,7 @@ </constant> <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode"> </constant> + <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessMode"> + </constant> </constants> </class> diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml index 7070fdec4c..62c97feaf9 100644 --- a/doc/classes/BackBufferCopy.xml +++ b/doc/classes/BackBufferCopy.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="BackBufferCopy" inherits="Node2D" category="Core" version="3.1"> <brief_description> - Copies a region of the screen (or the whole screen) to a buffer so it can be accessed with the texscreen() shader instruction. + Copies a region of the screen (or the whole screen) to a buffer so it can be accessed with [code]SCREEN_TEXTURE[/code] in the [code]texture()[/code] function. </brief_description> <description> - Node for back-buffering the currently displayed screen. The region defined in the BackBufferCopy node is bufferized with the content of the screen it covers, or the entire screen according to the copy mode set. Accessing this buffer is done with the texscreen() shader instruction. + Node for back-buffering the currently displayed screen. The region defined in the BackBufferCopy node is bufferized with the content of the screen it covers, or the entire screen according to the copy mode set. Use [code]SCREEN_TEXTURE[/code] in the [code]texture()[/code] function to access the buffer. </description> <tutorials> </tutorials> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 232357f822..4d52eacba8 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -4,7 +4,7 @@ Color picker control. </brief_description> <description> - This is a simple color picker [Control]. It's useful for selecting a color from an RGB/RGBA colorspace. + [Control] node displaying a color picker widget. It's useful for selecting a color from an RGB/RGBA colorspace. </description> <tutorials> </tutorials> @@ -17,7 +17,7 @@ <argument index="0" name="color" type="Color"> </argument> <description> - Adds the current selected to color to a list of colors (presets), the presets will be displayed in the color picker and the user will be able to select them, notice that the presets list is only for this color picker. + Adds the given color to a list of color presets. The presets are displayed in the color picker and the user will be able to select them. Note: the presets list is only for [i]this[/i] color picker. </description> </method> </methods> @@ -26,13 +26,13 @@ The currently selected color. </member> <member name="deferred_mode" type="bool" setter="set_deferred_mode" getter="is_deferred_mode"> - If [code]true[/code], the color will apply only after user releases mouse button, otherwise it will apply immediatly even in mouse motion event (which can cause performance issues). + If [code]true[/code] the color will apply only after the user releases the mouse button, otherwise it will apply immediatly even in mouse motion event (which can cause performance issues). </member> <member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha"> - If [code]true[/code], shows an alpha channel slider (transparency). + If [code]true[/code] shows an alpha channel slider (transparency). </member> <member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode"> - If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). + If [code]true[/code] allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). </member> </members> <signals> diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index d049e936a8..6ac2911c11 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -4,7 +4,7 @@ Button that pops out a [ColorPicker]. </brief_description> <description> - Encapsulates a [ColorPicker] making it accesible by pressing a button, pressing the button will toggle the [ColorPicker] visibility + Encapsulates a [ColorPicker] making it accesible by pressing a button. Pressing the button will toggle the [ColorPicker] visibility. </description> <tutorials> </tutorials> @@ -15,14 +15,14 @@ <return type="ColorPicker"> </return> <description> - Returns the [code]ColorPicker[/code] that this [code]ColorPickerButton[/code] toggles. + Returns the [ColorPicker] that this node toggles. </description> </method> <method name="get_popup"> <return type="PopupPanel"> </return> <description> - Returns the control's [PopupPanel] which allows you to connect to Popup Signals. This allows you to handle events when the ColorPicker is shown or hidden. + Returns the control's [PopupPanel] which allows you to connect to popup signals. This allows you to handle events when the ColorPicker is shown or hidden. </description> </method> </methods> diff --git a/doc/classes/ColorRect.xml b/doc/classes/ColorRect.xml index 69a70cfa39..e1bffb719e 100644 --- a/doc/classes/ColorRect.xml +++ b/doc/classes/ColorRect.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="ColorRect" inherits="Control" category="Core" version="3.1"> <brief_description> - Colored rect for canvas. + Colored rectangle. </brief_description> <description> - An object that is represented on the canvas as a rect with color. [Color] is used to set or get color info for the rect. + Displays a colored rectangle. </description> <tutorials> </tutorials> @@ -14,9 +14,9 @@ </methods> <members> <member name="color" type="Color" setter="set_frame_color" getter="get_frame_color"> - The color to fill the [code]ColorRect[/code]. + The fill color. [codeblock] - $ColorRect.color = Color(1, 0, 0, 1) # Set ColorRect node's color to red + $ColorRect.color = Color(1, 0, 0, 1) # Set ColorRect's color to red. [/codeblock] </member> </members> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index d11b369e68..2efb529f31 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Control" inherits="CanvasItem" category="Core" version="3.1"> <brief_description> - All User Interface nodes inherit from Control. Features anchors and margins to adapt its position and size to its parent. + All User Interface nodes inherit from Control. A control's anchors and margins adapt its position and size relative to its parent. </brief_description> <description> Base class for all User Interface or [i]UI[/i] related nodes. [code]Control[/code] features a bounding rectangle that defines its extents, an anchor position relative to its parent and margins that represent an offset to the anchor. The margins update automatically when the node, any of its parents, or the screen size change. @@ -23,7 +23,7 @@ <return type="Vector2"> </return> <description> - Returns the minimum size this Control can shrink to. The node can never be smaller than this minimum size. + Returns the minimum size for this control. See [member rect_min_size]. </description> </method> <method name="_gui_input" qualifiers="virtual"> @@ -129,7 +129,7 @@ This method should only be used to test the data. Process the data in [method drop_data]. [codeblock] extends Control - + func can_drop_data(position, data): # check position if it is relevant to you # otherwise just check data @@ -148,10 +148,10 @@ Godot calls this method to pass you the [code]data[/code] from a control's [method get_drag_data] result. Godot first calls [method can_drop_data] to test if [code]data[/code] is allowed to drop at [code]position[/code] where [code]position[/code] is local to this control. [codeblock] extends ColorRect - + func can_drop_data(position, data): return typeof(data) == TYPE_DICTIONARY and data.has('color') - + func drop_data(position, data): color = data['color'] [/codeblock] @@ -173,6 +173,7 @@ <return type="Vector2"> </return> <description> + Returns [member margin_left] and [member margin_top]. See also [member rect_position]. </description> </method> <method name="get_color" qualifiers="const"> @@ -207,7 +208,7 @@ <argument index="0" name="position" type="Vector2" default="Vector2( 0, 0 )"> </argument> <description> - Returns the mouse cursor shape the control displays on mouse hover, one of the [code]CURSOR_*[/code] constants. + Returns the mouse cursor shape the control displays on mouse hover. See [enum CursorShape]. </description> </method> <method name="get_drag_data" qualifiers="virtual"> @@ -220,7 +221,7 @@ A preview that will follow the mouse that should represent the data can be set with [method set_drag_preview]. A good time to set the preview is in this method. [codeblock] extends Control - + func get_drag_data(position): var mydata = make_data() set_drag_preview(make_preview(mydata)) @@ -232,14 +233,14 @@ <return type="Vector2"> </return> <description> - Returns MARGIN_LEFT and MARGIN_TOP at the same time. This is a helper (see [method set_margin]). + Returns [member margin_right] and [member margin_bottom]. </description> </method> <method name="get_focus_owner" qualifiers="const"> <return type="Control"> </return> <description> - Return which control is owning the keyboard focus, or null if no one. + Returns the control that has the keyboard focus or [code]null[/code] if none. </description> </method> <method name="get_font" qualifiers="const"> @@ -256,7 +257,7 @@ <return type="Rect2"> </return> <description> - Return position and size of the Control, relative to the top-left corner of the [i]window[/i] Control. This is a helper (see [method get_global_position], [method get_size]). + Returns the position and size of the control relative to the top-left corner of the screen. See [member rect_position] and [member rect_size]. </description> </method> <method name="get_icon" qualifiers="const"> @@ -273,33 +274,35 @@ <return type="Vector2"> </return> <description> - Return the minimum size this Control can shrink to. A control will never be displayed or resized smaller than its minimum size. + Returns the minimum size for this control. See [member rect_min_size]. </description> </method> <method name="get_parent_area_size" qualifiers="const"> <return type="Vector2"> </return> <description> + Returns the width/height occupied in the parent control. </description> </method> <method name="get_parent_control" qualifiers="const"> <return type="Control"> </return> <description> + Returns the parent control node. </description> </method> <method name="get_rect" qualifiers="const"> <return type="Rect2"> </return> <description> - Return position and size of the Control, relative to the top-left corner of the parent Control. This is a helper (see [method get_position], [method get_size]). + Returns the position and size of the control relative to the top-left corner of the parent Control. See [member rect_position] and [member rect_size]. </description> </method> <method name="get_rotation" qualifiers="const"> <return type="float"> </return> <description> - Return the rotation (in radians) + Returns the rotation (in radians). </description> </method> <method name="get_stylebox" qualifiers="const"> @@ -318,7 +321,7 @@ <argument index="0" name="at_position" type="Vector2" default="Vector2( 0, 0 )"> </argument> <description> - Return the tooltip, which will appear when the cursor is resting over this control. + Returns the tooltip, which will appear when the cursor is resting over this control. </description> </method> <method name="grab_click_focus"> @@ -374,7 +377,7 @@ <return type="bool"> </return> <description> - Return whether the Control is the current focused control (see [method set_focus_mode]). + Returns [code]true[/code] if this is the current focused control. See [member focus_mode]. </description> </method> <method name="has_font" qualifiers="const"> @@ -457,7 +460,7 @@ <return type="void"> </return> <description> - Give up the focus, no other control will be able to receive keyboard input. + Give up the focus. No other control will be able to receive keyboard input. </description> </method> <method name="set_anchor"> @@ -516,7 +519,7 @@ <argument index="0" name="position" type="Vector2"> </argument> <description> - Sets MARGIN_LEFT and MARGIN_TOP at the same time. This is a helper (see [method set_margin]). + Sets [member margin_left] and [member margin_top] at the same time. </description> </method> <method name="set_drag_forwarding"> @@ -534,15 +537,15 @@ extends Control func _ready(): set_drag_forwarding(target_control) - + # TargetControl.gd extends Control func can_drop_data_fw(position, data, from_control): return true - + func drop_data_fw(position, data, from_control): my_handle_data(data) - + func get_drag_data_fw(position, from_control): set_drag_preview(my_preview) return my_data() @@ -564,7 +567,7 @@ <argument index="0" name="position" type="Vector2"> </argument> <description> - Sets MARGIN_RIGHT and MARGIN_BOTTOM at the same time. This is a helper (see [method set_margin]). + Sets [member margin_right] and [member margin_bottom] at the same time. </description> </method> <method name="set_margins_preset"> @@ -585,7 +588,7 @@ <argument index="0" name="radians" type="float"> </argument> <description> - Set the rotation (in radians). + Sets the rotation (in radians). </description> </method> <method name="show_modal"> @@ -594,7 +597,7 @@ <argument index="0" name="exclusive" type="bool" default="false"> </argument> <description> - Display a Control as modal. Control must be a subwindow. Modal controls capture the input signals until closed or the area outside them is accessed. When a modal control loses focus, or the ESC key is pressed, they automatically hide. Modal controls are used extensively for popup dialogs and menus. + Displays a control as modal. Control must be a subwindow. Modal controls capture the input signals until closed or the area outside them is accessed. When a modal control loses focus, or the ESC key is pressed, they automatically hide. Modal controls are used extensively for popup dialogs and menus. </description> </method> <method name="warp_mouse"> @@ -753,22 +756,22 @@ </signals> <constants> <constant name="FOCUS_NONE" value="0" enum="FocusMode"> - The node cannot grab focus. Use with [member set_focus_mode]. + The node cannot grab focus. Use with [member focus_mode]. </constant> <constant name="FOCUS_CLICK" value="1" enum="FocusMode"> - The node can only grab focus on mouse clicks. Use with [member set_focus_mode]. + The node can only grab focus on mouse clicks. Use with [member focus_mode]. </constant> <constant name="FOCUS_ALL" value="2" enum="FocusMode"> - The node can grab focus on mouse click or using the arrows and the Tab keys on the keyboard. Use with [member set_focus_mode]. + The node can grab focus on mouse click or using the arrows and the Tab keys on the keyboard. Use with [member focus_mode]. </constant> <constant name="NOTIFICATION_RESIZED" value="40"> Sent when the node changes size. Use [member rect_size] to get the new size. </constant> <constant name="NOTIFICATION_MOUSE_ENTER" value="41"> - Sent when the mouse pointer enters the node's [code]Rect[/code] area. + Sent when the mouse pointer enters the node. </constant> <constant name="NOTIFICATION_MOUSE_EXIT" value="42"> - Sent when the mouse pointer exits the node's [code]Rect[/code] area. + Sent when the mouse pointer exits the node. </constant> <constant name="NOTIFICATION_FOCUS_ENTER" value="43"> Sent when the node grabs focus. @@ -777,7 +780,7 @@ Sent when the node loses focus. </constant> <constant name="NOTIFICATION_THEME_CHANGED" value="45"> - Sent when the node's [member theme] changes, right before Godot redraws the [code]Control[/code]. Happens when you call one of the [code]add_*_override[/code] + Sent when the node's [member theme] changes, right before Godot redraws the control. Happens when you call one of the [code]add_*_override[/code] </constant> <constant name="NOTIFICATION_MODAL_CLOSE" value="46"> Sent when an open modal dialog closes. See [member show_modal]. @@ -903,7 +906,7 @@ Sets the node's size flags to both fill and expand. See the 2 constants above for more information. </constant> <constant name="SIZE_SHRINK_CENTER" value="4" enum="SizeFlags"> - Tells the parent [Container] to center the node in itself. It centers the [code]Control[/code] based on its bounding box, so it doesn't work with the fill or expand size flags. Use with [member size_flags_horizontal] and [member size_flags_vertical]. + Tells the parent [Container] to center the node in itself. It centers the control based on its bounding box, so it doesn't work with the fill or expand size flags. Use with [member size_flags_horizontal] and [member size_flags_vertical]. </constant> <constant name="SIZE_SHRINK_END" value="8" enum="SizeFlags"> Tells the parent [Container] to align the node with its end, either the bottom or the right edge. It doesn't work with the fill or expand size flags. Use with [member size_flags_horizontal] and [member size_flags_vertical]. diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml index 48ca0ddc01..4723cf8ee4 100644 --- a/doc/classes/ItemList.xml +++ b/doc/classes/ItemList.xml @@ -77,6 +77,14 @@ <description> </description> </method> + <method name="get_item_custom_fg_color" qualifiers="const"> + <return type="Color"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <description> + </description> + </method> <method name="get_item_icon" qualifiers="const"> <return type="Texture"> </return> @@ -227,6 +235,16 @@ <description> </description> </method> + <method name="set_item_custom_fg_color"> + <return type="void"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <argument index="1" name="custom_fg_color" type="Color"> + </argument> + <description> + </description> + </method> <method name="set_item_disabled"> <return type="void"> </return> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index ab49bc468c..a830468042 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -184,6 +184,8 @@ <argument index="0" name="property" type="NodePath"> </argument> <description> + Get indexed object property by String. + Property indices get accessed with colon seperation, for example: [code]position:x[/code] </description> </method> <method name="get_instance_id" qualifiers="const"> diff --git a/doc/classes/ReferenceRect.xml b/doc/classes/ReferenceRect.xml index 4453e8726f..4c6f014965 100644 --- a/doc/classes/ReferenceRect.xml +++ b/doc/classes/ReferenceRect.xml @@ -14,8 +14,8 @@ </methods> <constants> </constants> - <theme_items> - <theme_item name="border" type="StyleBox"> - </theme_item> - </theme_items> + <members> + <member name="border_color" type="Color" setter="set_border_color" getter="get_border_color"> + </member> + </members> </class> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index 25426ee72c..533df57564 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -94,6 +94,8 @@ <argument index="0" name="position" type="Vector2"> </argument> <description> + If [member drop_mode_flags] includes [code]DROP_MODE_INBETWEEN[/code], returns -1 if [code]position[/code] is the upper part of a tree item at that position, 1 for the lower part, and additionally 0 for the middle part if [member drop_mode_flags] includes [code]DROP_MODE_ON_ITEM[/code]. + Otherwise, returns 0. If there are no tree item at [code]position[/code], returns -100. </description> </method> <method name="get_edited" qualifiers="const"> @@ -228,7 +230,7 @@ The amount of columns. </member> <member name="drop_mode_flags" type="int" setter="set_drop_mode_flags" getter="get_drop_mode_flags"> - The drop mode as an OR combination of flags. See [code]DROP_MODE_*[/code] constants. + The drop mode as an OR combination of flags. See [code]DROP_MODE_*[/code] constants. Once dropping is done, reverts to [code]DROP_MODE_DISABLED[/code]. Setting this during [method can_drop_data] is recommended. </member> <member name="hide_folding" type="bool" setter="set_hide_folding" getter="is_folding_hidden"> If [code]true[/code] the folding arrow is hidden. diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 2332c1a7aa..123226183a 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -170,7 +170,7 @@ <argument index="7" name="delay" type="float" default="0"> </argument> <description> - Animates [code]property[/code] of [code]object[/code] from [code]initial_val[/code] to [code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. + Animates [code]property[/code] of [code]object[/code] from [code]initial_val[/code] to [code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. Setting the initial value to [code]null[/code] uses the current value of the property. Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] for [code]ease_type[/code] parameters. These values control the timing and direction of the interpolation. See the class description for more information </description> </method> diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 6ffeddf5c1..9b18962a6f 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -130,6 +130,15 @@ Returns the distance to vector [code]b[/code]. </description> </method> + <method name="project"> + <return type="Vector2"> + </return> + <argument index="0" name="b" type="Vector2"> + </argument> + <description> + Returns the vector projected onto the vector [code]b[/code]. + </description> + </method> <method name="dot"> <return type="float"> </return> diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 62a480166a..22384c5012 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -99,6 +99,15 @@ Returns the distance to [code]b[/code]. </description> </method> + <method name="project_onto"> + <return type="Vector3"> + </return> + <argument index="0" name="b" type="Vector3"> + </argument> + <description> + Returns the vector projected onto the vector [code]b[/code]. + </description> + </method> <method name="dot"> <return type="float"> </return> diff --git a/drivers/convex_decomp/b2d_decompose.h b/drivers/convex_decomp/b2d_decompose.h index 068689d73d..b21792047e 100644 --- a/drivers/convex_decomp/b2d_decompose.h +++ b/drivers/convex_decomp/b2d_decompose.h @@ -31,8 +31,8 @@ #ifndef B2D_DECOMPOSE_H #define B2D_DECOMPOSE_H -#include "math_2d.h" #include "vector.h" +#include "vector2.h" Vector<Vector<Vector2> > b2d_decompose(const Vector<Vector2> &p_polygon); #endif // B2D_DECOMPOSE_H diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index c35d9bac98..f7b49c627d 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -79,6 +79,7 @@ void RasterizerCanvasGLES2::canvas_begin() { } if (storage->frame.clear_request) { + glColorMask(true, true, true, true); glClearColor(storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index b460a2559b..288a144b32 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -2031,7 +2031,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const } break; default: { - print_line("uhm"); + // FIXME: implement other background modes } break; } } diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 1bd3c0a935..6ff6bd7ced 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -3641,6 +3641,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { texture_set_flags(rt->texture, texture->flags); + glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // copy texscreen buffers diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 9251e21080..3e64c92e96 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -526,7 +526,7 @@ FRAGMENT_SHADER_CODE #if defined(ENABLE_NORMALMAP) normalmap.xy = normalmap.xy * 2.0 - 1.0; - normalmap.z = sqrt(1.0 - dot(normalmap.xy, normalmap.xy)); + normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); // normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; normal = normalmap; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index dee8bcbc58..2d6f42679f 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1700,7 +1700,7 @@ FRAGMENT_SHADER_CODE #if defined(ENABLE_NORMALMAP) normalmap.xy=normalmap.xy*2.0-1.0; - normalmap.z=sqrt(1.0-dot(normalmap.xy,normalmap.xy)); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. + normalmap.z=sqrt(max(0.0, 1.0-dot(normalmap.xy,normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. normal = normalize( mix(normal_interp,tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z,normaldepth) ) * side; diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index f97f1d0871..8433f4ff7b 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -86,7 +86,7 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) { memdelete(f); } - _update_favorite_list(); + _save_and_update_favorite_list(); // Restore valid window bounds or pop up at default size. if (EditorSettings::get_singleton()->has_setting("interface/dialogs/create_new_node_bounds")) { @@ -157,6 +157,18 @@ Ref<Texture> CreateDialog::_get_editor_icon(const String &p_type) const { return get_icon(p_type, "EditorIcons"); } + if (ScriptServer::is_global_class(p_type)) { + String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(p_type); + RES icon; + if (FileAccess::exists(icon_path)) { + icon = ResourceLoader::load(icon_path); + } + if (!icon.is_valid()) { + icon = get_icon(ScriptServer::get_global_class_base(p_type), "EditorIcons"); + } + return icon; + } + const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types(); for (const Map<String, Vector<EditorData::CustomType> >::Element *E = p_map.front(); E; E = E->next()) { const Vector<EditorData::CustomType> &ct = E->value(); @@ -180,7 +192,7 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p return; bool cpp_type = ClassDB::class_exists(p_type); - EditorData &ed = EditorNode::get_singleton()->get_editor_data(); + EditorData &ed = EditorNode::get_editor_data(); if (p_type == base_type) return; @@ -262,13 +274,7 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p const String &description = EditorHelp::get_doc_data()->class_list[p_type].brief_description; item->set_tooltip(0, description); - if (cpp_type && has_icon(p_type, "EditorIcons")) { - - item->set_icon(0, get_icon(p_type, "EditorIcons")); - } else if (!cpp_type && has_icon(ScriptServer::get_global_class_base(p_type), "EditorIcons")) { - - item->set_icon(0, get_icon(ScriptServer::get_global_class_base(p_type), "EditorIcons")); - } + item->set_icon(0, _get_editor_icon(p_type)); p_types[p_type] = item; } @@ -287,7 +293,7 @@ void CreateDialog::_update_search() { HashMap<String, TreeItem *> types; TreeItem *root = search_options->create_item(); - EditorData &ed = EditorNode::get_singleton()->get_editor_data(); + EditorData &ed = EditorNode::get_editor_data(); root->set_text(0, base_type); if (has_icon(base_type, "EditorIcons")) { @@ -330,7 +336,7 @@ void CreateDialog::_update_search() { break; } - type = ClassDB::get_parent_class(type); + type = cpp_type ? ClassDB::get_parent_class(type) : ed.script_class_get_base(type); } if (found) @@ -490,16 +496,8 @@ Object *CreateDialog::instance_selected() { custom = md; if (custom != String()) { - if (ScriptServer::is_global_class(custom)) { - RES script = ResourceLoader::load(ScriptServer::get_global_class_path(custom)); - ERR_FAIL_COND_V(!script.is_valid(), NULL); - - Object *obj = ClassDB::instance(ScriptServer::get_global_class_base(custom)); - ERR_FAIL_COND_V(!obj, NULL); - - obj->set_script(script.get_ref_ptr()); - return obj; + return EditorNode::get_editor_data().script_class_instance(custom); } return EditorNode::get_editor_data().instance_custom_type(selected->get_text(0), custom); } else { @@ -545,8 +543,7 @@ void CreateDialog::_favorite_toggled() { favorite->set_pressed(false); } - _save_favorite_list(); - _update_favorite_list(); + _save_and_update_favorite_list(); } void CreateDialog::_save_favorite_list() { @@ -556,8 +553,11 @@ void CreateDialog::_save_favorite_list() { if (f) { for (int i = 0; i < favorite_list.size(); i++) { - - f->store_line(favorite_list[i]); + String l = favorite_list[i]; + String name = l.split(" ")[0]; + if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) + continue; + f->store_line(l); } memdelete(f); } @@ -568,11 +568,15 @@ void CreateDialog::_update_favorite_list() { favorites->clear(); TreeItem *root = favorites->create_item(); for (int i = 0; i < favorite_list.size(); i++) { - TreeItem *ti = favorites->create_item(root); String l = favorite_list[i]; + String name = l.split(" ")[0]; + if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) + continue; + TreeItem *ti = favorites->create_item(root); ti->set_text(0, l); ti->set_icon(0, _get_editor_icon(l)); } + emit_signal("favorites_updated"); } void CreateDialog::_history_selected() { @@ -581,7 +585,7 @@ void CreateDialog::_history_selected() { if (!item) return; - search_box->set_text(item->get_text(0)); + search_box->set_text(item->get_text(0).get_slicec(' ', 0)); _update_search(); } @@ -591,7 +595,7 @@ void CreateDialog::_favorite_selected() { if (!item) return; - search_box->set_text(item->get_text(0)); + search_box->set_text(item->get_text(0).get_slicec(' ', 0)); _update_search(); } @@ -675,6 +679,10 @@ void CreateDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co } } + _save_and_update_favorite_list(); +} + +void CreateDialog::_save_and_update_favorite_list() { _save_favorite_list(); _update_favorite_list(); } @@ -690,12 +698,14 @@ void CreateDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_favorite_selected"), &CreateDialog::_favorite_selected); ClassDB::bind_method(D_METHOD("_history_activated"), &CreateDialog::_history_activated); ClassDB::bind_method(D_METHOD("_favorite_activated"), &CreateDialog::_favorite_activated); + ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list); ClassDB::bind_method("get_drag_data_fw", &CreateDialog::get_drag_data_fw); ClassDB::bind_method("can_drop_data_fw", &CreateDialog::can_drop_data_fw); ClassDB::bind_method("drop_data_fw", &CreateDialog::drop_data_fw); ADD_SIGNAL(MethodInfo("create")); + ADD_SIGNAL(MethodInfo("favorites_updated")); } CreateDialog::CreateDialog() { diff --git a/editor/create_dialog.h b/editor/create_dialog.h index f8eec231a4..6df9eebc8c 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -90,6 +90,8 @@ protected: void _notification(int p_what); static void _bind_methods(); + void _save_and_update_favorite_list(); + public: Object *instance_selected(); String get_selected_type(); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index f4ef11eb36..69c120bb3c 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -888,11 +888,56 @@ StringName EditorData::script_class_get_base(const String &p_class) { return script->get_language()->get_global_class_name(base_script->get_path()); } +Object *EditorData::script_class_instance(const String &p_class) { + if (ScriptServer::is_global_class(p_class)) { + Object *obj = ClassDB::instance(ScriptServer::get_global_class_base(p_class)); + if (obj) { + RES script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class)); + if (script.is_valid()) + obj->set_script(script.get_ref_ptr()); + + RES icon = ResourceLoader::load(script_class_get_icon_path(p_class)); + if (icon.is_valid()) + obj->set_meta("_editor_icon", icon); + + return obj; + } + } + return NULL; +} + +void EditorData::script_class_save_icon_paths() { + List<StringName> keys; + _script_class_icon_paths.get_key_list(&keys); + + Dictionary d; + for (List<StringName>::Element *E = keys.front(); E; E = E->next()) { + d[E->get()] = _script_class_icon_paths[E->get()]; + } + + ProjectSettings::get_singleton()->set("_global_script_class_icons", d); + ProjectSettings::get_singleton()->save(); +} + +void EditorData::script_class_load_icon_paths() { + script_class_clear_icon_paths(); + + Dictionary d = ProjectSettings::get_singleton()->get("_global_script_class_icons"); + List<Variant> keys; + d.get_key_list(&keys); + + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { + String key = E->get().operator String(); + _script_class_icon_paths[key] = d[key]; + } +} + EditorData::EditorData() { current_edited_scene = -1; //load_imported_scenes_from_globals(); + script_class_load_icon_paths(); } /////////// diff --git a/editor/editor_data.h b/editor/editor_data.h index fac6635cd2..285769aa78 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -146,6 +146,8 @@ private: bool _find_updated_instances(Node *p_root, Node *p_node, Set<String> &checked_paths); + HashMap<StringName, String> _script_class_icon_paths; + public: EditorPlugin *get_editor(Object *p_object); EditorPlugin *get_subeditor(Object *p_object); @@ -213,6 +215,12 @@ public: bool script_class_is_parent(const String &p_class, const String &p_inherits); StringName script_class_get_base(const String &p_class); + Object *script_class_instance(const String &p_class); + String script_class_get_icon_path(const String &p_class) const { return _script_class_icon_paths.has(p_class) ? _script_class_icon_paths[p_class] : String(); } + void script_class_set_icon_path(const String &p_class, const String &p_icon_path) { _script_class_icon_paths[p_class] = p_icon_path; } + void script_class_clear_icon_paths() { _script_class_icon_paths.clear(); } + void script_class_save_icon_paths(); + void script_class_load_icon_paths(); EditorData(); }; diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 7d56c4985a..d240f4ed25 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -558,7 +558,9 @@ void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p } if (single_item_selected) { item_menu->add_separator(); - item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + Dictionary item_meta = item_list->get_item_metadata(p_item); + String item_text = item_meta["dir"] ? TTR("Open In File Manager") : TTR("Show In File Manager"); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), item_text, ITEM_MENU_SHOW_IN_EXPLORER); } if (item_menu->get_item_count() > 0) { @@ -582,7 +584,7 @@ void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) { } item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5); item_menu->add_separator(); - item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Open In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); item_menu->set_position(item_list->get_global_position() + p_pos); item_menu->popup(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index d8ab41fa05..9562a8c63c 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -133,6 +133,10 @@ String EditorFileSystemDirectory::get_file_script_class_extends(int p_idx) const return files[p_idx]->script_class_extends; } +String EditorFileSystemDirectory::get_file_script_class_icon_path(int p_idx) const { + return files[p_idx]->script_class_icon_path; +} + StringName EditorFileSystemDirectory::get_file_type(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, files.size(), ""); @@ -233,6 +237,7 @@ void EditorFileSystem::_scan_filesystem() { fc.import_valid = split[4].to_int64() != 0; fc.script_class_name = split[5].get_slice("<>", 0); fc.script_class_extends = split[5].get_slice("<>", 1); + fc.script_class_icon_path = split[5].get_slice("<>", 2); String deps = split[6].strip_edges(); if (deps.length()) { @@ -721,6 +726,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess fi->import_valid = fc->import_valid; fi->script_class_name = fc->script_class_name; fi->script_class_extends = fc->script_class_extends; + fi->script_class_icon_path = fc->script_class_icon_path; if (fc->type == String()) { fi->type = ResourceLoader::get_resource_type(path); @@ -731,7 +737,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess } else { fi->type = ResourceFormatImporter::get_singleton()->get_resource_type(path); - fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends); + fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path); fi->modified_time = 0; fi->import_modified_time = 0; fi->import_valid = ResourceLoader::is_import_valid(path); @@ -753,10 +759,11 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess fi->import_valid = true; fi->script_class_name = fc->script_class_name; fi->script_class_extends = fc->script_class_extends; + fi->script_class_icon_path = fc->script_class_icon_path; } else { //new or modified time fi->type = ResourceLoader::get_resource_type(path); - fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends); + fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path); fi->deps = _get_dependencies(path); fi->modified_time = mt; fi->import_modified_time = 0; @@ -855,7 +862,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const fi->modified_time = FileAccess::get_modified_time(path); fi->import_modified_time = 0; fi->type = ResourceLoader::get_resource_type(path); - fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends); + fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path); fi->import_valid = ResourceLoader::is_import_valid(path); { @@ -1110,7 +1117,7 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir, for (int i = 0; i < p_dir->files.size(); i++) { - String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends; + String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path; s += "::"; for (int j = 0; j < p_dir->files[i]->deps.size(); j++) { @@ -1316,19 +1323,22 @@ Vector<String> EditorFileSystem::_get_dependencies(const String &p_path) { return ret; } -String EditorFileSystem::_get_global_script_class(const String &p_type, const String &p_path, String *r_extends) const { +String EditorFileSystem::_get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const { for (int i = 0; i < ScriptServer::get_language_count(); i++) { if (ScriptServer::get_language(i)->handles_global_class_type(p_type)) { String global_name; String extends; + String icon_path; - global_name = ScriptServer::get_language(i)->get_global_class_name(p_path, &extends); + global_name = ScriptServer::get_language(i)->get_global_class_name(p_path, &extends, &icon_path); *r_extends = extends; + *r_icon_path = icon_path; return global_name; } } *r_extends = String(); + *r_icon_path = String(); return String(); } @@ -1346,8 +1356,8 @@ void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) { lang = ScriptServer::get_language(j)->get_name(); } } - ScriptServer::add_global_class(files[i]->script_class_name, files[i]->script_class_extends, lang, p_dir->get_file_path(i)); + EditorNode::get_editor_data().script_class_set_icon_path(files[i]->script_class_name, files[i]->script_class_icon_path); } for (int i = 0; i < p_dir->get_subdir_count(); i++) { _scan_script_classes(p_dir->get_subdir(i)); @@ -1366,6 +1376,8 @@ void EditorFileSystem::update_script_classes() { } ScriptServer::save_global_classes(); + EditorNode::get_editor_data().script_class_save_icon_paths(); + emit_signal("script_classes_updated"); } void EditorFileSystem::_queue_update_script_classes() { @@ -1437,7 +1449,7 @@ void EditorFileSystem::update_file(const String &p_file) { } fs->files[cpos]->type = type; - fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends); + fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends, &fs->files[cpos]->script_class_icon_path); fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file); fs->files[cpos]->deps = _get_dependencies(p_file); fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file); @@ -1704,6 +1716,7 @@ void EditorFileSystem::_bind_methods() { ADD_SIGNAL(MethodInfo("filesystem_changed")); ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist"))); ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::POOL_STRING_ARRAY, "resources"))); + ADD_SIGNAL(MethodInfo("script_classes_updated")); } void EditorFileSystem::_update_extensions() { diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 1aa35f4782..75ca79932f 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -60,6 +60,7 @@ class EditorFileSystemDirectory : public Object { bool verified; //used for checking changes String script_class_name; String script_class_extends; + String script_class_icon_path; }; struct FileInfoSort { @@ -90,6 +91,7 @@ public: bool get_file_import_is_valid(int p_idx) const; String get_file_script_class_name(int p_idx) const; //used for scripts String get_file_script_class_extends(int p_idx) const; //used for scripts + String get_file_script_class_icon_path(int p_idx) const; //used for scripts EditorFileSystemDirectory *get_parent(); @@ -163,6 +165,7 @@ class EditorFileSystem : public Node { bool import_valid; String script_class_name; String script_class_extends; + String script_class_icon_path; }; HashMap<String, FileCache> file_cache; @@ -225,7 +228,7 @@ class EditorFileSystem : public Node { volatile bool update_script_classes_queued; void _queue_update_script_classes(); - String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends) const; + String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const; protected: void _notification(int p_what); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 1ac6eef8b4..60826aa81b 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -718,16 +718,22 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { if (p_class == edited_class) return OK; //already there + edited_class = p_class; + _update_doc(); + return OK; +} + +void EditorHelp::_update_doc() { + scroll_locked = true; class_desc->clear(); method_line.clear(); section_line.clear(); - edited_class = p_class; _init_colors(); - DocData::ClassDoc cd = doc->class_list[p_class]; //make a copy, so we can sort without worrying + DocData::ClassDoc cd = doc->class_list[edited_class]; //make a copy, so we can sort without worrying Ref<Font> doc_font = get_font("doc", "EditorFonts"); Ref<Font> doc_title_font = get_font("doc_title", "EditorFonts"); @@ -739,7 +745,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->push_color(title_color); class_desc->add_text(TTR("Class:") + " "); class_desc->push_color(headline_color); - _add_text(p_class); + _add_text(edited_class); class_desc->pop(); class_desc->pop(); class_desc->pop(); @@ -1458,8 +1464,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { } scroll_locked = false; - - return OK; } void EditorHelp::_request_help(const String &p_string) { @@ -1756,9 +1760,6 @@ void EditorHelp::_add_text(const String &p_bbcode) { _add_text_to_rt(p_bbcode, class_desc); } -void EditorHelp::_update_doc() { -} - void EditorHelp::generate_doc() { doc = memnew(DocData); @@ -1781,6 +1782,7 @@ void EditorHelp::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor")); + _update_doc(); } break; diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 158eedfb0f..b3ec717d85 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -54,7 +54,11 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f self->emit_signal("show_request"); */ - self->add_message(err_str, true); + if (p_type == ERR_HANDLER_WARNING) { + self->add_message(err_str, MSG_TYPE_WARNING); + } else { + self->add_message(err_str, MSG_TYPE_ERROR); + } } void EditorLog::_notification(int p_what) { @@ -95,22 +99,32 @@ void EditorLog::clear() { _clear_request(); } -void EditorLog::add_message(const String &p_msg, bool p_error) { +void EditorLog::add_message(const String &p_msg, MessageType p_type) { log->add_newline(); - if (p_error) { - log->push_color(get_color("error_color", "Editor")); - Ref<Texture> icon = get_icon("Error", "EditorIcons"); - log->add_image(icon); - log->add_text(" "); - tool_button->set_icon(icon); + bool restore = p_type != MSG_TYPE_STD; + switch (p_type) { + case MSG_TYPE_ERROR: { + log->push_color(get_color("error_color", "Editor")); + Ref<Texture> icon = get_icon("Error", "EditorIcons"); + log->add_image(icon); + log->add_text(" "); + tool_button->set_icon(icon); + } break; + case MSG_TYPE_WARNING: { + log->push_color(get_color("warning_color", "Editor")); + Ref<Texture> icon = get_icon("Warning", "EditorIcons"); + log->add_image(icon); + log->add_text(" "); + tool_button->set_icon(icon); + } break; } log->add_text(p_msg); //button->set_text(p_msg); - if (p_error) + if (restore) log->pop(); } diff --git a/editor/editor_log.h b/editor/editor_log.h index f9bc82de7d..8d0310d914 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -42,6 +42,7 @@ #include "scene/gui/panel_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" + class EditorLog : public VBoxContainer { GDCLASS(EditorLog, VBoxContainer); @@ -68,7 +69,13 @@ protected: void _notification(int p_what); public: - void add_message(const String &p_msg, bool p_error = false); + enum MessageType { + MSG_TYPE_STD, + MSG_TYPE_ERROR, + MSG_TYPE_WARNING + }; + + void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD); void set_tool_button(ToolButton *p_tool_button); void deinit(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 81b7a66361..0be6ee8759 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -411,6 +411,18 @@ void EditorNode::_notification(int p_what) { } } +void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_name) { + Ref<Script> script = Object::cast_to<Script>(p_script); + if (script.is_null()) + return; + if (p_activate_name.length()) { + set_addon_plugin_enabled(p_activate_name, true); + } + project_settings->update_plugins(); + project_settings->hide(); + push_item(script.operator->()); +} + void EditorNode::_fs_changed() { for (Set<FileDialog *>::Element *E = file_dialogs.front(); E; E = E->next()) { @@ -2547,6 +2559,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled) EditorPlugin *ep = memnew(EditorPlugin); ep->set_script(script.get_ref_ptr()); + ep->set_dir_cache(p_addon); plugin_addons[p_addon] = ep; add_editor_plugin(ep); @@ -4548,6 +4561,8 @@ void EditorNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_resources_reimported"), &EditorNode::_resources_reimported); ClassDB::bind_method(D_METHOD("_bottom_panel_raise_toggled"), &EditorNode::_bottom_panel_raise_toggled); + ClassDB::bind_method(D_METHOD("_on_plugin_ready"), &EditorNode::_on_plugin_ready); + ClassDB::bind_method(D_METHOD("_video_driver_selected"), &EditorNode::_video_driver_selected); ADD_SIGNAL(MethodInfo("play_pressed")); @@ -4566,7 +4581,7 @@ static Node *_resource_get_edited_scene() { void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_error) { EditorNode *en = (EditorNode *)p_this; - en->log->add_message(p_string, p_error); + en->log->add_message(p_string, p_error ? EditorLog::MSG_TYPE_ERROR : EditorLog::MSG_TYPE_STD); } EditorNode::EditorNode() { @@ -4776,7 +4791,7 @@ EditorNode::EditorNode() { EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false); EDITOR_DEF("interface/inspector/horizontal_vector3_editing", true); EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true); - EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial"); + EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial,Script"); EDITOR_DEF("run/auto_save/save_before_running", true); theme_base = memnew(Control); @@ -5134,6 +5149,10 @@ EditorNode::EditorNode() { p->connect("id_pressed", this, "_menu_option"); p->add_item(TTR("Export"), FILE_EXPORT_PROJECT); + plugin_config_dialog = memnew(PluginConfigDialog); + plugin_config_dialog->connect("plugin_ready", this, "_on_plugin_ready"); + gui_base->add_child(plugin_config_dialog); + tool_menu = memnew(PopupMenu); tool_menu->set_name("Tools"); tool_menu->connect("index_pressed", this, "_tool_menu_option"); @@ -5409,7 +5428,7 @@ EditorNode::EditorNode() { } filesystem_dock = memnew(FileSystemDock(this)); - filesystem_dock->set_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode"))); + filesystem_dock->set_file_list_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode"))); if (use_single_dock_column) { dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(filesystem_dock); @@ -5448,6 +5467,7 @@ EditorNode::EditorNode() { bottom_panel->add_child(bottom_panel_vb); bottom_panel_hb = memnew(HBoxContainer); + bottom_panel_hb->set_custom_minimum_size(Size2(0, 24)); // Adjust for the height of the "Expand Bottom Dock" icon. bottom_panel_vb->add_child(bottom_panel_hb); bottom_panel_hb_editors = memnew(HBoxContainer); diff --git a/editor/editor_node.h b/editor/editor_node.h index 85aa37ec7e..5a17ab6ca0 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -56,6 +56,7 @@ #include "editor/inspector_dock.h" #include "editor/node_dock.h" #include "editor/pane_drag.h" +#include "editor/plugin_config_dialog.h" #include "editor/progress_dialog.h" #include "editor/project_export.h" #include "editor/project_settings_editor.h" @@ -257,6 +258,8 @@ private: ToolButton *search_button; TextureProgress *audio_vu; + PluginConfigDialog *plugin_config_dialog; + RichTextLabel *load_errors; AcceptDialog *load_error_dialog; @@ -416,6 +419,8 @@ private: void _tool_menu_option(int p_idx); void _update_debug_options(); + void _on_plugin_ready(Object *p_script, const String &p_activate_name); + void _fs_changed(); void _resources_reimported(const Vector<String> &p_resources); void _sources_changed(bool p_exist); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index a926401558..137e710c5c 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -309,6 +309,12 @@ void EditorPlugin::remove_autoload_singleton(const String &p_name) { EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_remove(p_name); } +Ref<ConfigFile> EditorPlugin::get_config() { + Ref<ConfigFile> cf = memnew(ConfigFile); + cf->load(_dir_cache.plus_file("plugin.cfg")); + return cf; +} + ToolButton *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const String &p_title) { ERR_FAIL_NULL_V(p_control, NULL); return EditorNode::get_singleton()->add_bottom_panel_item(p_title, p_control); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index c417f487dc..903b82937f 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -114,6 +114,7 @@ class EditorPlugin : public Node { bool force_draw_over_forwarding_enabled; String last_main_screen_name; + String _dir_cache; protected: static void _bind_methods(); @@ -221,6 +222,10 @@ public: void add_autoload_singleton(const String &p_name, const String &p_path); void remove_autoload_singleton(const String &p_name); + void set_dir_cache(const String &p_dir) { _dir_cache = p_dir; } + String get_dir_cache() { return _dir_cache; } + Ref<ConfigFile> get_config(); + EditorPlugin(); virtual ~EditorPlugin(); }; diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index ea1e0fe99e..68f8ed6d94 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -41,6 +41,9 @@ void EditorPluginSettings::_notification(int p_what) { if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) { update_plugins(); + } else if (p_what == Node::NOTIFICATION_READY) { + plugin_config_dialog->connect("plugin_ready", EditorNode::get_singleton(), "_on_plugin_ready"); + plugin_list->connect("button_pressed", this, "_cell_button_pressed"); } } @@ -124,6 +127,7 @@ void EditorPluginSettings::update_plugins() { item->set_range_config(3, 0, 1, 1); item->set_text(3, "Inactive,Active"); item->set_editable(3, true); + item->add_button(4, get_icon("Edit", "EditorIcons"), BUTTON_PLUGIN_EDIT, false, TTR("Edit Plugin")); if (EditorNode::get_singleton()->is_addon_plugin_enabled(d)) { item->set_custom_color(3, get_color("success_color", "Editor")); @@ -164,17 +168,44 @@ void EditorPluginSettings::_plugin_activity_changed() { ti->set_custom_color(3, get_color("disabled_font_color", "Editor")); } +void EditorPluginSettings::_create_clicked() { + plugin_config_dialog->config(""); + plugin_config_dialog->popup_centered(); +} + +void EditorPluginSettings::_cell_button_pressed(Object *p_item, int p_column, int p_id) { + TreeItem *item = Object::cast_to<TreeItem>(p_item); + if (!item) + return; + if (p_id == BUTTON_PLUGIN_EDIT) { + if (p_column == 4) { + String dir = item->get_metadata(0); + plugin_config_dialog->config("res://addons/" + dir + "/plugin.cfg"); + plugin_config_dialog->popup_centered(); + } + } +} + void EditorPluginSettings::_bind_methods() { ClassDB::bind_method("update_plugins", &EditorPluginSettings::update_plugins); + ClassDB::bind_method("_create_clicked", &EditorPluginSettings::_create_clicked); ClassDB::bind_method("_plugin_activity_changed", &EditorPluginSettings::_plugin_activity_changed); + ClassDB::bind_method("_cell_button_pressed", &EditorPluginSettings::_cell_button_pressed); } EditorPluginSettings::EditorPluginSettings() { + plugin_config_dialog = memnew(PluginConfigDialog); + plugin_config_dialog->config(""); + add_child(plugin_config_dialog); + HBoxContainer *title_hb = memnew(HBoxContainer); title_hb->add_child(memnew(Label(TTR("Installed Plugins:")))); title_hb->add_spacer(); + create_plugin = memnew(Button(TTR("Create"))); + create_plugin->connect("pressed", this, "_create_clicked"); + title_hb->add_child(create_plugin); update_list = memnew(Button(TTR("Update"))); update_list->connect("pressed", this, "update_plugins"); title_hb->add_child(update_list); @@ -182,19 +213,22 @@ EditorPluginSettings::EditorPluginSettings() { plugin_list = memnew(Tree); plugin_list->set_v_size_flags(SIZE_EXPAND_FILL); - plugin_list->set_columns(4); + plugin_list->set_columns(5); plugin_list->set_column_titles_visible(true); plugin_list->set_column_title(0, TTR("Name:")); plugin_list->set_column_title(1, TTR("Version:")); plugin_list->set_column_title(2, TTR("Author:")); plugin_list->set_column_title(3, TTR("Status:")); + plugin_list->set_column_title(4, TTR("Edit:")); plugin_list->set_column_expand(0, true); plugin_list->set_column_expand(1, false); plugin_list->set_column_expand(2, false); plugin_list->set_column_expand(3, false); + plugin_list->set_column_expand(4, false); plugin_list->set_column_min_width(1, 100 * EDSCALE); plugin_list->set_column_min_width(2, 250 * EDSCALE); plugin_list->set_column_min_width(3, 80 * EDSCALE); + plugin_list->set_column_min_width(4, 40 * EDSCALE); plugin_list->set_hide_root(true); plugin_list->connect("item_edited", this, "_plugin_activity_changed"); diff --git a/editor/editor_plugin_settings.h b/editor/editor_plugin_settings.h index aacbd05dd4..310cab699f 100644 --- a/editor/editor_plugin_settings.h +++ b/editor/editor_plugin_settings.h @@ -31,6 +31,7 @@ #ifndef EDITORPLUGINSETTINGS_H #define EDITORPLUGINSETTINGS_H +#include "editor/plugin_config_dialog.h"; #include "editor_data.h" #include "property_editor.h" #include "scene/gui/dialogs.h" @@ -40,11 +41,19 @@ class EditorPluginSettings : public VBoxContainer { GDCLASS(EditorPluginSettings, VBoxContainer); + enum { + BUTTON_PLUGIN_EDIT + }; + + PluginConfigDialog *plugin_config_dialog; + Button *create_plugin; Button *update_list; Tree *plugin_list; bool updating; void _plugin_activity_changed(); + void _create_clicked(); + void _cell_button_pressed(Object *p_item, int p_column, int p_id); protected: void _notification(int p_what); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 83a3662f21..0cbd5f0bff 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -46,11 +46,22 @@ EditorPropertyNil::EditorPropertyNil() { } ///////////////////// TEXT ///////////////////////// + +void EditorPropertyText::_text_entered(const String &p_string) { + if (updating) + return; + + if (text->has_focus()) { + text->release_focus(); + _text_changed(p_string); + } +} + void EditorPropertyText::_text_changed(const String &p_string) { if (updating) return; - emit_signal("property_changed", get_edited_property(), p_string, true); + emit_signal("property_changed", get_edited_property(), p_string); } void EditorPropertyText::update_property() { @@ -64,6 +75,7 @@ void EditorPropertyText::update_property() { void EditorPropertyText::_bind_methods() { ClassDB::bind_method(D_METHOD("_text_changed", "txt"), &EditorPropertyText::_text_changed); + ClassDB::bind_method(D_METHOD("_text_entered", "txt"), &EditorPropertyText::_text_entered); } EditorPropertyText::EditorPropertyText() { @@ -71,6 +83,8 @@ EditorPropertyText::EditorPropertyText() { add_child(text); add_focusable(text); text->connect("text_changed", this, "_text_changed"); + text->connect("text_entered", this, "_text_entered"); + updating = false; } @@ -78,12 +92,12 @@ EditorPropertyText::EditorPropertyText() { void EditorPropertyMultilineText::_big_text_changed() { text->set_text(big_text->get_text()); - emit_signal("property_changed", get_edited_property(), big_text->get_text(), true); + emit_signal("property_changed", get_edited_property(), big_text->get_text()); } void EditorPropertyMultilineText::_text_changed() { - emit_signal("property_changed", get_edited_property(), text->get_text(), true); + emit_signal("property_changed", get_edited_property(), text->get_text()); } void EditorPropertyMultilineText::_open_big_text() { @@ -2038,7 +2052,7 @@ void EditorPropertyResource::_menu_option(int p_which) { ERR_BREAK(!resp); if (get_edited_object() && base_type != String() && base_type == "Script") { //make visual script the right type - res->call("set_instance_base_type", get_edited_object()->get_class()); + resp->call("set_instance_base_type", get_edited_object()->get_class()); } res = Ref<Resource>(resp); @@ -2240,7 +2254,7 @@ void EditorPropertyResource::_sub_inspector_object_id_selected(int p_id) { void EditorPropertyResource::_open_editor_pressed() { RES res = get_edited_object()->get(get_edited_property()); if (res.is_valid()) { - EditorNode::get_singleton()->edit_resource(res.ptr()); + EditorNode::get_singleton()->edit_item(res.ptr()); } } diff --git a/editor/editor_properties.h b/editor/editor_properties.h index ccd73d2539..d5fac9c1a0 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -54,6 +54,7 @@ class EditorPropertyText : public EditorProperty { bool updating; void _text_changed(const String &p_string); + void _text_entered(const String &p_string); protected: static void _bind_methods(); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 2bd28170e7..8203c85c6a 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -210,8 +210,8 @@ void EditorPropertyArray::update_property() { default: {} } - if (!array.is_array()) { - edit->set_text(arrtype + "[" + Variant::get_type_name(array.get_type()) + "]"); + if (array.get_type() == Variant::NIL) { + edit->set_text(String("(Nil) ") + arrtype); edit->set_pressed(false); if (vbox) { memdelete(vbox); @@ -219,7 +219,7 @@ void EditorPropertyArray::update_property() { return; } - edit->set_text(arrtype + "[" + itos(array.call("size")) + "]"); + edit->set_text(arrtype + "(size " + itos(array.call("size")) + ")"); #ifdef TOOLS_ENABLED @@ -613,7 +613,13 @@ void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) { void EditorPropertyDictionary::_add_key_value() { + // Do not allow nil as valid key. I experienced errors with this + if (object->get_new_item_key().get_type() == Variant::NIL) { + return; + } + Dictionary dict = object->get_dict(); + dict[object->get_new_item_key()] = object->get_new_item_value(); object->set_new_item_key(Variant()); object->set_new_item_value(Variant()); @@ -663,9 +669,20 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) { void EditorPropertyDictionary::update_property() { - Dictionary dict = get_edited_object()->get(get_edited_property()); + Variant updated_val = get_edited_object()->get(get_edited_property()); + + if (updated_val.get_type() == Variant::NIL) { + edit->set_text("Dictionary (Nil)"); //This provides symmetry with the array property. + edit->set_pressed(false); + if (vbox) { + memdelete(vbox); + } + return; + } + + Dictionary dict = updated_val; - edit->set_text("Dict[" + itos(dict.size()) + "]"); + edit->set_text("Dictionary (size " + itos(dict.size()) + ")"); #ifdef TOOLS_ENABLED @@ -695,9 +712,9 @@ void EditorPropertyDictionary::update_property() { page->set_h_size_flags(SIZE_EXPAND_FILL); page->connect("value_changed", this, "_page_changed"); } else { - //bye bye children of the box - while (vbox->get_child_count() > 1) { - memdelete(vbox->get_child(1)); + // Queue childs for deletion, delete immediately might cause errors. + for (size_t i = 1; i < vbox->get_child_count(); i++) { + vbox->get_child(i)->queue_delete(); } } @@ -941,10 +958,10 @@ void EditorPropertyDictionary::update_property() { prop->update_property(); if (i == amount + 1) { - Button *add_item = memnew(Button); - add_item->set_text(TTR("Add Key/Value Pair")); - add_vbox->add_child(add_item); - add_item->connect("pressed", this, "_add_key_value"); + Button *butt_add_item = memnew(Button); + butt_add_item->set_text(TTR("Add Key/Value Pair")); + butt_add_item->connect("pressed", this, "_add_key_value"); + add_vbox->add_child(butt_add_item); } } @@ -965,8 +982,16 @@ void EditorPropertyDictionary::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { } } + void EditorPropertyDictionary::_edit_pressed() { + Variant prop_val = get_edited_object()->get(get_edited_property()); + if (prop_val.get_type() == Variant::NIL) { + Variant::CallError ce; + prop_val = Variant::construct(Variant::DICTIONARY, NULL, 0, ce); + get_edited_object()->set(get_edited_property(), prop_val); + } + get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); update_property(); } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index a14ced1340..d24816ee02 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -511,6 +511,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("filesystem/file_dialog/thumbnail_size", 64); hints["filesystem/file_dialog/thumbnail_size"] = PropertyInfo(Variant::INT, "filesystem/file_dialog/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16"); + _initial_set("docks/filesystem/disable_split", false); + _initial_set("docks/filesystem/split_mode_minimum_height", 600); _initial_set("docks/filesystem/display_mode", 0); hints["docks/filesystem/display_mode"] = PropertyInfo(Variant::INT, "docks/filesystem/display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List"); _initial_set("docks/filesystem/thumbnail_size", 64); @@ -755,7 +757,7 @@ void EditorSettings::create() { } if (dir->change_dir(data_dir) != OK) { - dir->make_dir(data_dir); + dir->make_dir_recursive(data_dir); if (dir->change_dir(data_dir) != OK) { ERR_PRINT("Cannot create data directory!"); memdelete(dir); @@ -771,14 +773,8 @@ void EditorSettings::create() { // Validate/create cache dir - if (dir->change_dir(cache_path) != OK) { - ERR_PRINT("Cannot find path for cache directory!"); - memdelete(dir); - goto fail; - } - if (dir->change_dir(cache_dir) != OK) { - dir->make_dir(cache_dir); + dir->make_dir_recursive(cache_dir); if (dir->change_dir(cache_dir) != OK) { ERR_PRINT("Cannot create cache directory!"); memdelete(dir); @@ -788,14 +784,8 @@ void EditorSettings::create() { // Validate/create config dir and subdirectories - if (dir->change_dir(config_path) != OK) { - ERR_PRINT("Cannot find path for config directory!"); - memdelete(dir); - goto fail; - } - if (dir->change_dir(config_dir) != OK) { - dir->make_dir(config_dir); + dir->make_dir_recursive(config_dir); if (dir->change_dir(config_dir) != OK) { ERR_PRINT("Cannot create config directory!"); memdelete(dir); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 76fc7fd0cd..69a013dd00 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -173,9 +173,9 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = const Color error_color = p_theme->get_color("error_color", "Editor"); const Color success_color = p_theme->get_color("success_color", "Editor"); const Color warning_color = p_theme->get_color("warning_color", "Editor"); - dark_icon_color_dictionary[Color::html("#ff5d5d")] = error_color; + dark_icon_color_dictionary[Color::html("#ff0000")] = error_color; dark_icon_color_dictionary[Color::html("#45ff8b")] = success_color; - dark_icon_color_dictionary[Color::html("#ffdd65")] = warning_color; + dark_icon_color_dictionary[Color::html("#dbab09")] = warning_color; List<String> exceptions; exceptions.push_back("EditorPivot"); @@ -365,13 +365,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("mono_color", "Editor", mono_color); Color success_color = accent_color.linear_interpolate(Color(0.2, 1, 0.2), 0.6) * 1.2; - Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.2; + Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.0; Color error_color = accent_color.linear_interpolate(Color(1, 0, 0), 0.8) * 1.7; Color property_color = font_color.linear_interpolate(Color(0.5, 0.5, 0.5), 0.5); if (!dark_theme) { // yellow on white themes is a P.I.T.A. - warning_color = accent_color.linear_interpolate(Color(1, 0.8, 0), 0.9); + warning_color = accent_color.linear_interpolate(Color(0.9, 0.7, 0), 0.9); warning_color = warning_color.linear_interpolate(mono_color, 0.2); success_color = success_color.linear_interpolate(mono_color, 0.2); error_color = error_color.linear_interpolate(mono_color, 0.2); diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 931785333f..6c9d1568fa 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -178,7 +178,7 @@ void ExportTemplateManager::_uninstall_template_confirm() { _update_template_list(); } -void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) { +bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) { FileAccess *fa = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&fa); @@ -187,7 +187,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (!pkg) { EditorNode::get_singleton()->show_warning(TTR("Can't open export templates zip.")); - return; + return false; } int ret = unzGoToFirstFile(pkg); @@ -221,7 +221,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (data_str.get_slice_count(".") < 3) { EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside templates: %s."), data_str)); unzClose(pkg); - return; + return false; } version = data_str; @@ -237,7 +237,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (version == String()) { EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside templates.")); unzClose(pkg); - return; + return false; } String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version); @@ -247,7 +247,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (err != OK) { EditorNode::get_singleton()->show_warning(TTR("Error creating path for templates:") + "\n" + template_path); unzClose(pkg); - return; + return false; } memdelete(d); @@ -310,6 +310,8 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ unzClose(pkg); _update_template_list(); + + return true; } void ExportTemplateManager::popup_manager() { @@ -401,7 +403,15 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int String path = download_templates->get_download_file(); template_list_state->set_text(TTR("Download Complete.")); template_downloader->hide(); - _install_from_file(path, false); + int ret = _install_from_file(path, false); + if (ret) { + Error err = OS::get_singleton()->move_to_trash(path); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + path + "\n"); + } + } else { + WARN_PRINTS(vformat(TTR("Templates installation failed. The problematic templates archives can be found at '%s'."), path)); + } } } break; } diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h index 54a645c69f..bd43fe5dc5 100644 --- a/editor/export_template_manager.h +++ b/editor/export_template_manager.h @@ -70,7 +70,7 @@ class ExportTemplateManager : public ConfirmationDialog { void _uninstall_template_confirm(); virtual void ok_pressed(); - void _install_from_file(const String &p_file, bool p_use_progress = true); + bool _install_from_file(const String &p_file, bool p_use_progress = true); void _http_download_mirror_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); void _http_download_templates_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 7b8a7afa87..ec1153a015 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -139,41 +139,56 @@ void FileSystemDock::_update_tree(bool keep_collapse_state, bool p_uncollapse_ro updating_tree = false; } -void FileSystemDock::_notification(int p_what) { +void FileSystemDock::_update_display_mode() { - switch (p_what) { + bool disable_split = bool(EditorSettings::get_singleton()->get("docks/filesystem/disable_split")); + bool compact_mode = get_size().height < int(EditorSettings::get_singleton()->get("docks/filesystem/split_mode_minimum_height")); + DisplayMode new_mode; + if (disable_split || compact_mode) { + new_mode = file_list_view ? DISPLAY_FILE_LIST_ONLY : DISPLAY_TREE_ONLY; + } else { + new_mode = DISPLAY_SPLIT; + } - case NOTIFICATION_RESIZED: { + if (new_mode != display_mode) { + switch (new_mode) { + case DISPLAY_TREE_ONLY: + tree->show(); + tree->set_v_size_flags(SIZE_EXPAND_FILL); + _update_tree(true); - bool new_mode = get_size().height < get_viewport_rect().size.height / 2; + file_list_vb->hide(); + break; - if (new_mode != low_height_mode) { + case DISPLAY_FILE_LIST_ONLY: + tree->hide(); + button_tree->show(); - low_height_mode = new_mode; + file_list_vb->show(); + _update_files(true); + break; - if (low_height_mode) { + case DISPLAY_SPLIT: + tree->show(); + tree->set_v_size_flags(SIZE_EXPAND_FILL); + button_tree->hide(); + tree->ensure_cursor_is_visible(); + _update_tree(true); - tree->hide(); - tree->set_v_size_flags(SIZE_EXPAND_FILL); - button_tree->show(); - } else { + file_list_vb->show(); + _update_files(true); + break; + } + display_mode = new_mode; + } +} - tree->set_v_size_flags(SIZE_FILL); - button_tree->hide(); - if (!tree->is_visible()) { - tree->show(); - button_favorite->show(); - _update_tree(true); - } - tree->ensure_cursor_is_visible(); +void FileSystemDock::_notification(int p_what) { - if (!file_list_vb->is_visible()) { - file_list_vb->show(); - _update_files(true); - } - } - } + switch (p_what) { + case NOTIFICATION_RESIZED: { + _update_display_mode(); } break; case NOTIFICATION_ENTER_TREE: { @@ -190,8 +205,8 @@ void FileSystemDock::_notification(int p_what) { //button_instance->set_icon(get_icon("Add", ei)); //button_open->set_icon(get_icon("Folder", ei)); button_tree->set_icon(get_icon("Filesystem", ei)); - _update_file_display_toggle_button(); - button_display_mode->connect("pressed", this, "_change_file_display"); + _update_file_list_display_mode_button(); + button_file_list_display_mode->connect("pressed", this, "_change_file_display"); //file_options->set_icon( get_icon("Tools","ei")); files->connect("item_activated", this, "_select_file"); button_hist_next->connect("pressed", this, "_fw_history"); @@ -208,6 +223,8 @@ void FileSystemDock::_notification(int p_what) { button_tree->connect("pressed", this, "_go_to_tree", varray(), CONNECT_DEFERRED); current_path->connect("text_entered", this, "navigate_to_path"); + _update_display_mode(); + if (EditorFileSystem::get_singleton()->is_scanning()) { _set_scanning_mode(); } else { @@ -241,12 +258,8 @@ void FileSystemDock::_notification(int p_what) { } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - + // Update icons String ei = "EditorIcons"; - int new_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")); - - //_update_icons - button_reload->set_icon(get_icon("Reload", ei)); button_favorite->set_icon(get_icon("Favorites", ei)); button_tree->set_icon(get_icon("Filesystem", ei)); @@ -256,14 +269,18 @@ void FileSystemDock::_notification(int p_what) { search_box->set_right_icon(get_icon("Search", ei)); search_box->set_clear_button_enabled(true); - if (new_mode != display_mode) { - set_display_mode(new_mode); + // Change size mode + int new_file_list_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")); + if (new_file_list_mode != file_list_display_mode) { + set_file_list_display_mode(new_file_list_mode); } else { - _update_file_display_toggle_button(); + _update_file_list_display_mode_button(); _update_files(true); } - _update_tree(true); + // Change full tree mode + _update_display_mode(); + } break; } } @@ -289,7 +306,7 @@ void FileSystemDock::_dir_selected() { current_path->set_text(path); _push_to_history(); - if (!low_height_mode) { + if (display_mode == DISPLAY_SPLIT) { _update_files(false); } } @@ -360,7 +377,7 @@ void FileSystemDock::navigate_to_path(const String &p_path) { current_path->set_text(path); _push_to_history(); - if (!low_height_mode) { + if (display_mode == DISPLAY_SPLIT) { _update_tree(true); _update_files(false); } else { @@ -390,24 +407,24 @@ void FileSystemDock::_thumbnail_done(const String &p_path, const Ref<Texture> &p } } -void FileSystemDock::_update_file_display_toggle_button() { +void FileSystemDock::_update_file_list_display_mode_button() { - if (button_display_mode->is_pressed()) { - display_mode = DISPLAY_LIST; - button_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons")); - button_display_mode->set_tooltip(TTR("View items as a grid of thumbnails.")); + if (button_file_list_display_mode->is_pressed()) { + file_list_display_mode = FILE_LIST_DISPLAY_LIST; + button_file_list_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons")); + button_file_list_display_mode->set_tooltip(TTR("View items as a grid of thumbnails.")); } else { - display_mode = DISPLAY_THUMBNAILS; - button_display_mode->set_icon(get_icon("FileList", "EditorIcons")); - button_display_mode->set_tooltip(TTR("View items as a list.")); + file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS; + button_file_list_display_mode->set_icon(get_icon("FileList", "EditorIcons")); + button_file_list_display_mode->set_tooltip(TTR("View items as a list.")); } } void FileSystemDock::_change_file_display() { - _update_file_display_toggle_button(); + _update_file_list_display_mode_button(); - EditorSettings::get_singleton()->set("docks/filesystem/display_mode", display_mode); + EditorSettings::get_singleton()->set("docks/filesystem/display_mode", file_list_display_mode); _update_files(true); } @@ -472,8 +489,8 @@ void FileSystemDock::_update_files(bool p_keep_selection) { bool always_show_folders = EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders"); - bool use_thumbnails = (display_mode == DISPLAY_THUMBNAILS); - bool use_folders = search_box->get_text().length() == 0 && (low_height_mode || always_show_folders); + bool use_thumbnails = (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS); + bool use_folders = search_box->get_text().length() == 0 && ((display_mode == DISPLAY_FILE_LIST_ONLY || display_mode == DISPLAY_TREE_ONLY) || always_show_folders); if (use_thumbnails) { @@ -617,24 +634,28 @@ void FileSystemDock::_select_file(int p_idx) { } } -void FileSystemDock::_go_to_tree() { +void FileSystemDock::_go_to_file_list() { - if (low_height_mode) { - tree->show(); - button_favorite->show(); - file_list_vb->hide(); + if (display_mode == DISPLAY_TREE_ONLY) { + file_list_view = true; + _update_display_mode(); + } else { + bool collapsed = tree->get_selected()->is_collapsed(); + tree->get_selected()->set_collapsed(!collapsed); + _update_files(false); } +} +void FileSystemDock::_go_to_tree() { - _update_tree(true); + file_list_view = false; tree->grab_focus(); + _update_display_mode(); tree->ensure_cursor_is_visible(); - //button_open->hide(); - //file_options->hide(); } void FileSystemDock::_preview_invalidated(const String &p_path) { - if (display_mode == DISPLAY_THUMBNAILS && p_path.get_base_dir() == path && search_box->get_text() == String() && file_list_vb->is_visible_in_tree()) { + if (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS && p_path.get_base_dir() == path && search_box->get_text() == String() && file_list_vb->is_visible_in_tree()) { for (int i = 0; i < files->get_item_count(); i++) { @@ -1413,24 +1434,6 @@ void FileSystemDock::_resource_created() const { editor->save_resource_as(current_res, path); } -void FileSystemDock::_go_to_file_list() { - - if (low_height_mode) { - tree->hide(); - file_list_vb->show(); - button_favorite->hide(); - } else { - bool collapsed = tree->get_selected()->is_collapsed(); - tree->get_selected()->set_collapsed(!collapsed); - } - - //file_options->show(); - - _update_files(false); - - //emit_signal("open",path); -} - void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) { folder_options->clear(); folder_options->set_size(Size2(1, 1)); @@ -1450,7 +1453,7 @@ void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) { } folder_options->add_separator(); folder_options->add_item(TTR("New Folder..."), FOLDER_NEW_FOLDER); - folder_options->add_item(TTR("Show In File Manager"), FOLDER_SHOW_IN_EXPLORER); + folder_options->add_item(TTR("Open In File Manager"), FOLDER_SHOW_IN_EXPLORER); } folder_options->set_position(tree->get_global_position() + p_pos); folder_options->popup(); @@ -1474,7 +1477,7 @@ void FileSystemDock::fix_dependencies(const String &p_for_file) { void FileSystemDock::focus_on_filter() { - if (low_height_mode && tree->is_visible()) { + if (display_mode == DISPLAY_FILE_LIST_ONLY && tree->is_visible()) { // Tree mode, switch to files list with search box tree->hide(); file_list_vb->show(); @@ -1484,12 +1487,12 @@ void FileSystemDock::focus_on_filter() { search_box->grab_focus(); } -void FileSystemDock::set_display_mode(int p_mode) { +void FileSystemDock::set_file_list_display_mode(int p_mode) { - if (p_mode == display_mode) + if (p_mode == file_list_display_mode) return; - button_display_mode->set_pressed(p_mode == DISPLAY_LIST); + button_file_list_display_mode->set_pressed(p_mode == FILE_LIST_DISPLAY_LIST); _change_file_display(); } @@ -1759,7 +1762,10 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); - file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER); + + String fpath = files->get_item_metadata(p_item); + String item_text = fpath.ends_with("/") ? TTR("Open In File Manager") : TTR("Show In File Manager"); + file_options->add_item(item_text, FILE_SHOW_IN_EXPLORER); file_options->set_position(files->get_global_position() + p_pos); file_options->popup(); @@ -2027,9 +2033,9 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { search_box->connect("text_changed", this, "_search_changed"); path_hb->add_child(search_box); - button_display_mode = memnew(ToolButton); - button_display_mode->set_toggle_mode(true); - path_hb->add_child(button_display_mode); + button_file_list_display_mode = memnew(ToolButton); + button_file_list_display_mode->set_toggle_mode(true); + path_hb->add_child(button_file_list_display_mode); files = memnew(ItemList); files->set_v_size_flags(SIZE_EXPAND_FILL); @@ -2125,8 +2131,8 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { history_max_size = 20; history.push_back("res://"); - low_height_mode = false; - display_mode = DISPLAY_THUMBNAILS; + display_mode = DISPLAY_SPLIT; + file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS; } FileSystemDock::~FileSystemDock() { diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 6a0c73d52e..fbbe87fc16 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -60,12 +60,18 @@ class FileSystemDock : public VBoxContainer { GDCLASS(FileSystemDock, VBoxContainer); public: - enum DisplayMode { - DISPLAY_THUMBNAILS, - DISPLAY_LIST + enum FileListDisplayMode { + FILE_LIST_DISPLAY_THUMBNAILS, + FILE_LIST_DISPLAY_LIST }; private: + enum DisplayMode { + DISPLAY_TREE_ONLY, + DISPLAY_FILE_LIST_ONLY, + DISPLAY_SPLIT, + }; + enum FileMenu { FILE_OPEN, FILE_INSTANCE, @@ -106,7 +112,7 @@ private: Button *button_reload; Button *button_favorite; Button *button_tree; - Button *button_display_mode; + Button *button_file_list_display_mode; Button *button_hist_next; Button *button_hist_prev; Button *button_show; @@ -115,8 +121,9 @@ private: TextureRect *search_icon; HBoxContainer *path_hb; - bool low_height_mode; + FileListDisplayMode file_list_display_mode; DisplayMode display_mode; + bool file_list_view; PopupMenu *file_options; PopupMenu *folder_options; @@ -172,7 +179,7 @@ private: void _files_gui_input(Ref<InputEvent> p_event); void _update_files(bool p_keep_selection); - void _update_file_display_toggle_button(); + void _update_file_list_display_mode_button(); void _change_file_display(); void _fs_changed(); @@ -245,6 +252,8 @@ private: void _preview_invalidated(const String &p_path); void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata); + void _update_display_mode(); + protected: void _notification(int p_what); static void _bind_methods(); @@ -258,7 +267,7 @@ public: void fix_dependencies(const String &p_for_file); - void set_display_mode(int p_mode); + void set_file_list_display_mode(int p_mode); int get_split_offset() { return split_box->get_split_offset(); } void set_split_offset(int p_offset) { split_box->set_split_offset(p_offset); } diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp new file mode 100644 index 0000000000..418936ac9f --- /dev/null +++ b/editor/plugin_config_dialog.cpp @@ -0,0 +1,230 @@ +/*************************************************************************/ +/* plugin_config_dialog.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "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. */ +/*************************************************************************/ + +#include "plugin_config_dialog.h" +#include "core/io/config_file.h" +#include "core/os/dir_access.h" +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "modules/gdscript/gdscript.h" +#include "scene/gui/grid_container.h" + +void PluginConfigDialog::_clear_fields() { + name_edit->set_text(""); + subfolder_edit->set_text(""); + desc_edit->set_text(""); + author_edit->set_text(""); + version_edit->set_text(""); + script_edit->set_text(""); +} + +void PluginConfigDialog::_on_confirmed() { + + String path = "res://addons/" + subfolder_edit->get_text(); + + if (!_edit_mode) { + DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (!d || d->make_dir_recursive(path) != OK) + return; + } + + Ref<ConfigFile> cf = memnew(ConfigFile); + cf->set_value("plugin", "name", name_edit->get_text()); + cf->set_value("plugin", "description", desc_edit->get_text()); + cf->set_value("plugin", "author", author_edit->get_text()); + cf->set_value("plugin", "version", version_edit->get_text()); + cf->set_value("plugin", "script", script_edit->get_text()); + + cf->save(path.plus_file("plugin.cfg")); + + if (!_edit_mode) { + String type = script_option_edit->get_item_text(script_option_edit->get_selected()); + + Ref<Script> script; + + if (type == GDScriptLanguage::get_singleton()->get_name()) { + Ref<GDScript> gdscript = memnew(GDScript); + gdscript->set_source_code( + "tool\n" + "extends EditorPlugin\n" + "\n" + "func _enter_tree():\n" + "\tpass"); + String script_path = path.plus_file(script_edit->get_text()); + gdscript->set_path(script_path); + ResourceSaver::save(script_path, gdscript); + script = gdscript; + } + //TODO: other languages + + emit_signal("plugin_ready", script.operator->(), active_edit->is_pressed() ? name_edit->get_text() : ""); + } else { + EditorNode::get_singleton()->get_project_settings()->update_plugins(); + } + _clear_fields(); +} + +void PluginConfigDialog::_on_cancelled() { + _clear_fields(); +} + +void PluginConfigDialog::_on_required_text_changed(const String &p_text) { + String ext = script_option_edit->get_item_metadata(script_option_edit->get_selected()); + get_ok()->set_disabled(script_edit->get_text().get_basename().empty() || script_edit->get_text().get_extension() != ext || name_edit->get_text().empty()); +} + +void PluginConfigDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + connect("confirmed", this, "_on_confirmed"); + get_cancel()->connect("pressed", this, "_on_cancelled"); + } break; + } +} + +void PluginConfigDialog::config(const String &p_config_path) { + if (p_config_path.length()) { + Ref<ConfigFile> cf = memnew(ConfigFile); + print_line(p_config_path); + cf->load(p_config_path); + + name_edit->set_text(cf->get_value("plugin", "name", "")); + subfolder_edit->set_text(p_config_path.get_base_dir().get_basename().get_file()); + desc_edit->set_text(cf->get_value("plugin", "description", "")); + author_edit->set_text(cf->get_value("plugin", "author", "")); + version_edit->set_text(cf->get_value("plugin", "version", "")); + script_edit->set_text(cf->get_value("plugin", "script", "")); + + _edit_mode = true; + active_edit->hide(); + Object::cast_to<Label>(active_edit->get_parent()->get_child(active_edit->get_index() - 1))->hide(); + subfolder_edit->hide(); + Object::cast_to<Label>(subfolder_edit->get_parent()->get_child(subfolder_edit->get_index() - 1))->hide(); + set_title(TTR("Edit a Plugin")); + } else { + _clear_fields(); + _edit_mode = false; + active_edit->show(); + Object::cast_to<Label>(active_edit->get_parent()->get_child(active_edit->get_index() - 1))->show(); + subfolder_edit->show(); + Object::cast_to<Label>(subfolder_edit->get_parent()->get_child(subfolder_edit->get_index() - 1))->show(); + set_title(TTR("Create a Plugin")); + } + get_ok()->set_disabled(!_edit_mode); + get_ok()->set_text(_edit_mode ? TTR("Update") : TTR("Create")); +} + +void PluginConfigDialog::_bind_methods() { + ClassDB::bind_method("_on_required_text_changed", &PluginConfigDialog::_on_required_text_changed); + ClassDB::bind_method("_on_confirmed", &PluginConfigDialog::_on_confirmed); + ClassDB::bind_method("_on_cancelled", &PluginConfigDialog::_on_cancelled); + ADD_SIGNAL(MethodInfo("plugin_ready", PropertyInfo(Variant::STRING, "script_path", PROPERTY_HINT_NONE, ""), PropertyInfo(Variant::STRING, "activate_name"))); +} + +PluginConfigDialog::PluginConfigDialog() { + get_ok()->set_disabled(true); + set_hide_on_ok(true); + + GridContainer *grid = memnew(GridContainer); + grid->set_columns(2); + add_child(grid); + + Label *name_lb = memnew(Label); + name_lb->set_text(TTR("Plugin Name:")); + grid->add_child(name_lb); + + name_edit = memnew(LineEdit); + name_edit->connect("text_changed", this, "_on_required_text_changed"); + name_edit->set_placeholder("MyPlugin"); + grid->add_child(name_edit); + + Label *subfolder_lb = memnew(Label); + subfolder_lb->set_text(TTR("Subfolder:")); + grid->add_child(subfolder_lb); + + subfolder_edit = memnew(LineEdit); + subfolder_edit->set_placeholder("\"my_plugin\" -> res://addons/my_plugin"); + grid->add_child(subfolder_edit); + + Label *desc_lb = memnew(Label); + desc_lb->set_text(TTR("Description:")); + grid->add_child(desc_lb); + + desc_edit = memnew(TextEdit); + desc_edit->set_custom_minimum_size(Size2(400.0f, 50.0f)); + grid->add_child(desc_edit); + + Label *author_lb = memnew(Label); + author_lb->set_text(TTR("Author:")); + grid->add_child(author_lb); + + author_edit = memnew(LineEdit); + author_edit->set_placeholder("Godette"); + grid->add_child(author_edit); + + Label *version_lb = memnew(Label); + version_lb->set_text(TTR("Version:")); + grid->add_child(version_lb); + + version_edit = memnew(LineEdit); + version_edit->set_placeholder("1.0"); + grid->add_child(version_edit); + + Label *script_option_lb = memnew(Label); + script_option_lb->set_text(TTR("Language:")); + grid->add_child(script_option_lb); + + script_option_edit = memnew(OptionButton); + script_option_edit->add_item(GDScriptLanguage::get_singleton()->get_name()); + script_option_edit->set_item_metadata(0, GDScriptLanguage::get_singleton()->get_extension()); + script_option_edit->select(0); + //TODO: add other languages + grid->add_child(script_option_edit); + + Label *script_lb = memnew(Label); + script_lb->set_text(TTR("Script Name:")); + grid->add_child(script_lb); + + script_edit = memnew(LineEdit); + script_edit->connect("text_changed", this, "_on_required_text_changed"); + script_edit->set_placeholder("\"plugin.gd\" -> res://addons/my_plugin/plugin.gd"); + grid->add_child(script_edit); + + Label *active_lb = memnew(Label); + active_lb->set_text(TTR("Activate now?")); + grid->add_child(active_lb); + + active_edit = memnew(CheckBox); + active_edit->set_pressed(true); + grid->add_child(active_edit); +} + +PluginConfigDialog::~PluginConfigDialog() { +} diff --git a/platform/haiku/power_haiku.h b/editor/plugin_config_dialog.h index 2fe85cd23d..2d321a479d 100644 --- a/platform/haiku/power_haiku.h +++ b/editor/plugin_config_dialog.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* power_haiku.h */ +/* plugin_config_dialog.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,26 +28,44 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PLATFORM_HAIKU_POWER_HAIKU_H_ -#define PLATFORM_HAIKU_POWER_HAIKU_H_ +#ifndef PLUGIN_CONFIG_DIALOG_H +#define PLUGIN_CONFIG_DIALOG_H -#include <os/os.h> +#include "scene/gui/check_box.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/option_button.h" +#include "scene/gui/text_edit.h" -class PowerHaiku { -private: - int nsecs_left; - int percent_left; - OS::PowerState power_state; +class PluginConfigDialog : public ConfirmationDialog { - bool UpdatePowerInfo(); + GDCLASS(PluginConfigDialog, ConfirmationDialog); + + LineEdit *name_edit; + LineEdit *subfolder_edit; + TextEdit *desc_edit; + LineEdit *author_edit; + LineEdit *version_edit; + OptionButton *script_option_edit; + LineEdit *script_edit; + CheckBox *active_edit; + + bool _edit_mode; + + void _clear_fields(); + void _on_confirmed(); + void _on_cancelled(); + void _on_required_text_changed(const String &p_text); + +protected: + virtual void _notification(int p_what); + static void _bind_methods(); public: - PowerHaiku(); - virtual ~PowerHaiku(); + void config(const String &p_plugin_dir_name); - OS::PowerState get_power_state(); - int get_power_seconds_left(); - int get_power_percent_left(); + PluginConfigDialog(); + ~PluginConfigDialog(); }; -#endif /* PLATFORM_HAIKU_POWER_HAIKU_H_ */ +#endif // PLUGIN_CONFIG_DIALOG_H diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index ddd84aa563..4ed2b051aa 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -384,14 +384,11 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int return; } - progress->set_max(download->get_body_size()); - progress->set_value(download->get_downloaded_bytes()); - install->set_disabled(false); + status->set_text(TTR("Success!")); + // Make the progress bar invisible but don't reflow other Controls around it + progress->set_modulate(Color(0, 0, 0, 0)); - progress->set_value(download->get_downloaded_bytes()); - - status->set_text(TTR("Success!") + " (" + String::humanize_size(download->get_downloaded_bytes()) + ")"); set_process(false); } @@ -413,25 +410,37 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { - progress->set_max(download->get_body_size()); - progress->set_value(download->get_downloaded_bytes()); + // Make the progress bar visible again when retrying the download + progress->set_modulate(Color(1, 1, 1, 1)); + + if (download->get_downloaded_bytes() > 0) { + progress->set_max(download->get_body_size()); + progress->set_value(download->get_downloaded_bytes()); + } int cstatus = download->get_http_client_status(); - if (cstatus == HTTPClient::STATUS_BODY) - status->set_text(TTR("Fetching:") + " " + String::humanize_size(download->get_downloaded_bytes())); + if (cstatus == HTTPClient::STATUS_BODY) { + status->set_text(vformat(TTR("Downloading (%s / %s)..."), String::humanize_size(download->get_downloaded_bytes()), String::humanize_size(download->get_body_size()))); + } if (cstatus != prev_status) { switch (cstatus) { case HTTPClient::STATUS_RESOLVING: { status->set_text(TTR("Resolving...")); + progress->set_max(1); + progress->set_value(0); } break; case HTTPClient::STATUS_CONNECTING: { status->set_text(TTR("Connecting...")); + progress->set_max(1); + progress->set_value(0); } break; case HTTPClient::STATUS_REQUESTING: { status->set_text(TTR("Requesting...")); + progress->set_max(1); + progress->set_value(0); } break; default: {} } @@ -527,7 +536,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { hb2->add_child(retry); hb2->add_child(install); - set_custom_minimum_size(Size2(250, 0)); + set_custom_minimum_size(Size2(310, 0)); download = memnew(HTTPRequest); add_child(download); diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index c2b17189ef..b50e0dfe88 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -68,6 +68,11 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) { switch (p_idx) { case MENU_GENERATE_VISIBILITY_RECT: { + float gen_time = particles->get_lifetime(); + if (gen_time < 1.0) + generate_seconds->set_value(1.0); + else + generate_seconds->set_value(trunc(gen_time) + 1.0); generate_aabb->popup_centered_minsize(); } break; case MENU_LOAD_EMISSION_MASK: { @@ -90,6 +95,12 @@ void Particles2DEditorPlugin::_generate_visibility_rect() { EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time)); + bool was_emitting = particles->is_emitting(); + if (!was_emitting) { + particles->set_emitting(true); + OS::get_singleton()->delay_usec(1000); + } + Rect2 rect; while (running < time) { @@ -106,6 +117,10 @@ void Particles2DEditorPlugin::_generate_visibility_rect() { running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0; } + if (!was_emitting) { + particles->set_emitting(false); + } + particles->set_visibility_rect(rect); } diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index 1f5a4a8a36..6a99dcb9a5 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -270,6 +270,12 @@ void ParticlesEditor::_menu_option(int p_option) { switch (p_option) { case MENU_OPTION_GENERATE_AABB: { + float gen_time = node->get_lifetime(); + + if (gen_time < 1.0) + generate_seconds->set_value(1.0); + else + generate_seconds->set_value(trunc(gen_time) + 1.0); generate_aabb->popup_centered_minsize(); } break; case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: { @@ -323,7 +329,14 @@ void ParticlesEditor::_generate_aabb() { EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time)); + bool was_emitting = node->is_emitting(); + if (!was_emitting) { + node->set_emitting(true); + OS::get_singleton()->delay_usec(1000); + } + AABB rect; + while (running < time) { uint64_t ticks = OS::get_singleton()->get_ticks_usec(); @@ -339,6 +352,10 @@ void ParticlesEditor::_generate_aabb() { running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0; } + if (!was_emitting) { + node->set_emitting(false); + } + node->set_visibility_aabb(rect); } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 7d72537e32..1bb7c98114 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -842,6 +842,19 @@ bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) { void ScriptEditor::_file_dialog_action(String p_file) { switch (file_dialog_option) { + case FILE_NEW_TEXTFILE: { + Error err; + FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); + if (err) { + memdelete(file); + editor->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!")); + break; + } + file->close(); + memdelete(file); + + // fallthrough to open the file. + } case FILE_OPEN: { List<String> extensions; @@ -870,7 +883,7 @@ void ScriptEditor::_file_dialog_action(String p_file) { file_dialog_option = -1; return; } - } + } break; case FILE_SAVE_AS: { ScriptEditorBase *current = _get_current_editor(); @@ -929,6 +942,15 @@ void ScriptEditor::_menu_option(int p_option) { script_create_dialog->config("Node", ".gd"); script_create_dialog->popup_centered(Size2(300, 300) * EDSCALE); } break; + case FILE_NEW_TEXTFILE: { + file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + file_dialog_option = FILE_NEW_TEXTFILE; + + file_dialog->clear_filters(); + file_dialog->popup_centered_ratio(); + file_dialog->set_title(TTR("New TextFile...")); + } break; case FILE_OPEN: { file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); @@ -1937,7 +1959,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra if (!se) continue; - if (se->get_edited_resource() == p_resource) { + if ((script != NULL && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) { if (should_open) { if (tab_container->get_current_tab() != i) { @@ -2387,9 +2409,23 @@ void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) { void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) { Ref<InputEventMouseButton> mb = ev; - if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { + if (mb.is_valid() && mb->is_pressed()) { + switch (mb->get_button_index()) { + + case BUTTON_MIDDLE: { + // Right-click selects automatically; middle-click does not. + int idx = script_list->get_item_at_position(mb->get_position(), true); + if (idx >= 0) { + script_list->select(idx); + _script_selected(idx); + _menu_option(FILE_CLOSE); + } + } break; - _make_script_list_context_menu(); + case BUTTON_RIGHT: { + _make_script_list_context_menu(); + } break; + } } } @@ -2960,7 +2996,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { menu_hb->add_child(file_menu); file_menu->set_text(TTR("File")); file_menu->get_popup()->set_hide_on_window_lose_focus(true); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New")), FILE_NEW); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New Script")), FILE_NEW); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New TextFile")), FILE_NEW_TEXTFILE); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open")), FILE_OPEN); file_menu->get_popup()->add_submenu_item(TTR("Open Recent"), "RecentScripts", FILE_OPEN_RECENT); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 186c80a5f9..737f17358b 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -130,6 +130,7 @@ class ScriptEditor : public PanelContainer { EditorNode *editor; enum { FILE_NEW, + FILE_NEW_TEXTFILE, FILE_OPEN, FILE_OPEN_RECENT, FILE_SAVE, diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 40d6b67426..9782b9d1f4 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2081,6 +2081,15 @@ void SpatialEditorViewport::set_message(String p_message, float p_time) { message_time = p_time; } +void SpatialEditorPlugin::edited_scene_changed() { + for (int i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) { + SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(i); + if (viewport->is_visible()) { + viewport->notification(Control::NOTIFICATION_VISIBILITY_CHANGED); + } + } +} + void SpatialEditorViewport::_notification(int p_what) { if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { @@ -2824,7 +2833,7 @@ void SpatialEditorViewport::update_transform_gizmo_view() { dd = 0.0001; float gsize = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size"); - gizmo_scale = (gsize / Math::abs(dd)); + gizmo_scale = (gsize / Math::abs(dd)) * MAX(1, EDSCALE) / viewport_container->get_stretch_shrink(); Vector3 scale = Vector3(1, 1, 1) * gizmo_scale; xform.basis.scale(scale); @@ -3346,7 +3355,7 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p if (root_node) { list.push_back(root_node); } else { - accept->get_ok()->set_text(TTR("OK :(")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("No parent to instance a child at.")); accept->popup_centered_minsize(); _remove_preview(); @@ -3386,6 +3395,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed clicked = 0; clicked_includes_current = false; orthogonal = false; + lock_rotation = false; message_time = 0; zoom_indicator_delay = 0.0; @@ -4517,9 +4527,9 @@ void SpatialEditor::_init_indicators() { nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE), }; - int arrow_sides = 6; + int arrow_sides = 16; - for (int k = 0; k < 6; k++) { + for (int k = 0; k < arrow_sides; k++) { Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides); Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides); @@ -4603,10 +4613,10 @@ void SpatialEditor::_init_indicators() { ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE, }; - for (int k = 0; k < 32; k++) { + for (int k = 0; k < 64; k++) { - Basis ma(ivec, Math_PI * 2 * float(k) / 32); - Basis mb(ivec, Math_PI * 2 * float(k + 1) / 32); + Basis ma(ivec, Math_PI * 2 * float(k) / 64); + Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64); for (int j = 0; j < 4; j++) { diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 0ebc11e5df..4057145c2f 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -741,6 +741,8 @@ public: virtual void set_state(const Dictionary &p_state); virtual void clear() { spatial_editor->clear(); } + virtual void edited_scene_changed(); + SpatialEditorPlugin(EditorNode *p_node); ~SpatialEditorPlugin(); }; diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 0419c3d4b1..d13e01dc1e 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -603,7 +603,6 @@ void TextureRegionEditor::_notification(int p_what) { zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons")); zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons")); - icon_zoom->set_texture(get_icon("Zoom", "EditorIcons")); } break; } } @@ -865,7 +864,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { hb_grid->add_child(sb_step_y); hb_grid->add_child(memnew(VSeparator)); - hb_grid->add_child(memnew(Label(TTR("Separation:")))); + hb_grid->add_child(memnew(Label(TTR("Sep.:")))); sb_sep_x = memnew(SpinBox); sb_sep_x->set_min(0); @@ -898,10 +897,6 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { separator->set_h_size_flags(Control::SIZE_EXPAND_FILL); hb_tools->add_child(separator); - icon_zoom = memnew(TextureRect); - icon_zoom->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); - hb_tools->add_child(icon_zoom); - zoom_out = memnew(ToolButton); zoom_out->connect("pressed", this, "_zoom_out"); hb_tools->add_child(zoom_out); @@ -940,16 +935,15 @@ bool TextureRegionEditorPlugin::handles(Object *p_object) const { void TextureRegionEditorPlugin::make_visible(bool p_visible) { if (p_visible) { texture_region_button->show(); - if (region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region())) { + if (region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region()) || texture_region_button->is_pressed()) { editor->make_bottom_panel_item_visible(region_editor); - } else { - if (texture_region_button->is_pressed()) - region_editor->show(); } } else { + if (region_editor->is_visible_in_tree()) { + editor->hide_bottom_panel(); + } texture_region_button->hide(); region_editor->edit(NULL); - region_editor->hide(); } } @@ -1001,10 +995,9 @@ TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) { editor = p_node; region_editor = memnew(TextureRegionEditor(p_node)); - texture_region_button = p_node->add_bottom_panel_item(TTR("TextureRegion"), region_editor); - texture_region_button->set_tooltip(TTR("Texture Region Editor")); - region_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); region_editor->hide(); + + texture_region_button = p_node->add_bottom_panel_item(TTR("TextureRegion"), region_editor); texture_region_button->hide(); } diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index bd93be9267..670cc86bbb 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -56,7 +56,6 @@ class TextureRegionEditor : public Control { friend class TextureRegionEditorPlugin; MenuButton *snap_mode_button; - TextureRect *icon_zoom; ToolButton *zoom_in; ToolButton *zoom_reset; ToolButton *zoom_out; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 101dc3037f..3d14db7d0e 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -533,10 +533,9 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era return PoolVector<Vector2>(); } - for (int i = ids.size() - 1; i >= 0; i--) { - if (ids[i] == prev_id) { - return PoolVector<Vector2>(); - } + if (ids.size() == 1 && ids[0] == prev_id) { + // Same ID, nothing to change + return PoolVector<Vector2>(); } Rect2i r = node->get_used_rect(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 8d1db5de8f..490ebeca26 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -307,6 +307,11 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", p); tool_hb->add_child(tool_workspacemode[i]); } + Control *spacer = memnew(Control); + spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL); + tool_hb->add_child(spacer); + tool_hb->move_child(spacer, (int)WORKSPACE_CREATE_SINGLE); + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); workspace_mode = WORKSPACE_EDIT; @@ -314,9 +319,6 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { main_vb->add_child(memnew(HSeparator)); tool_hb = memnew(HBoxContainer); - Control *spacer = memnew(Control); - spacer->set_custom_minimum_size(Size2(30, 0)); - tool_hb->add_child(spacer); g = Ref<ButtonGroup>(memnew(ButtonGroup)); String label[EDITMODE_MAX] = { "Region", "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" }; @@ -335,7 +337,8 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { edit_mode = EDITMODE_COLLISION; main_vb->add_child(tool_hb); - main_vb->add_child(memnew(HSeparator)); + separator_editmode = memnew(HSeparator); + main_vb->add_child(separator_editmode); toolbar = memnew(HBoxContainer); Ref<ButtonGroup> tg(memnew(ButtonGroup)); @@ -369,13 +372,17 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { toolbar->add_child(tools[SHAPE_NEW_POLYGON]); tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true); tools[SHAPE_NEW_POLYGON]->set_button_group(tg); - toolbar->add_child(memnew(VSeparator)); + + separator_delete = memnew(VSeparator); + toolbar->add_child(separator_delete); tools[SHAPE_DELETE] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)SHAPE_DELETE); tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", p); toolbar->add_child(tools[SHAPE_DELETE]); - toolbar->add_child(memnew(VSeparator)); + + separator_grid = memnew(VSeparator); + toolbar->add_child(separator_grid); tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton); tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true); tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true); @@ -588,10 +595,16 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { tools[BITMASK_PASTE]->hide(); tools[BITMASK_CLEAR]->hide(); tools[SHAPE_NEW_POLYGON]->hide(); - if (workspace_mode == WORKSPACE_EDIT) + + if (workspace_mode == WORKSPACE_EDIT) { + separator_delete->show(); tools[SHAPE_DELETE]->show(); - else + } else { + separator_delete->hide(); tools[SHAPE_DELETE]->hide(); + } + + separator_grid->show(); tools[SHAPE_KEEP_INSIDE_TILE]->hide(); tools[TOOL_GRID_SNAP]->show(); @@ -605,7 +618,11 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { tools[BITMASK_PASTE]->show(); tools[BITMASK_CLEAR]->show(); tools[SHAPE_NEW_POLYGON]->hide(); + + separator_delete->hide(); tools[SHAPE_DELETE]->hide(); + + separator_grid->hide(); tools[SHAPE_KEEP_INSIDE_TILE]->hide(); tools[TOOL_GRID_SNAP]->hide(); @@ -621,7 +638,11 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { tools[BITMASK_PASTE]->hide(); tools[BITMASK_CLEAR]->hide(); tools[SHAPE_NEW_POLYGON]->show(); + + separator_delete->show(); tools[SHAPE_DELETE]->show(); + + separator_grid->show(); tools[SHAPE_KEEP_INSIDE_TILE]->show(); tools[TOOL_GRID_SNAP]->show(); @@ -635,9 +656,14 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { tools[BITMASK_PASTE]->hide(); tools[BITMASK_CLEAR]->hide(); tools[SHAPE_NEW_POLYGON]->hide(); + + separator_delete->hide(); tools[SHAPE_DELETE]->hide(); + + separator_grid->show(); tools[SHAPE_KEEP_INSIDE_TILE]->hide(); tools[TOOL_GRID_SNAP]->show(); + if (edit_mode == EDITMODE_ICON) { tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.\nClick on another Tile to edit it.")); spin_priority->hide(); @@ -661,6 +687,7 @@ void TileSetEditor::_on_workspace_mode_changed(int p_workspace_mode) { tool_editmode[EDITMODE_REGION]->show(); tool_editmode[EDITMODE_REGION]->set_pressed(true); _on_edit_mode_changed(EDITMODE_REGION); + separator_editmode->show(); } } @@ -2076,6 +2103,7 @@ void TileSetEditor::update_workspace_tile_mode() { tool_editmode[EDITMODE_REGION]->show(); tool_editmode[EDITMODE_REGION]->set_pressed(true); _on_edit_mode_changed(EDITMODE_REGION); + separator_editmode->show(); return; } @@ -2086,12 +2114,16 @@ void TileSetEditor::update_workspace_tile_mode() { for (int i = 0; i < ZOOM_OUT; i++) { tools[i]->hide(); } + separator_editmode->hide(); + separator_delete->hide(); + separator_grid->hide(); return; } for (int i = 0; i < EDITMODE_MAX; i++) { tool_editmode[i]->show(); } + separator_editmode->show(); if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { if (tool_editmode[EDITMODE_ICON]->is_pressed() || tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) { @@ -2336,12 +2368,10 @@ bool TileSetEditorPlugin::handles(Object *p_node) const { void TileSetEditorPlugin::make_visible(bool p_visible) { if (p_visible) { tileset_editor_button->show(); - if (tileset_editor_button->is_pressed()) { - tileset_editor->show(); - } + editor->make_bottom_panel_item_visible(tileset_editor); get_tree()->connect("idle_frame", tileset_editor, "_on_workspace_process"); } else { - tileset_editor->hide(); + editor->hide_bottom_panel(); tileset_editor_button->hide(); get_tree()->disconnect("idle_frame", tileset_editor, "_on_workspace_process"); } diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 0c175e718c..23bf68b90f 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -40,12 +40,12 @@ #define WORKSPACE_MARGIN Vector2(10, 10) class TilesetEditorContext; -class TileSetEditor : public Panel { +class TileSetEditor : public Control { friend class TileSetEditorPlugin; friend class TilesetEditorContext; - GDCLASS(TileSetEditor, Panel) + GDCLASS(TileSetEditor, Control) enum TextureToolButtons { TOOL_TILESET_ADD_TEXTURE, @@ -131,8 +131,11 @@ class TileSetEditor : public Panel { Control *workspace; Button *tool_workspacemode[WORKSPACE_MODE_MAX]; Button *tool_editmode[EDITMODE_MAX]; + HSeparator *separator_editmode; HBoxContainer *toolbar; ToolButton *tools[TOOL_MAX]; + VSeparator *separator_delete; + VSeparator *separator_grid; SpinBox *spin_priority; WorkspaceMode workspace_mode; EditMode edit_mode; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 9218fed907..63e89b78ea 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -119,6 +119,9 @@ void VisualShaderEditor::_update_graph() { if (updating) return; + if (visual_shader.is_null()) + return; + graph->set_scroll_ofs(visual_shader->get_graph_offset() * EDSCALE); VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 170546f14c..3cebbb5d21 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -231,7 +231,7 @@ void ProjectExportDialog::_edit_preset(int p_index) { if (error != String()) { - Vector<String> items = error.split("\n"); + Vector<String> items = error.split("\n", false); error = ""; for (int i = 0; i < items.size(); i++) { if (i > 0) @@ -756,7 +756,7 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) { Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0); if (err != OK) { - error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted: ") + platform->get_name()); + error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " " + platform->get_name()); error_dialog->show(); error_dialog->popup_centered_minsize(Size2(300, 80)); ERR_PRINT("Failed to export project"); @@ -956,7 +956,7 @@ ProjectExportDialog::ProjectExportDialog() { export_error = memnew(Label); main_vb->add_child(export_error); export_error->hide(); - export_error->add_color_override("font_color", get_color("error_color", "Editor")); + export_error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); export_templates_error = memnew(HBoxContainer); main_vb->add_child(export_templates_error); @@ -964,7 +964,7 @@ ProjectExportDialog::ProjectExportDialog() { Label *export_error2 = memnew(Label); export_templates_error->add_child(export_error2); - export_error2->add_color_override("font_color", get_color("error_color", "Editor")); + export_error2->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " "); error_dialog = memnew(AcceptDialog); @@ -975,6 +975,7 @@ ProjectExportDialog::ProjectExportDialog() { LinkButton *download_templates = memnew(LinkButton); download_templates->set_text(TTR("Manage Export Templates")); + download_templates->set_v_size_flags(SIZE_SHRINK_CENTER); export_templates_error->add_child(download_templates); download_templates->connect("pressed", this, "_open_export_template_manager"); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 6af7779575..aad9258ed9 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -915,12 +915,6 @@ void ProjectManager::_update_project_buttons() { CanvasItem *item = Object::cast_to<CanvasItem>(scroll_children->get_child(i)); item->update(); - - Button *show = Object::cast_to<Button>(item->get_node(NodePath("project/path_box/show"))); - if (show) { - String current = item->get_meta("name"); - show->set_visible(selected_list.has(current)); - } } bool empty_selection = selected_list.empty(); @@ -1316,7 +1310,6 @@ void ProjectManager::_load_recent_projects() { path_hb->add_child(show); show->connect("pressed", this, "_show_project", varray(path)); show->set_tooltip(TTR("Show In File Manager")); - show->set_visible(false); Label *fpath = memnew(Label(path)); fpath->set_name("path"); @@ -1757,6 +1750,8 @@ ProjectManager::ProjectManager() { editor_set_scale(custom_display_scale); } break; } + + OS::get_singleton()->set_window_size(OS::get_singleton()->get_window_size() * MAX(1, EDSCALE)); } FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); @@ -1824,7 +1819,7 @@ ProjectManager::ProjectManager() { project_filter = memnew(ProjectListFilter); search_box->add_child(project_filter); project_filter->connect("filter_changed", this, "_load_recent_projects"); - project_filter->set_custom_minimum_size(Size2(250, 10)); + project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE); search_tree_vb->add_child(search_box); PanelContainer *pc = memnew(PanelContainer); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index d52538f67b..970302e058 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -215,10 +215,8 @@ void ProjectSettingsEditor::_action_edited() { undo_redo->create_action(TTR("Change Action deadzone")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, new_action); - undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_action); - undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_settings_changed"); undo_redo->commit_action(); } @@ -808,6 +806,10 @@ void ProjectSettingsEditor::popup_project_settings() { plugin_settings->update_plugins(); } +void ProjectSettingsEditor::update_plugins() { + plugin_settings->update_plugins(); +} + void ProjectSettingsEditor::_item_selected(const String &p_path) { String selected_path = p_path; diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index b738c4ae20..1344da1de7 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -186,6 +186,7 @@ public: static ProjectSettingsEditor *get_singleton() { return singleton; } void popup_project_settings(); void set_plugins_page(); + void update_plugins(); EditorAutoloadSettings *get_autoload_settings() { return autoload_settings; } diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index b370a711e3..408e67149a 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -287,7 +287,11 @@ void CustomPropertyEditor::_menu_option(int p_which) { Object *obj = ClassDB::instance(intype); if (!obj) { - obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource"); + if (ScriptServer::is_global_class(intype)) { + obj = EditorNode::get_editor_data().script_class_instance(intype); + } else { + obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource"); + } } ERR_BREAK(!obj); @@ -1132,7 +1136,11 @@ void CustomPropertyEditor::_type_create_selected(int p_idx) { Object *obj = ClassDB::instance(intype); if (!obj) { - obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource"); + if (ScriptServer::is_global_class(intype)) { + obj = EditorNode::get_editor_data().script_class_instance(intype); + } else { + obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource"); + } } ERR_FAIL_COND(!obj); @@ -1334,7 +1342,11 @@ void CustomPropertyEditor::_action_pressed(int p_which) { Object *obj = ClassDB::instance(intype); if (!obj) { - obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource"); + if (ScriptServer::is_global_class(intype)) { + obj = EditorNode::get_editor_data().script_class_instance(intype); + } else { + obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource"); + } } ERR_BREAK(!obj); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index e1bb622ea4..607d974025 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -119,7 +119,7 @@ void SceneTreeDock::instance(const String &p_file) { if (!edited_scene) { current_option = -1; - accept->get_ok()->set_text(TTR("OK :(")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("No parent to instance a child at.")); accept->popup_centered_minsize(); return; @@ -365,10 +365,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { ScriptLanguage *l = ScriptServer::get_language(i); if (l->get_type() == existing->get_class()) { - if (EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) { - String name = l->get_global_class_name(existing->get_path(), NULL); - inherits = editor->get_editor_data().script_class_get_base(name); - } else if (l->can_inherit_from_file()) { + String name = l->get_global_class_name(existing->get_path()); + if (ScriptServer::is_global_class(name)) { + if (EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) { + inherits = editor->get_editor_data().script_class_get_base(name); + } else if (l->can_inherit_from_file()) { + inherits = "\"" + existing->get_path() + "\""; + } + } else { inherits = "\"" + existing->get_path() + "\""; } } @@ -395,6 +399,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { const RefPtr empty; editor_data->get_undo_redo().add_do_method(E->get(), "set_script", empty); editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing); + + editor_data->get_undo_redo().add_do_method(E->get(), "set_meta", "_editor_icon", get_icon(E->get()->get_class(), "EditorIcons")); + editor_data->get_undo_redo().add_undo_method(E->get(), "set_meta", "_editor_icon", E->get()->get_meta("_editor_icon")); } } @@ -402,7 +409,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); editor_data->get_undo_redo().commit_action(); - } break; case TOOL_MOVE_UP: case TOOL_MOVE_DOWN: { @@ -797,18 +803,38 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } break; case TOOL_CREATE_2D_SCENE: case TOOL_CREATE_3D_SCENE: - case TOOL_CREATE_USER_INTERFACE: { + case TOOL_CREATE_USER_INTERFACE: + case TOOL_CREATE_FAVORITE: { Node *new_node; - switch (p_tool) { - case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break; - case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break; - case TOOL_CREATE_USER_INTERFACE: { - Control *node = memnew(Control); - node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs. - new_node = node; - } break; + if (TOOL_CREATE_FAVORITE == p_tool) { + String name = selected_favorite_root.get_slicec(' ', 0); + if (ScriptServer::is_global_class(name)) { + new_node = Object::cast_to<Node>(ClassDB::instance(ScriptServer::get_global_class_base(name))); + Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script"); + if (new_node && script.is_valid()) { + new_node->set_script(script.get_ref_ptr()); + new_node->set_name(name); + } + } else { + new_node = Object::cast_to<Node>(ClassDB::instance(selected_favorite_root)); + } + if (!new_node) { + ERR_EXPLAIN("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead."); + new_node = memnew(Node); + } + } else { + switch (p_tool) { + case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break; + case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break; + case TOOL_CREATE_USER_INTERFACE: { + Control *node = memnew(Control); + node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs. + new_node = node; + + } break; + } } editor_data->get_undo_redo().create_action("New Scene Root"); @@ -867,35 +893,62 @@ void SceneTreeDock::_notification(int p_what) { EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed"); - create_root_dialog->add_child(memnew(Label(TTR("Create Root Node:")))); + // create_root_dialog + HBoxContainer *top_row = memnew(HBoxContainer); + top_row->set_name("NodeShortcutsTopRow"); + top_row->set_h_size_flags(SIZE_EXPAND_FILL); + top_row->add_child(memnew(Label(TTR("Create Root Node:")))); + top_row->add_spacer(); - Button *button_2d = memnew(Button); - create_root_dialog->add_child(button_2d); + ToolButton *node_shortcuts_toggle = memnew(ToolButton); + node_shortcuts_toggle->set_name("NodeShortcutsToggle"); + node_shortcuts_toggle->set_icon(get_icon("Favorites", "EditorIcons")); + node_shortcuts_toggle->set_toggle_mode(true); + node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection")); + node_shortcuts_toggle->set_anchors_and_margins_preset(Control::PRESET_CENTER_RIGHT); + node_shortcuts_toggle->connect("pressed", this, "_update_create_root_dialog"); + top_row->add_child(node_shortcuts_toggle); + + create_root_dialog->add_child(top_row); + VBoxContainer *node_shortcuts = memnew(VBoxContainer); + node_shortcuts->set_name("NodeShortcuts"); + + VBoxContainer *beginner_node_shortcuts = memnew(VBoxContainer); + beginner_node_shortcuts->set_name("BeginnerNodeShortcuts"); + node_shortcuts->add_child(beginner_node_shortcuts); + + Button *button_2d = memnew(Button); + beginner_node_shortcuts->add_child(button_2d); button_2d->set_text(TTR("2D Scene")); button_2d->set_icon(get_icon("Node2D", "EditorIcons")); button_2d->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_2D_SCENE, false)); Button *button_3d = memnew(Button); - create_root_dialog->add_child(button_3d); + beginner_node_shortcuts->add_child(button_3d); button_3d->set_text(TTR("3D Scene")); button_3d->set_icon(get_icon("Spatial", "EditorIcons")); button_3d->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_3D_SCENE, false)); Button *button_ui = memnew(Button); - create_root_dialog->add_child(button_ui); + beginner_node_shortcuts->add_child(button_ui); button_ui->set_text(TTR("User Interface")); button_ui->set_icon(get_icon("Control", "EditorIcons")); button_ui->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_USER_INTERFACE, false)); + VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer); + favorite_node_shortcuts->set_name("FavoriteNodeShortcuts"); + node_shortcuts->add_child(favorite_node_shortcuts); + Button *button_custom = memnew(Button); - create_root_dialog->add_child(button_custom); + node_shortcuts->add_child(button_custom); button_custom->set_text(TTR("Custom Node")); button_custom->set_icon(get_icon("Add", "EditorIcons")); button_custom->connect("pressed", this, "_tool_selected", make_binds(TOOL_NEW, false)); - create_root_dialog->add_spacer(); - + node_shortcuts->add_spacer(); + create_root_dialog->add_child(node_shortcuts); + _update_create_root_dialog(); } break; case NOTIFICATION_ENTER_TREE: { @@ -1251,7 +1304,7 @@ bool SceneTreeDock::_validate_no_foreign() { if (E->get() != edited_scene && E->get()->get_owner() != edited_scene) { - accept->get_ok()->set_text(TTR("Makes Sense!")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Can't operate on nodes from a foreign scene!")); accept->popup_centered_minsize(); return false; @@ -1259,7 +1312,7 @@ bool SceneTreeDock::_validate_no_foreign() { if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get())) >= 0) { - accept->get_ok()->set_text(TTR("Makes Sense!")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Can't operate on nodes the current scene inherits from!")); accept->popup_centered_minsize(); return false; @@ -1443,9 +1496,23 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { Ref<Script> existing = E->get()->get_script(); editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script.get_ref_ptr()); editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing); + + String icon_path; + String name = p_script->get_language()->get_global_class_name(p_script->get_path(), NULL, &icon_path); + if (ScriptServer::is_global_class(name)) { + RES icon = ResourceLoader::load(icon_path); + editor_data->get_undo_redo().add_do_method(E->get(), "set_meta", "_editor_icon", icon); + String existing_name = existing.is_valid() ? existing->get_language()->get_global_class_name(existing->get_path()) : String(); + if (existing.is_null() || !ScriptServer::is_global_class(existing_name)) { + editor_data->get_undo_redo().add_undo_method(E->get(), "set_meta", "_editor_icon", get_icon(E->get()->get_class(), "EditorIcons")); + } else { + editor_data->get_undo_redo().add_undo_method(E->get(), "set_meta", "_editor_icon", editor_data->script_class_get_icon_path(existing_name)); + } + } } editor_data->get_undo_redo().commit_action(); + print_line("test: " + String(Variant(selected.front()->get()->get_meta("_editor_icon")))); editor->push_item(p_script.operator->()); } @@ -2150,6 +2217,67 @@ void SceneTreeDock::_local_tree_selected() { edit_local->set_pressed(true); } +void SceneTreeDock::_update_create_root_dialog() { + + BaseButton *toggle = Object::cast_to<BaseButton>(create_root_dialog->get_node(String("NodeShortcutsTopRow/NodeShortcutsToggle"))); + Node *node_shortcuts = create_root_dialog->get_node(String("NodeShortcuts")); + + if (!toggle || !node_shortcuts) + return; + + Control *beginner_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("BeginnerNodeShortcuts"))); + Control *favorite_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("FavoriteNodeShortcuts"))); + + if (!beginner_nodes || !favorite_nodes) + return; + + EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", toggle->is_pressed()); + EditorSettings::get_singleton()->save(); + if (toggle->is_pressed()) { + + for (int i = 0; i < favorite_nodes->get_child_count(); i++) { + favorite_nodes->get_child(i)->queue_delete(); + } + + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ); + + if (f) { + + while (!f->eof_reached()) { + String l = f->get_line().strip_edges(); + + if (l != String()) { + Button *button = memnew(Button); + favorite_nodes->add_child(button); + button->set_text(TTR(l)); + String name = l.get_slicec(' ', 0); + if (ScriptServer::is_global_class(name)) + name = ScriptServer::get_global_class_base(name); + button->set_icon(get_icon(name, "EditorIcons")); + button->connect("pressed", this, "_favorite_root_selected", make_binds(l)); + } + } + + memdelete(f); + } + + if (!favorite_nodes->is_visible_in_tree()) { + favorite_nodes->show(); + beginner_nodes->hide(); + } + } else { + if (!beginner_nodes->is_visible_in_tree()) { + beginner_nodes->show(); + favorite_nodes->hide(); + } + } +} + +void SceneTreeDock::_favorite_root_selected(const String &p_class) { + selected_favorite_root = p_class; + _tool_selected(TOOL_CREATE_FAVORITE, false); +} + void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_tool_selected"), &SceneTreeDock::_tool_selected, DEFVAL(false)); @@ -2178,6 +2306,8 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_remote_tree_selected"), &SceneTreeDock::_remote_tree_selected); ClassDB::bind_method(D_METHOD("_local_tree_selected"), &SceneTreeDock::_local_tree_selected); ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button); + ClassDB::bind_method(D_METHOD("_favorite_root_selected"), &SceneTreeDock::_favorite_root_selected); + ClassDB::bind_method(D_METHOD("_update_create_root_dialog"), &SceneTreeDock::_update_create_root_dialog); ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance); @@ -2303,6 +2433,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel create_dialog->set_base_type("Node"); add_child(create_dialog); create_dialog->connect("create", this, "_create"); + create_dialog->connect("favorites_updated", this, "_update_create_root_dialog"); + EditorFileSystem::get_singleton()->connect("script_classes_updated", create_dialog, "_save_and_update_favorite_list"); rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo())); add_child(rename_dialog); @@ -2349,11 +2481,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel clear_inherit_confirm = memnew(ConfirmationDialog); clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)")); - clear_inherit_confirm->get_ok()->set_text(TTR("Clear!")); + clear_inherit_confirm->get_ok()->set_text(TTR("Clear")); add_child(clear_inherit_confirm); set_process_input(true); set_process(true); EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true); + EDITOR_DEF("_use_favorites_root_selection", false); } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 57f4759747..34a7c98d11 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -86,6 +86,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_CREATE_2D_SCENE, TOOL_CREATE_3D_SCENE, TOOL_CREATE_USER_INTERFACE, + TOOL_CREATE_FAVORITE, }; @@ -141,6 +142,7 @@ class SceneTreeDock : public VBoxContainer { EditorNode *editor; VBoxContainer *create_root_dialog; + String selected_favorite_root; void _add_children_to_popup(Object *p_obj, int p_depth); @@ -201,6 +203,9 @@ class SceneTreeDock : public VBoxContainer { void _remote_tree_selected(); void _local_tree_selected(); + void _update_create_root_dialog(); + void _favorite_root_selected(const String &p_class); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index e483fde4bc..97147535c0 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -734,7 +734,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da error_list->set_item_metadata(error_list->get_item_count() - 1, stack); - error_count++; + if (warning) + warning_count++; + else + error_count++; } else if (p_msg == "profile_sig") { //cache a signature @@ -1011,20 +1014,26 @@ void ScriptEditorDebugger::_notification(int p_what) { } } - if (error_count != last_error_count) { + if (error_count != last_error_count || warning_count != last_warning_count) { - if (error_count == 0) { + if (error_count == 0 && warning_count == 0) { error_split->set_name(TTR("Errors")); debugger_button->set_text(TTR("Debugger")); debugger_button->set_icon(Ref<Texture>()); tabs->set_tab_icon(error_split->get_index(), Ref<Texture>()); } else { - error_split->set_name(TTR("Errors") + " (" + itos(error_count) + ")"); - debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count) + ")"); - debugger_button->set_icon(get_icon("Error", "EditorIcons")); - tabs->set_tab_icon(error_split->get_index(), get_icon("Error", "EditorIcons")); + error_split->set_name(TTR("Errors") + " (" + itos(error_count + warning_count) + ")"); + debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count + warning_count) + ")"); + if (error_count == 0) { + debugger_button->set_icon(get_icon("Warning", "EditorIcons")); + tabs->set_tab_icon(error_split->get_index(), get_icon("Warning", "EditorIcons")); + } else { + debugger_button->set_icon(get_icon("Error", "EditorIcons")); + tabs->set_tab_icon(error_split->get_index(), get_icon("Error", "EditorIcons")); + } } last_error_count = error_count; + last_warning_count = warning_count; } if (connection.is_null()) { @@ -1054,6 +1063,7 @@ void ScriptEditorDebugger::_notification(int p_what) { error_list->clear(); error_stack->clear(); error_count = 0; + warning_count = 0; profiler_signature.clear(); //live_edit_root->set_text("/root"); @@ -1198,7 +1208,7 @@ void ScriptEditorDebugger::start() { int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); if (server->listen(remote_port) != OK) { - EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), true); + EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), EditorLog::MSG_TYPE_ERROR); return; } @@ -1750,6 +1760,7 @@ void ScriptEditorDebugger::_clear_errors_list() { error_list->clear(); error_count = 0; + warning_count = 0; _notification(NOTIFICATION_PROCESS); } @@ -2162,9 +2173,11 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { live_debug = false; last_path_id = false; error_count = 0; + warning_count = 0; hide_on_stop = true; enable_external_editor = false; last_error_count = 0; + last_warning_count = 0; EditorNode::get_singleton()->get_pause_button()->connect("pressed", this, "_paused"); } diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index f7fe348b65..ce705aa35b 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -96,7 +96,9 @@ class ScriptEditorDebugger : public Control { EditorFileDialog *file_dialog; int error_count; + int warning_count; int last_error_count; + int last_warning_count; bool hide_on_stop; bool enable_external_editor; diff --git a/modules/csg/csg.h b/modules/csg/csg.h index 53303a6533..2e07c23e28 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -34,9 +34,9 @@ #include "aabb.h" #include "dvector.h" #include "map.h" -#include "math_2d.h" #include "oa_hash_map.h" #include "plane.h" +#include "rect2.h" #include "scene/resources/material.h" #include "transform.h" #include "vector3.h" diff --git a/modules/gdnative/gdnative/pool_arrays.cpp b/modules/gdnative/gdnative/pool_arrays.cpp index 6688be1a0d..2b6b7a823a 100644 --- a/modules/gdnative/gdnative/pool_arrays.cpp +++ b/modules/gdnative/gdnative/pool_arrays.cpp @@ -35,7 +35,7 @@ #include "dvector.h" #include "core/color.h" -#include "core/math/math_2d.h" +#include "core/math/vector2.h" #include "core/math/vector3.h" #ifdef __cplusplus diff --git a/modules/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp index 83c58db520..54b98fc4e5 100644 --- a/modules/gdnative/gdnative/rect2.cpp +++ b/modules/gdnative/gdnative/rect2.cpp @@ -30,7 +30,7 @@ #include "gdnative/rect2.h" -#include "core/math/math_2d.h" +#include "core/math/transform_2d.h" #include "core/variant.h" #ifdef __cplusplus diff --git a/modules/gdnative/gdnative/transform2d.cpp b/modules/gdnative/gdnative/transform2d.cpp index c69607a18a..fa0e15d9d2 100644 --- a/modules/gdnative/gdnative/transform2d.cpp +++ b/modules/gdnative/gdnative/transform2d.cpp @@ -30,7 +30,7 @@ #include "gdnative/transform2d.h" -#include "core/math/math_2d.h" +#include "core/math/transform_2d.h" #include "core/variant.h" #ifdef __cplusplus diff --git a/modules/gdnative/gdnative/vector2.cpp b/modules/gdnative/gdnative/vector2.cpp index 9e40b42373..c7902e06ee 100644 --- a/modules/gdnative/gdnative/vector2.cpp +++ b/modules/gdnative/gdnative/vector2.cpp @@ -30,7 +30,7 @@ #include "gdnative/vector2.h" -#include "core/math/math_2d.h" +#include "core/math/vector2.h" #include "core/variant.h" #ifdef __cplusplus diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 0f3b497c94..24264c4256 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -62,6 +62,11 @@ void NativeScript::_bind_methods() { ClassDB::bind_method(D_METHOD("set_library", "library"), &NativeScript::set_library); ClassDB::bind_method(D_METHOD("get_library"), &NativeScript::get_library); + ClassDB::bind_method(D_METHOD("set_script_class_name", "class_name"), &NativeScript::set_script_class_name); + ClassDB::bind_method(D_METHOD("get_script_class_name"), &NativeScript::get_script_class_name); + ClassDB::bind_method(D_METHOD("set_script_class_icon_path", "icon_path"), &NativeScript::set_script_class_icon_path); + ClassDB::bind_method(D_METHOD("get_script_class_icon_path"), &NativeScript::get_script_class_icon_path); + ClassDB::bind_method(D_METHOD("get_class_documentation"), &NativeScript::get_class_documentation); ClassDB::bind_method(D_METHOD("get_method_documentation", "method"), &NativeScript::get_method_documentation); ClassDB::bind_method(D_METHOD("get_signal_documentation", "signal_name"), &NativeScript::get_signal_documentation); @@ -69,6 +74,9 @@ void NativeScript::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name"); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); + ADD_GROUP("Script Class", "script_class_"); + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_name"), "set_script_class_name", "get_script_class_name"); + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_icon_path", PROPERTY_HINT_FILE), "set_script_class_icon_path", "get_script_class_icon_path"); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo(Variant::OBJECT, "new")); } @@ -131,6 +139,22 @@ Ref<GDNativeLibrary> NativeScript::get_library() const { return library; } +void NativeScript::set_script_class_name(String p_type) { + script_class_name = p_type; +} + +String NativeScript::get_script_class_name() const { + return script_class_name; +} + +void NativeScript::set_script_class_icon_path(String p_icon_path) { + script_class_icon_path = p_icon_path; +} + +String NativeScript::get_script_class_icon_path() const { + return script_class_icon_path; +} + bool NativeScript::can_instance() const { NativeScriptDesc *script_data = get_script_desc(); @@ -1396,6 +1420,22 @@ void NativeScriptLanguage::thread_exit() { #endif // NO_THREADS +bool NativeScriptLanguage::handles_global_class_type(const String &p_type) const { + return p_type == "NativeScript"; +} + +String NativeScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { + Ref<NativeScript> script = ResourceLoader::load(p_path, "NativeScript"); + if (script.is_valid()) { + *r_base_type = script->get_instance_base_type(); + *r_icon_path = script->get_script_class_icon_path(); + return script->get_script_class_name(); + } + *r_base_type = String(); + *r_icon_path = String(); + return String(); +} + void NativeReloadNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_notification"), &NativeReloadNode::_notification); } diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index 688ed295db..c1f11646b0 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -118,6 +118,9 @@ class NativeScript : public Script { String class_name; + String script_class_name; + String script_class_icon_path; + #ifndef NO_THREADS Mutex *owners_lock; #endif @@ -135,6 +138,11 @@ public: void set_library(Ref<GDNativeLibrary> p_library); Ref<GDNativeLibrary> get_library() const; + void set_script_class_name(String p_type); + String get_script_class_name() const; + void set_script_class_icon_path(String p_icon_path); + String get_script_class_icon_path() const; + virtual bool can_instance() const; virtual Ref<Script> get_base_script() const; //for script inheritance @@ -332,6 +340,9 @@ public: void set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag); const void *get_global_type_tag(int p_idx, StringName p_class_name) const; + + virtual bool handles_global_class_type(const String &p_type) const; + virtual String get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const; }; inline NativeScriptDesc *NativeScript::get_script_desc() const { diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index ef6a42f145..b987d2897f 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -181,7 +181,11 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Variant::CallErro bool GDScript::can_instance() const { - return valid || (!tool && !ScriptServer::is_scripting_enabled()); +#ifdef TOOLS_ENABLED + return valid && (tool || ScriptServer::is_scripting_enabled()); +#else + return valid; +#endif } Ref<Script> GDScript::get_base_script() const { @@ -310,27 +314,6 @@ bool GDScript::get_property_default_value(const StringName &p_property, Variant ScriptInstance *GDScript::instance_create(Object *p_this) { - if (!tool && !ScriptServer::is_scripting_enabled()) { - -#ifdef TOOLS_ENABLED - - //instance a fake script for editing the values - //plist.invert(); - - /*print_line("CREATING PLACEHOLDER"); - for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { - print_line(E->get().name); - }*/ - PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this)); - placeholders.insert(si); - //_update_placeholder(si); - _update_exports(); - return si; -#else - return NULL; -#endif - } - GDScript *top = this; while (top->_base) top = top->_base; @@ -349,6 +332,27 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { Variant::CallError unchecked_error; return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); } + +PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) { +#ifdef TOOLS_ENABLED + + //instance a fake script for editing the values + //plist.invert(); + + /*print_line("CREATING PLACEHOLDER"); + for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { + print_line(E->get().name); + }*/ + PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this)); + placeholders.insert(si); + //_update_placeholder(si); + _update_exports(); + return si; +#else + return NULL; +#endif +} + bool GDScript::instance_has(const Object *p_this) const { #ifndef NO_THREADS @@ -480,6 +484,10 @@ bool GDScript::_update_exports() { for (int i = 0; i < c->_signals.size(); i++) { _signals[c->_signals[i].name] = c->_signals[i].arguments; } + } else { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->set_build_failed(true); + } } } else { //print_line("unchanged is "+get_path()); @@ -501,7 +509,7 @@ bool GDScript::_update_exports() { _update_exports_values(values, propnames); for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - + E->get()->set_build_failed(false); E->get()->update(propnames, values); } } @@ -1803,7 +1811,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { return p_type == "GDScript"; } -String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type) const { +String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { PoolVector<uint8_t> sourcef; Error err; @@ -1868,6 +1876,12 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b } } } + if (r_icon_path) { + if (c->icon_path.empty() || c->icon_path.is_abs_path()) + *r_icon_path = c->icon_path; + else if (c->icon_path.is_rel_path()) + *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path(); + } return c->name; } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index edad12f1f3..d400230f43 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -171,6 +171,7 @@ public: virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so virtual ScriptInstance *instance_create(Object *p_this); + virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this); virtual bool instance_has(const Object *p_this) const; virtual bool has_source_code() const; @@ -491,7 +492,7 @@ public: /* GLOBAL CLASSES */ virtual bool handles_global_class_type(const String &p_type) const; - virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const; + virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const; GDScriptLanguage(); ~GDScriptLanguage(); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index e0ed2b332b..bec314866d 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3429,6 +3429,32 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(2); + if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { + tokenizer->advance(); + + if ((tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type() == Variant::STRING)) { + Variant constant = tokenizer->get_token_constant(); + String icon_path = constant.operator String(); + + String abs_icon_path = icon_path.is_rel_path() ? self_path.get_base_dir().plus_file(icon_path).simplify_path() : icon_path; + if (!FileAccess::exists(abs_icon_path)) { + _set_error("No class icon found at: " + abs_icon_path); + return; + } + + p_class->icon_path = icon_path; + + tokenizer->advance(); + } else { + _set_error("Optional parameter after 'class_name' must be a string constant file path to an icon."); + return; + } + + } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT) { + _set_error("Class icon must be separated by a comma."); + return; + } + } break; case GDScriptTokenizer::TK_PR_TOOL: { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index d8ee4e8159..dbe523a0b9 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -149,6 +149,7 @@ public: StringName extends_file; Vector<StringName> extends_class; DataType base_type; + String icon_path; struct Member { PropertyInfo _export; diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index 2ec00aa72d..e2c630565f 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -297,6 +297,47 @@ bool MobileVRInterface::initialize() { mag_current_min = Vector3(0, 0, 0); mag_current_max = Vector3(0, 0, 0); + // build our shader + if (lens_shader == NULL) { + ///@TODO need to switch between GLES2 and GLES3 version, Reduz suggested moving this into our drivers and making this a core shader + // create a shader + lens_shader = new LensDistortedShaderGLES3(); + + // create our shader stuff + lens_shader->init(); + + glGenBuffers(1, &half_screen_quad); + glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad); + { + /* clang-format off */ + const float qv[16] = { + 0, -1, + -1, -1, + 0, 1, + -1, 1, + 1, 1, + 1, 1, + 1, -1, + 1, -1, + }; + /* clang-format on */ + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + + glGenVertexArrays(1, &half_screen_array); + glBindVertexArray(half_screen_array); + glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, ((uint8_t *)NULL) + 8); + glEnableVertexAttribArray(4); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + } + // reset our orientation orientation = Basis(); @@ -304,7 +345,7 @@ bool MobileVRInterface::initialize() { arvr_server->set_primary_interface(this); last_ticks = OS::get_singleton()->get_ticks_usec(); - ; + initialized = true; }; @@ -319,6 +360,15 @@ void MobileVRInterface::uninitialize() { arvr_server->clear_primary_interface_if(this); } + // cleanup our shader and buffers + if (lens_shader != NULL) { + glDeleteVertexArrays(1, &half_screen_array); + glDeleteBuffers(1, &half_screen_quad); + + delete lens_shader; + lens_shader = NULL; + } + initialized = false; }; }; @@ -394,6 +444,9 @@ void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_t // We must have a valid render target ERR_FAIL_COND(!p_render_target.is_valid()); + // We must have an initialised shader + ERR_FAIL_COND(lens_shader != NULL); + // Because we are rendering to our device we must use our main viewport! ERR_FAIL_COND(p_screen_rect == Rect2()); @@ -420,13 +473,13 @@ void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_t glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texid); - lens_shader.bind(); - lens_shader.set_uniform(LensDistortedShaderGLES3::OFFSET_X, offset_x); - lens_shader.set_uniform(LensDistortedShaderGLES3::K1, k1); - lens_shader.set_uniform(LensDistortedShaderGLES3::K2, k2); - lens_shader.set_uniform(LensDistortedShaderGLES3::EYE_CENTER, eye_center); - lens_shader.set_uniform(LensDistortedShaderGLES3::UPSCALE, oversample); - lens_shader.set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio); + lens_shader->bind(); + lens_shader->set_uniform(LensDistortedShaderGLES3::OFFSET_X, offset_x); + lens_shader->set_uniform(LensDistortedShaderGLES3::K1, k1); + lens_shader->set_uniform(LensDistortedShaderGLES3::K2, k2); + lens_shader->set_uniform(LensDistortedShaderGLES3::EYE_CENTER, eye_center); + lens_shader->set_uniform(LensDistortedShaderGLES3::UPSCALE, oversample); + lens_shader->set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio); glBindVertexArray(half_screen_array); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -454,41 +507,7 @@ MobileVRInterface::MobileVRInterface() { k2 = 0.215; last_ticks = 0; - // create our shader stuff - lens_shader.init(); - - { - glGenBuffers(1, &half_screen_quad); - glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad); - { - /* clang-format off */ - const float qv[16] = { - 0, -1, - -1, -1, - 0, 1, - -1, 1, - 1, 1, - 1, 1, - 1, -1, - 1, -1, - }; - /* clang-format on */ - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - glGenVertexArrays(1, &half_screen_array); - glBindVertexArray(half_screen_array); - glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, ((uint8_t *)NULL) + 8); - glEnableVertexAttribArray(4); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - } + lens_shader = NULL; }; MobileVRInterface::~MobileVRInterface() { diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h index 7b2344f1fe..cee0cca90e 100644 --- a/modules/mobile_vr/mobile_vr_interface.h +++ b/modules/mobile_vr/mobile_vr_interface.h @@ -58,7 +58,7 @@ private: float eye_height; uint64_t last_ticks; - LensDistortedShaderGLES3 lens_shader; + LensDistortedShaderGLES3 *lens_shader; GLuint half_screen_quad; GLuint half_screen_array; diff --git a/modules/mono/SCsub b/modules/mono/SCsub index a2df83925c..f3cf4c9c5d 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -18,14 +18,20 @@ def make_cs_files_header(src, dst): header.write('#include "ustring.h"\n') inserted_files = '' import os - for file in os.listdir(src): - if file.endswith('.cs'): - with open(os.path.join(src, file), 'rb') as f: + latest_mtime = 0 + for root, _, files in os.walk(src): + files = [f for f in files if f.endswith('.cs')] + for file in files: + filepath = os.path.join(root, file) + filepath_src_rel = os.path.relpath(filepath, src) + mtime = os.path.getmtime(filepath) + latest_mtime = mtime if mtime > latest_mtime else latest_mtime + with open(filepath, 'rb') as f: buf = f.read() decomp_size = len(buf) import zlib buf = zlib.compress(buf) - name = os.path.splitext(file)[0] + name = os.path.splitext(os.path.normpath(filepath_src_rel))[0].strip(os.sep).replace(os.sep, '_').replace('.', '_dotto_') header.write('\nstatic const int _cs_' + name + '_compressed_size = ' + str(len(buf)) + ';\n') header.write('static const int _cs_' + name + '_uncompressed_size = ' + str(decomp_size) + ';\n') header.write('static const unsigned char _cs_' + name + '_compressed[] = { ') @@ -33,18 +39,13 @@ def make_cs_files_header(src, dst): if i > 0: header.write(', ') header.write(byte_to_str(buf[buf_idx])) - inserted_files += '\tr_files.insert("' + file + '", ' \ + inserted_files += '\tr_files.insert("' + filepath_src_rel + '", ' \ 'CompressedFile(_cs_' + name + '_compressed_size, ' \ '_cs_' + name + '_uncompressed_size, ' \ '_cs_' + name + '_compressed));\n' header.write(' };\n') - version_file = os.path.join(src, 'VERSION.txt') - with open(version_file, 'r') as content_file: - try: - glue_version = int(content_file.read()) # make sure the format is valid - header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n') - except ValueError: - raise ValueError('Invalid C# glue version in: ' + version_file) + glue_version = int(latest_mtime) # The latest modified time will do for now + header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n') header.write('\nstruct CompressedFile\n' '{\n' '\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n' '\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n' diff --git a/modules/mono/config.py b/modules/mono/config.py index 7f226443a1..c4f8dcfde8 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -83,7 +83,8 @@ def configure(env): mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0'] if env['platform'] == 'windows': - mono_root = None + mono_root = '' + if bits == '32': if os.getenv('MONO32_PREFIX'): mono_root = os.getenv('MONO32_PREFIX') diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 7d7028a7a6..cd1a8266ed 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -736,6 +736,9 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { obj->get_script_instance()->get_property_state(state); map[obj->get_instance_id()] = state; obj->set_script(RefPtr()); + } else { + // no instance found. Let's remove it so we don't loop forever + E->get()->placeholders.erase(E->get()->placeholders.front()->get()); } } @@ -747,8 +750,24 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { } } - if (gdmono->reload_scripts_domain() != OK) + if (gdmono->reload_scripts_domain() != OK) { + // Failed to reload the scripts domain + // Make sure to add the scripts back to their owners before returning + for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) { + Ref<CSharpScript> scr = E->key(); + for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) { + Object *obj = ObjectDB::get_instance(F->key()); + if (!obj) + continue; + obj->set_script(scr.get_ref_ptr()); + // Save reload state for next time if not saved + if (!scr->pending_reload_state.has(obj->get_instance_id())) { + scr->pending_reload_state[obj->get_instance_id()] = F->get(); + } + } + } return; + } for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) { @@ -778,6 +797,14 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { continue; } + if (scr->valid && scr->is_tool() && obj->get_script_instance()->is_placeholder()) { + // Script instance was a placeholder, but now the script was built successfully and is a tool script. + // We have to replace the placeholder with an actual C# script instance. + scr->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(obj->get_script_instance())); + ScriptInstance *script_instance = scr->instance_create(obj); + obj->set_script_instance(script_instance); // Not necessary as it's already done in instance_create, but just in case... + } + for (List<Pair<StringName, Variant> >::Element *G = F->get().front(); G; G = G->next()) { obj->get_script_instance()->set(G->get().first, G->get().second); } @@ -1474,8 +1501,12 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List bool CSharpScript::_update_exports() { #ifdef TOOLS_ENABLED - if (!valid) + if (!valid) { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->set_build_failed(true); + } return false; + } bool changed = false; @@ -1577,6 +1608,7 @@ bool CSharpScript::_update_exports() { _update_exports_values(values, propnames); for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->set_build_failed(false); E->get()->update(propnames, values); } } @@ -1687,7 +1719,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute)); - PropertyHint hint; + PropertyHint hint = PROPERTY_HINT_NONE; String hint_string; if (variant_type == Variant::NIL) { @@ -1873,7 +1905,11 @@ bool CSharpScript::can_instance() const { } #endif - return valid || (!tool && !ScriptServer::is_scripting_enabled()); +#ifdef TOOLS_ENABLED + return valid && (tool || ScriptServer::is_scripting_enabled()); +#else + return valid; +#endif } StringName CSharpScript::get_instance_base_type() const { @@ -1971,16 +2007,9 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call ScriptInstance *CSharpScript::instance_create(Object *p_this) { - if (!tool && !ScriptServer::is_scripting_enabled()) { -#ifdef TOOLS_ENABLED - PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); - placeholders.insert(si); - _update_exports(); - return si; -#else - return NULL; +#ifdef DEBUG_ENABLED + CRASH_COND(!valid); #endif - } if (!script_class) { if (GDMono::get_singleton()->get_project_assembly() == NULL) { @@ -2011,6 +2040,18 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); } +PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) { + +#ifdef TOOLS_ENABLED + PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); + placeholders.insert(si); + _update_exports(); + return si; +#else + return NULL; +#endif +} + bool CSharpScript::instance_has(const Object *p_this) const { #ifndef NO_THREADS @@ -2077,9 +2118,11 @@ Error CSharpScript::reload(bool p_keep_state) { if (script_class) { #ifdef DEBUG_ENABLED - OS::get_singleton()->print(String("Found class " + script_class->get_namespace() + "." + - script_class->get_name() + " for script " + get_path() + "\n") - .utf8()); + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print(String("Found class " + script_class->get_namespace() + "." + + script_class->get_name() + " for script " + get_path() + "\n") + .utf8()); + } #endif tool = script_class->has_attribute(CACHED_CLASS(ToolAttribute)); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 363ae59d22..53644eafae 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -139,6 +139,7 @@ public: virtual bool can_instance() const; virtual StringName get_instance_base_type() const; virtual ScriptInstance *instance_create(Object *p_this); + virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this); virtual bool instance_has(const Object *p_this) const; virtual bool has_source_code() const; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 76907451e7..b97bb5e95f 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -512,6 +512,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo data.resize(file_data.uncompressed_size); Compression::decompress(data.ptrw(), file_data.uncompressed_size, file_data.data, file_data.compressed_size, Compression::MODE_DEFLATE); + String output_dir = output_file.get_base_dir(); + + if (!DirAccess::exists(output_dir)) { + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Error err = da->make_dir_recursive(ProjectSettings::get_singleton()->globalize_path(output_dir)); + ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); + } + FileAccessRef file = FileAccess::open(output_file, FileAccess::WRITE); ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); file->store_buffer(data.ptr(), data.size()); diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index b3b259e851..0fb8734410 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -210,6 +210,8 @@ bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_s if (!FileAccess::exists(api_assembly_file)) { MonoBuildInfo api_build_info(api_sln_file, p_config); + // TODO Replace this global NoWarn with '#pragma warning' directives on generated files, + // once we start to actively document manually maintained C# classes api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) { diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 0551c1991a..148bb32398 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -182,7 +182,7 @@ bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) { } bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) { - return ptr->erase_checked(GDMonoMarshal::mono_object_to_variant(key)); + return ptr->erase(GDMonoMarshal::mono_object_to_variant(key)); } bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) { @@ -191,7 +191,7 @@ bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject // no dupes Variant *ret = ptr->getptr(varKey); if (ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value)) { - ptr->erase_checked(varKey); + ptr->erase(varKey); return true; } diff --git a/modules/mono/glue/cs_files/Array.cs b/modules/mono/glue/cs_files/Array.cs index 51f57daef4..1ec4d7d20a 100644 --- a/modules/mono/glue/cs_files/Array.cs +++ b/modules/mono/glue/cs_files/Array.cs @@ -331,5 +331,10 @@ namespace Godot { return GetEnumerator(); } + + internal IntPtr GetPtr() + { + return objectArray.GetPtr(); + } } } diff --git a/modules/mono/glue/cs_files/Dictionary.cs b/modules/mono/glue/cs_files/Dictionary.cs index 57a1960ad9..30d17c2a59 100644 --- a/modules/mono/glue/cs_files/Dictionary.cs +++ b/modules/mono/glue/cs_files/Dictionary.cs @@ -397,5 +397,10 @@ namespace Godot { return GetEnumerator(); } + + internal IntPtr GetPtr() + { + return objectDict.GetPtr(); + } } } diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs index 43de9156f2..0a5d703f27 100644 --- a/modules/mono/glue/cs_files/GD.cs +++ b/modules/mono/glue/cs_files/GD.cs @@ -192,10 +192,5 @@ namespace Godot { return NativeCalls.godot_icall_Godot_var2str(var); } - - public static WeakRef WeakRef(Object obj) - { - return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj)); - } } } diff --git a/modules/mono/glue/cs_files/ObjectExtensions.cs b/modules/mono/glue/cs_files/ObjectExtensions.cs new file mode 100644 index 0000000000..5c9e6609f4 --- /dev/null +++ b/modules/mono/glue/cs_files/ObjectExtensions.cs @@ -0,0 +1,17 @@ +using System; + +namespace Godot +{ + public partial class Object + { + public static bool IsInstanceValid(Object instance) + { + return instance != null && instance.NativeInstance != IntPtr.Zero; + } + + public static WeakRef WeakRef(Object obj) + { + return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj)); + } + } +} diff --git a/modules/mono/glue/cs_files/Transform.cs b/modules/mono/glue/cs_files/Transform.cs index d1b247a552..e432d5b52c 100644 --- a/modules/mono/glue/cs_files/Transform.cs +++ b/modules/mono/glue/cs_files/Transform.cs @@ -102,7 +102,18 @@ namespace Godot basis[0, 2] * vInv.x + basis[1, 2] * vInv.y + basis[2, 2] * vInv.z ); } - + + // Constants + private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero); + private static readonly Transform _flipX = new Transform(new Basis(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1)), Vector3.Zero); + private static readonly Transform _flipY = new Transform(new Basis(new Vector3(1, 0, 0), new Vector3(0, -1, 0), new Vector3(0, 0, 1)), Vector3.Zero); + private static readonly Transform _flipZ = new Transform(new Basis(new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, -1)), Vector3.Zero); + + public static Transform Identity { get { return _identity; } } + public static Transform FlipX { get { return _flipX; } } + public static Transform FlipY { get { return _flipY; } } + public static Transform FlipZ { get { return _flipZ; } } + // Constructors public Transform(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin) { diff --git a/modules/mono/glue/cs_files/Transform2D.cs b/modules/mono/glue/cs_files/Transform2D.cs index ff5259178b..8d30833066 100644 --- a/modules/mono/glue/cs_files/Transform2D.cs +++ b/modules/mono/glue/cs_files/Transform2D.cs @@ -11,22 +11,10 @@ namespace Godot [StructLayout(LayoutKind.Sequential)] public struct Transform2D : IEquatable<Transform2D> { - private static readonly Transform2D identity = new Transform2D - ( - new Vector2(1f, 0f), - new Vector2(0f, 1f), - new Vector2(0f, 0f) - ); - public Vector2 x; public Vector2 y; public Vector2 o; - public static Transform2D Identity - { - get { return identity; } - } - public Vector2 Origin { get { return o; } @@ -264,6 +252,15 @@ namespace Godot Vector2 vInv = v - o; return new Vector2(x.Dot(vInv), y.Dot(vInv)); } + + // Constants + private static readonly Transform2D _identity = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, 1f), Vector2.Zero); + private static readonly Transform2D _flipX = new Transform2D(new Vector2(-1f, 0f), new Vector2(0f, 1f), Vector2.Zero); + private static readonly Transform2D _flipY = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, -1f), Vector2.Zero); + + public static Transform2D Identity { get { return _identity; } } + public static Transform2D FlipX { get { return _flipX; } } + public static Transform2D FlipY { get { return _flipY; } } // Constructors public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin) diff --git a/modules/mono/glue/cs_files/VERSION.txt b/modules/mono/glue/cs_files/VERSION.txt deleted file mode 100755 index 7f8f011eb7..0000000000 --- a/modules/mono/glue/cs_files/VERSION.txt +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/modules/mono/glue/cs_files/Vector2.cs b/modules/mono/glue/cs_files/Vector2.cs index c274364895..14c8de6986 100644 --- a/modules/mono/glue/cs_files/Vector2.cs +++ b/modules/mono/glue/cs_files/Vector2.cs @@ -231,24 +231,27 @@ namespace Godot { return new Vector2(y, -x); } - - private static readonly Vector2 zero = new Vector2 (0, 0); - private static readonly Vector2 one = new Vector2 (1, 1); - private static readonly Vector2 negOne = new Vector2 (-1, -1); - - private static readonly Vector2 up = new Vector2 (0, 1); - private static readonly Vector2 down = new Vector2 (0, -1); - private static readonly Vector2 right = new Vector2 (1, 0); - private static readonly Vector2 left = new Vector2 (-1, 0); - - public static Vector2 Zero { get { return zero; } } - public static Vector2 One { get { return one; } } - public static Vector2 NegOne { get { return negOne; } } - - public static Vector2 Up { get { return up; } } - public static Vector2 Down { get { return down; } } - public static Vector2 Right { get { return right; } } - public static Vector2 Left { get { return left; } } + + // Constants + private static readonly Vector2 _zero = new Vector2(0, 0); + private static readonly Vector2 _one = new Vector2(1, 1); + private static readonly Vector2 _negOne = new Vector2(-1, -1); + private static readonly Vector2 _inf = new Vector2(Mathf.Inf, Mathf.Inf); + + private static readonly Vector2 _up = new Vector2(0, -1); + private static readonly Vector2 _down = new Vector2(0, 1); + private static readonly Vector2 _right = new Vector2(1, 0); + private static readonly Vector2 _left = new Vector2(-1, 0); + + public static Vector2 Zero { get { return _zero; } } + public static Vector2 NegOne { get { return _negOne; } } + public static Vector2 One { get { return _one; } } + public static Vector2 Inf { get { return _inf; } } + + public static Vector2 Up { get { return _up; } } + public static Vector2 Down { get { return _down; } } + public static Vector2 Right { get { return _right; } } + public static Vector2 Left { get { return _left; } } // Constructors public Vector2(real_t x, real_t y) diff --git a/modules/mono/glue/cs_files/Vector3.cs b/modules/mono/glue/cs_files/Vector3.cs index 085a4f0043..861d9c54d9 100644 --- a/modules/mono/glue/cs_files/Vector3.cs +++ b/modules/mono/glue/cs_files/Vector3.cs @@ -272,27 +272,30 @@ namespace Godot ); } - private static readonly Vector3 zero = new Vector3 (0, 0, 0); - private static readonly Vector3 one = new Vector3 (1, 1, 1); - private static readonly Vector3 negOne = new Vector3 (-1, -1, -1); + // Constants + private static readonly Vector3 _zero = new Vector3(0, 0, 0); + private static readonly Vector3 _one = new Vector3(1, 1, 1); + private static readonly Vector3 _negOne = new Vector3(-1, -1, -1); + private static readonly Vector3 _inf = new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf); - private static readonly Vector3 up = new Vector3 (0, 1, 0); - private static readonly Vector3 down = new Vector3 (0, -1, 0); - private static readonly Vector3 right = new Vector3 (1, 0, 0); - private static readonly Vector3 left = new Vector3 (-1, 0, 0); - private static readonly Vector3 forward = new Vector3 (0, 0, -1); - private static readonly Vector3 back = new Vector3 (0, 0, 1); - - public static Vector3 Zero { get { return zero; } } - public static Vector3 One { get { return one; } } - public static Vector3 NegOne { get { return negOne; } } + private static readonly Vector3 _up = new Vector3(0, 1, 0); + private static readonly Vector3 _down = new Vector3(0, -1, 0); + private static readonly Vector3 _right = new Vector3(1, 0, 0); + private static readonly Vector3 _left = new Vector3(-1, 0, 0); + private static readonly Vector3 _forward = new Vector3(0, 0, -1); + private static readonly Vector3 _back = new Vector3(0, 0, 1); + + public static Vector3 Zero { get { return _zero; } } + public static Vector3 One { get { return _one; } } + public static Vector3 NegOne { get { return _negOne; } } + public static Vector3 Inf { get { return _inf; } } - public static Vector3 Up { get { return up; } } - public static Vector3 Down { get { return down; } } - public static Vector3 Right { get { return right; } } - public static Vector3 Left { get { return left; } } - public static Vector3 Forward { get { return forward; } } - public static Vector3 Back { get { return back; } } + public static Vector3 Up { get { return _up; } } + public static Vector3 Down { get { return _down; } } + public static Vector3 Right { get { return _right; } } + public static Vector3 Left { get { return _left; } } + public static Vector3 Forward { get { return _forward; } } + public static Vector3 Back { get { return _back; } } // Constructors public Vector3(real_t x, real_t y, real_t z) diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 7cee1b491b..1aba3f56da 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -163,7 +163,6 @@ public: class VideoStreamTheora : public VideoStream { GDCLASS(VideoStreamTheora, VideoStream); - RES_BASE_EXTENSION("ogv"); String file; int audio_track; diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h index 08be50846d..dcf88092c5 100644 --- a/modules/webm/video_stream_webm.h +++ b/modules/webm/video_stream_webm.h @@ -109,7 +109,6 @@ private: class VideoStreamWebm : public VideoStream { GDCLASS(VideoStreamWebm, VideoStream); - RES_BASE_EXTENSION("webm"); String file; int audio_track; diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub index 15a88773e7..c0985b3245 100644 --- a/modules/websocket/SCsub +++ b/modules/websocket/SCsub @@ -7,87 +7,88 @@ Import('env_modules') env_lws = env_modules.Clone() -thirdparty_dir = "#thirdparty/libwebsockets/" -helper_dir = "win32helpers/" -thirdparty_sources = [ - - "core/alloc.c", - "core/context.c", - "core/libwebsockets.c", - "core/output.c", - "core/pollfd.c", - "core/service.c", - - "event-libs/poll/poll.c", - - "misc/base64-decode.c", - "misc/lejp.c", - "misc/sha-1.c", - - "roles/h1/ops-h1.c", - "roles/http/header.c", - "roles/http/client/client.c", - "roles/http/client/client-handshake.c", - "roles/http/server/fops-zip.c", - "roles/http/server/lejp-conf.c", - "roles/http/server/parsers.c", - "roles/http/server/server.c", - "roles/listen/ops-listen.c", - "roles/pipe/ops-pipe.c", - "roles/raw/ops-raw.c", - - "roles/ws/client-ws.c", - "roles/ws/client-parser-ws.c", - "roles/ws/ops-ws.c", - "roles/ws/server-ws.c", - - "tls/tls.c", - "tls/tls-client.c", - "tls/tls-server.c", - - "tls/mbedtls/wrapper/library/ssl_cert.c", - "tls/mbedtls/wrapper/library/ssl_pkey.c", - "tls/mbedtls/wrapper/library/ssl_stack.c", - "tls/mbedtls/wrapper/library/ssl_methods.c", - "tls/mbedtls/wrapper/library/ssl_lib.c", - "tls/mbedtls/wrapper/library/ssl_x509.c", - "tls/mbedtls/wrapper/platform/ssl_port.c", - "tls/mbedtls/wrapper/platform/ssl_pm.c", - "tls/mbedtls/lws-genhash.c", - "tls/mbedtls/mbedtls-client.c", - "tls/mbedtls/lws-genrsa.c", - "tls/mbedtls/ssl.c", - "tls/mbedtls/mbedtls-server.c" -] - -if env_lws["platform"] == "android": # Builtin getifaddrs - thirdparty_sources += ["misc/getifaddrs.c"] - -if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": # Winsock - thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"] -else: # Unix socket - thirdparty_sources += ["plat/lws-plat-unix.c"] - - -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -if env_lws["platform"] == "javascript": # No need to add third party libraries at all - pass -else: - env_lws.add_source_files(env.modules_sources, thirdparty_sources) - env_lws.Append(CPPPATH=[thirdparty_dir]) - - wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]] - env_lws.Prepend(CPPPATH=wrapper_includes) - - if env['builtin_mbedtls']: - mbedtls_includes = "#thirdparty/mbedtls/include" - env_lws.Prepend(CPPPATH=[mbedtls_includes]) - - if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": - env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir]) - - if env_lws["platform"] == "uwp": - env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"]) +if env['builtin_libwebsockets']: + thirdparty_dir = "#thirdparty/libwebsockets/" + helper_dir = "win32helpers/" + thirdparty_sources = [ + + "core/alloc.c", + "core/context.c", + "core/libwebsockets.c", + "core/output.c", + "core/pollfd.c", + "core/service.c", + + "event-libs/poll/poll.c", + + "misc/base64-decode.c", + "misc/lejp.c", + "misc/sha-1.c", + + "roles/h1/ops-h1.c", + "roles/http/header.c", + "roles/http/client/client.c", + "roles/http/client/client-handshake.c", + "roles/http/server/fops-zip.c", + "roles/http/server/lejp-conf.c", + "roles/http/server/parsers.c", + "roles/http/server/server.c", + "roles/listen/ops-listen.c", + "roles/pipe/ops-pipe.c", + "roles/raw/ops-raw.c", + + "roles/ws/client-ws.c", + "roles/ws/client-parser-ws.c", + "roles/ws/ops-ws.c", + "roles/ws/server-ws.c", + + "tls/tls.c", + "tls/tls-client.c", + "tls/tls-server.c", + + "tls/mbedtls/wrapper/library/ssl_cert.c", + "tls/mbedtls/wrapper/library/ssl_pkey.c", + "tls/mbedtls/wrapper/library/ssl_stack.c", + "tls/mbedtls/wrapper/library/ssl_methods.c", + "tls/mbedtls/wrapper/library/ssl_lib.c", + "tls/mbedtls/wrapper/library/ssl_x509.c", + "tls/mbedtls/wrapper/platform/ssl_port.c", + "tls/mbedtls/wrapper/platform/ssl_pm.c", + "tls/mbedtls/lws-genhash.c", + "tls/mbedtls/mbedtls-client.c", + "tls/mbedtls/lws-genrsa.c", + "tls/mbedtls/ssl.c", + "tls/mbedtls/mbedtls-server.c" + ] + + if env_lws["platform"] == "android": # Builtin getifaddrs + thirdparty_sources += ["misc/getifaddrs.c"] + + if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": # Winsock + thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"] + else: # Unix socket + thirdparty_sources += ["plat/lws-plat-unix.c"] + + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + if env_lws["platform"] == "javascript": # No need to add third party libraries at all + pass + else: + env_lws.add_source_files(env.modules_sources, thirdparty_sources) + env_lws.Append(CPPPATH=[thirdparty_dir]) + + wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]] + env_lws.Prepend(CPPPATH=wrapper_includes) + + if env['builtin_mbedtls']: + mbedtls_includes = "#thirdparty/mbedtls/include" + env_lws.Prepend(CPPPATH=[mbedtls_includes]) + + if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": + env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir]) + + if env_lws["platform"] == "uwp": + env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"]) env_lws.add_source_files(env.modules_sources, "*.cpp") diff --git a/platform/android/detect.py b/platform/android/detect.py index ada36e2814..0c6c9fdca3 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -128,7 +128,7 @@ def configure(env): env.extra_suffix = ".armv7" + env.extra_suffix elif env["android_arch"] == "arm64v8": if get_platform(env["ndk_platform"]) < 21: - print("WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than andorid-21; setting ndk_platform=android-21") + print("WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21") env["ndk_platform"] = "android-21" env['ARCH'] = 'arch-arm64' target_subpath = "aarch64-linux-android-4.9" diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp index 1f901c4919..aeaf698015 100644 --- a/platform/haiku/audio_driver_media_kit.cpp +++ b/platform/haiku/audio_driver_media_kit.cpp @@ -100,7 +100,7 @@ int AudioDriverMediaKit::get_mix_rate() const { return mix_rate; } -AudioDriverSW::SpeakerMode AudioDriverMediaKit::get_speaker_mode() const { +AudioDriverMediaKit::SpeakerMode AudioDriverMediaKit::get_speaker_mode() const { return speaker_mode; } diff --git a/platform/haiku/audio_driver_media_kit.h b/platform/haiku/audio_driver_media_kit.h index a09403e7d6..02fefcf52a 100644 --- a/platform/haiku/audio_driver_media_kit.h +++ b/platform/haiku/audio_driver_media_kit.h @@ -35,9 +35,10 @@ #include "core/os/mutex.h" #include "core/os/thread.h" -#include <SoundPlayer.h> #include <kernel/image.h> // needed for image_id +#include <SoundPlayer.h> + class AudioDriverMediaKit : public AudioDriver { Mutex *mutex; diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py index 2959023204..7ecdd2bb11 100644 --- a/platform/haiku/detect.py +++ b/platform/haiku/detect.py @@ -64,6 +64,87 @@ def configure(env): env["CC"] = "gcc-x86" env["CXX"] = "g++-x86" + ## Dependencies + + if not env['builtin_libwebp']: + env.ParseConfig('pkg-config libwebp --cflags --libs') + + # freetype depends on libpng and zlib, so bundling one of them while keeping others + # as shared libraries leads to weird issues + if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']: + env['builtin_freetype'] = True + env['builtin_libpng'] = True + env['builtin_zlib'] = True + + if not env['builtin_freetype']: + env.ParseConfig('pkg-config freetype2 --cflags --libs') + + if not env['builtin_libpng']: + env.ParseConfig('pkg-config libpng --cflags --libs') + + if not env['builtin_bullet']: + # We need at least version 2.88 + import subprocess + bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip() + if bullet_version < "2.88": + # Abort as system bullet was requested but too old + print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.88")) + sys.exit(255) + env.ParseConfig('pkg-config bullet --cflags --libs') + + if not env['builtin_enet']: + env.ParseConfig('pkg-config libenet --cflags --libs') + + if not env['builtin_squish'] and env['tools']: + env.ParseConfig('pkg-config libsquish --cflags --libs') + + if not env['builtin_zstd']: + env.ParseConfig('pkg-config libzstd --cflags --libs') + + # Sound and video libraries + # Keep the order as it triggers chained dependencies (ogg needed by others, etc.) + + if not env['builtin_libtheora']: + env['builtin_libogg'] = False # Needed to link against system libtheora + env['builtin_libvorbis'] = False # Needed to link against system libtheora + env.ParseConfig('pkg-config theora theoradec --cflags --libs') + + if not env['builtin_libvpx']: + env.ParseConfig('pkg-config vpx --cflags --libs') + + if not env['builtin_libvorbis']: + env['builtin_libogg'] = False # Needed to link against system libvorbis + env.ParseConfig('pkg-config vorbis vorbisfile --cflags --libs') + + if not env['builtin_opus']: + env['builtin_libogg'] = False # Needed to link against system opus + env.ParseConfig('pkg-config opus opusfile --cflags --libs') + + if not env['builtin_libogg']: + env.ParseConfig('pkg-config ogg --cflags --libs') + + if env['builtin_libtheora']: + list_of_x86 = ['x86_64', 'x86', 'i386', 'i586'] + if any(platform.machine() in s for s in list_of_x86): + env["x86_libtheora_opt_gcc"] = True + + if not env['builtin_libwebsockets']: + env.ParseConfig('pkg-config libwebsockets --cflags --libs') + + if not env['builtin_mbedtls']: + # mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228 + env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509']) + + if not env['builtin_miniupnpc']: + # No pkgconfig file so far, hardcode default paths. + env.Append(CPPPATH=["/system/develop/headers/x86/miniupnpc"]) + env.Append(LIBS=["miniupnpc"]) + + # On Linux wchar_t should be 32-bits + # 16-bit library shouldn't be required due to compiler optimisations + if not env['builtin_pcre2']: + env.ParseConfig('pkg-config libpcre2-32 --cflags --libs') + ## Flags env.Append(CPPPATH=['#platform/haiku']) diff --git a/platform/haiku/haiku_application.h b/platform/haiku/haiku_application.h index f92969bbb1..a870037985 100644 --- a/platform/haiku/haiku_application.h +++ b/platform/haiku/haiku_application.h @@ -31,9 +31,10 @@ #ifndef HAIKU_APPLICATION_H #define HAIKU_APPLICATION_H -#include <Application.h> #include <kernel/image.h> // needed for image_id +#include <Application.h> + class HaikuApplication : public BApplication { public: HaikuApplication(); diff --git a/platform/haiku/haiku_direct_window.cpp b/platform/haiku/haiku_direct_window.cpp index b234a2ff91..7eeb226167 100644 --- a/platform/haiku/haiku_direct_window.cpp +++ b/platform/haiku/haiku_direct_window.cpp @@ -41,10 +41,14 @@ HaikuDirectWindow::HaikuDirectWindow(BRect p_frame) : last_buttons_state = 0; last_button_mask = 0; last_key_modifier_state = 0; + + view = NULL; + update_runner = NULL; + input = NULL; + main_loop = NULL; } HaikuDirectWindow::~HaikuDirectWindow() { - delete update_runner; } void HaikuDirectWindow::SetHaikuGLView(HaikuGLView *p_view) { @@ -53,7 +57,7 @@ void HaikuDirectWindow::SetHaikuGLView(HaikuGLView *p_view) { void HaikuDirectWindow::StartMessageRunner() { update_runner = new BMessageRunner(BMessenger(this), - new BMessage(REDRAW_MSG), 1000000 / 30 /* 30 fps */); + new BMessage(REDRAW_MSG), 1000000 / 60 /* 60 fps */); } void HaikuDirectWindow::StopMessageRunner() { @@ -69,6 +73,7 @@ void HaikuDirectWindow::SetMainLoop(MainLoop *p_main_loop) { } bool HaikuDirectWindow::QuitRequested() { + StopMessageRunner(); main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST); return false; } @@ -152,39 +157,36 @@ void HaikuDirectWindow::HandleMouseButton(BMessage *message) { } */ - Ref<InputEvent> mouse_event; - mouse_event.type = Ref<InputEvent>::MOUSE_BUTTON; - mouse_event.device = 0; + Ref<InputEventMouseButton> mouse_event; + mouse_event.instance(); - mouse_event.mouse_button.mod = GetKeyModifierState(modifiers); - mouse_event->get_button_mask() = GetMouseButtonState(buttons); - mouse_event->get_position().x = where.x; - mouse_event->get_position().y = where.y; - mouse_event.mouse_button.global_x = where.x; - mouse_event.mouse_button.global_y = where.y; + mouse_event->set_button_mask(GetMouseButtonState(buttons)); + mouse_event->set_position({ where.x, where.y }); + mouse_event->set_global_position({ where.x, where.y }); + GetKeyModifierState(mouse_event, modifiers); switch (button) { default: case B_PRIMARY_MOUSE_BUTTON: - mouse_event->get_button_index() = 1; + mouse_event->set_button_index(1); break; case B_SECONDARY_MOUSE_BUTTON: - mouse_event->get_button_index() = 2; + mouse_event->set_button_index(2); break; case B_TERTIARY_MOUSE_BUTTON: - mouse_event->get_button_index() = 3; + mouse_event->set_button_index(3); break; } - mouse_event->is_pressed() = (message->what == B_MOUSE_DOWN); + mouse_event->set_pressed(message->what == B_MOUSE_DOWN); if (message->what == B_MOUSE_DOWN && mouse_event->get_button_index() == 1) { int32 clicks = message->FindInt32("clicks"); if (clicks > 1) { - mouse_event.mouse_button.doubleclick = true; + mouse_event->set_doubleclick(true); } } @@ -208,22 +210,18 @@ void HaikuDirectWindow::HandleMouseMoved(BMessage *message) { Point2i rel = pos - last_mouse_position; - Ref<InputEvent> motion_event; - motion_event.type = Ref<InputEvent>::MOUSE_MOTION; - motion_event.device = 0; + Ref<InputEventMouseMotion> motion_event; + motion_event.instance(); + GetKeyModifierState(motion_event, modifiers); - motion_event.mouse_motion.mod = GetKeyModifierState(modifiers); - motion_event->get_button_mask() = GetMouseButtonState(buttons); - motion_event.mouse_motion.x = pos.x; - motion_event.mouse_motion.y = pos.y; + motion_event->set_button_mask(GetMouseButtonState(buttons)); + motion_event->set_position({ pos.x, pos.y }); input->set_mouse_position(pos); - motion_event.mouse_motion.global_x = pos.x; - motion_event.mouse_motion.global_y = pos.y; - motion_event.mouse_motion.speed_x = input->get_last_mouse_speed().x; - motion_event.mouse_motion.speed_y = input->get_last_mouse_speed().y; + motion_event->set_global_position({ pos.x, pos.y }); + motion_event->set_speed({ input->get_last_mouse_speed().x, + input->get_last_mouse_speed().y }); - motion_event->get_relative().x = rel.x; - motion_event->get_relative().y = rel.y; + motion_event->set_relative({ rel.x, rel.y }); last_mouse_position = pos; @@ -236,22 +234,21 @@ void HaikuDirectWindow::HandleMouseWheelChanged(BMessage *message) { return; } - Ref<InputEvent> mouse_event; - mouse_event.type = Ref<InputEvent>::MOUSE_BUTTON; - mouse_event.device = 0; + Ref<InputEventMouseButton> mouse_event; + mouse_event.instance(); + //GetKeyModifierState(mouse_event, modifiers); - mouse_event->get_button_index() = wheel_delta_y < 0 ? 4 : 5; - mouse_event.mouse_button.mod = GetKeyModifierState(last_key_modifier_state); - mouse_event->get_button_mask() = last_button_mask; - mouse_event->get_position().x = last_mouse_position.x; - mouse_event->get_position().y = last_mouse_position.y; - mouse_event.mouse_button.global_x = last_mouse_position.x; - mouse_event.mouse_button.global_y = last_mouse_position.y; + mouse_event->set_button_index(wheel_delta_y < 0 ? 4 : 5); + mouse_event->set_button_mask(last_button_mask); + mouse_event->set_position({ last_mouse_position.x, + last_mouse_position.y }); + mouse_event->set_global_position({ last_mouse_position.x, + last_mouse_position.y }); - mouse_event->is_pressed() = true; + mouse_event->set_pressed(true); input->parse_input_event(mouse_event); - mouse_event->is_pressed() = false; + mouse_event->set_pressed(false); input->parse_input_event(mouse_event); } @@ -272,24 +269,23 @@ void HaikuDirectWindow::HandleKeyboardEvent(BMessage *message) { return; } - Ref<InputEvent> event; - event.type = Ref<InputEvent>::KEY; - event.device = 0; - event.key.mod = GetKeyModifierState(modifiers); - event->is_pressed() = (message->what == B_KEY_DOWN); - event->get_scancode() = KeyMappingHaiku::get_keysym(raw_char, key); - event->is_echo() = message->HasInt32("be:key_repeat"); - event.key.unicode = 0; + Ref<InputEventKey> event; + event.instance(); + GetKeyModifierState(event, modifiers); + event->set_pressed(message->what == B_KEY_DOWN); + event->set_scancode(KeyMappingHaiku::get_keysym(raw_char, key)); + event->set_echo(message->HasInt32("be:key_repeat")); + event->set_unicode(0); const char *bytes = NULL; if (message->FindString("bytes", &bytes) == B_OK) { - event.key.unicode = BUnicodeChar::FromUTF8(&bytes); + event->set_unicode(BUnicodeChar::FromUTF8(&bytes)); } //make it consistent across platforms. if (event->get_scancode() == KEY_BACKTAB) { - event->get_scancode() = KEY_TAB; - event->get_shift() = true; + event->set_scancode(KEY_TAB); + event->set_shift(true); } input->parse_input_event(event); @@ -309,14 +305,14 @@ void HaikuDirectWindow::HandleKeyboardModifierEvent(BMessage *message) { int32 key = old_modifiers ^ modifiers; - Ref<InputEvent> event; - event.type = Ref<InputEvent>::KEY; - event.device = 0; - event.key.mod = GetKeyModifierState(modifiers); - event->is_pressed() = ((modifiers & key) != 0); - event->get_scancode() = KeyMappingHaiku::get_modifier_keysym(key); - event->is_echo() = false; - event.key.unicode = 0; + Ref<InputEventWithModifiers> event; + event.instance(); + GetKeyModifierState(event, modifiers); + + event->set_shift(key & B_SHIFT_KEY); + event->set_alt(key & B_OPTION_KEY); + event->set_control(key & B_CONTROL_KEY); + event->set_command(key & B_COMMAND_KEY); input->parse_input_event(event); } @@ -333,14 +329,13 @@ void HaikuDirectWindow::HandleWindowResized(BMessage *message) { current_video_mode->height = height; } -inline InputModifierState HaikuDirectWindow::GetKeyModifierState(uint32 p_state) { +inline void HaikuDirectWindow::GetKeyModifierState(Ref<InputEventWithModifiers> event, uint32 p_state) { last_key_modifier_state = p_state; - InputModifierState state; - state.shift = (p_state & B_SHIFT_KEY) != 0; - state.control = (p_state & B_CONTROL_KEY) != 0; - state.alt = (p_state & B_OPTION_KEY) != 0; - state.meta = (p_state & B_COMMAND_KEY) != 0; + event->set_shift(p_state & B_SHIFT_KEY); + event->set_control(p_state & B_CONTROL_KEY); + event->set_alt(p_state & B_OPTION_KEY); + event->set_metakey(p_state & B_COMMAND_KEY); return state; } diff --git a/platform/haiku/haiku_direct_window.h b/platform/haiku/haiku_direct_window.h index 55c2f5fccc..eee09191fa 100644 --- a/platform/haiku/haiku_direct_window.h +++ b/platform/haiku/haiku_direct_window.h @@ -31,9 +31,10 @@ #ifndef HAIKU_DIRECT_WINDOW_H #define HAIKU_DIRECT_WINDOW_H -#include <DirectWindow.h> #include <kernel/image.h> // needed for image_id +#include <DirectWindow.h> + #include "core/os/os.h" #include "main/input_default.h" @@ -63,7 +64,7 @@ private: void HandleWindowResized(BMessage *message); void HandleKeyboardEvent(BMessage *message); void HandleKeyboardModifierEvent(BMessage *message); - inline InputModifierState GetKeyModifierState(uint32 p_state); + inline void GetKeyModifierState(Ref<InputEventWithModifiers> event, uint32 p_state); inline int GetMouseButtonState(uint32 p_state); public: diff --git a/platform/haiku/haiku_gl_view.h b/platform/haiku/haiku_gl_view.h index 1a694dc13b..6869cb7de7 100644 --- a/platform/haiku/haiku_gl_view.h +++ b/platform/haiku/haiku_gl_view.h @@ -31,9 +31,10 @@ #ifndef HAIKU_GL_VIEW_H #define HAIKU_GL_VIEW_H -#include <GLView.h> #include <kernel/image.h> // needed for image_id +#include <GLView.h> + class HaikuGLView : public BGLView { public: HaikuGLView(BRect frame, uint32 type); diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index 209cb5cec4..c80365f1f3 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -28,9 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "drivers/gles3/rasterizer_gles3.h" + #include "os_haiku.h" -#include "drivers/gles3/rasterizer_gles3.h" #include "main/main.h" #include "servers/physics/physics_server_sw.h" #include "servers/visual/visual_server_raster.h" @@ -111,13 +112,12 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p context_gl->initialize(); context_gl->make_current(); context_gl->set_use_vsync(current_video_mode.use_vsync); - - /* Port to GLES 3 rasterizer */ - //rasterizer = memnew(RasterizerGLES2); + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); #endif - visual_server = memnew(VisualServerRaster(rasterizer)); + visual_server = memnew(VisualServerRaster()); ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE); @@ -138,8 +138,6 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p AudioDriverManager::initialize(p_audio_driver); - power_manager = memnew(PowerHaiku); - return OK; } @@ -152,7 +150,6 @@ void OS_Haiku::finalize() { visual_server->finish(); memdelete(visual_server); - memdelete(rasterizer); memdelete(input); @@ -336,7 +333,7 @@ String OS_Haiku::get_config_path() const { if (has_environment("XDG_CONFIG_HOME")) { return get_environment("XDG_CONFIG_HOME"); } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".config"); + return get_environment("HOME").plus_file("config/settings"); } else { return "."; } @@ -347,7 +344,7 @@ String OS_Haiku::get_data_path() const { if (has_environment("XDG_DATA_HOME")) { return get_environment("XDG_DATA_HOME"); } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".local/share"); + return get_environment("HOME").plus_file("config/data"); } else { return get_config_path(); } @@ -358,8 +355,23 @@ String OS_Haiku::get_cache_path() const { if (has_environment("XDG_CACHE_HOME")) { return get_environment("XDG_CACHE_HOME"); } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".cache"); + return get_environment("HOME").plus_file("config/cache"); } else { return get_config_path(); } } + +OS::PowerState OS_Haiku::get_power_state() { + WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN"); + return OS::POWERSTATE_UNKNOWN; +} + +int OS_Haiku::get_power_seconds_left() { + WARN_PRINT("Power management is not implemented on this platform, defaulting to -1"); + return -1; +} + +int OS_Haiku::get_power_percent_left() { + WARN_PRINT("Power management is not implemented on this platform, defaulting to -1"); + return -1; +} diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index 13d4420bde..e862eb44c3 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -37,9 +37,7 @@ #include "haiku_application.h" #include "haiku_direct_window.h" #include "main/input_default.h" -#include "power_haiku.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" class OS_Haiku : public OS_Unix { @@ -48,11 +46,9 @@ private: HaikuDirectWindow *window; MainLoop *main_loop; InputDefault *input; - Rasterizer *rasterizer; VisualServer *visual_server; VideoMode current_video_mode; int video_driver_index; - PowerHaiku *power_manager; #ifdef MEDIA_KIT_ENABLED AudioDriverMediaKit driver_media_kit; diff --git a/platform/haiku/platform_config.h b/platform/haiku/platform_config.h index bbd72dfeb6..72c8ee2535 100644 --- a/platform/haiku/platform_config.h +++ b/platform/haiku/platform_config.h @@ -34,3 +34,4 @@ #define _BSD_SOURCE 1 #define GLES3_INCLUDE_H "glad/glad.h" +#define GLES2_INCLUDE_H "glad/glad.h" diff --git a/platform/haiku/power_haiku.cpp b/platform/haiku/power_haiku.cpp deleted file mode 100644 index 2a26dd0f9c..0000000000 --- a/platform/haiku/power_haiku.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************/ -/* power_haiku.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "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. */ -/*************************************************************************/ - -#include "core/error_macros.h" - -#include "power_haiku.h" - -bool PowerHaiku::UpdatePowerInfo() { - - return false; -} - -OS::PowerState PowerHaiku::get_power_state() { - if (UpdatePowerInfo()) { - return power_state; - } else { - WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN"); - return OS::POWERSTATE_UNKNOWN; - } -} - -int PowerX11::get_power_seconds_left() { - if (UpdatePowerInfo()) { - return nsecs_left; - } else { - WARN_PRINT("Power management is not implemented on this platform, defaulting to -1"); - return -1; - } -} - -int PowerX11::get_power_percent_left() { - if (UpdatePowerInfo()) { - return percent_left; - } else { - WARN_PRINT("Power management is not implemented on this platform, defaulting to -1"); - return -1; - } -} - -PowerHaiku::PowerHaiku() : - nsecs_left(-1), - percent_left(-1), - power_state(OS::POWERSTATE_UNKNOWN) { -} - -PowerHaiku::~PowerHaiku() { -} diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 3b48063fe9..89f71f0013 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -31,7 +31,7 @@ #ifndef OSUWP_H #define OSUWP_H -#include "core/math/math_2d.h" +#include "core/math/transform_2d.h" #include "core/ustring.h" #include "drivers/xaudio2/audio_driver_xaudio2.h" #include "gl_context_egl.h" diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 033654323b..d6cfd039d9 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2789,23 +2789,17 @@ bool OS_Windows::is_disable_crash_handler() const { } Error OS_Windows::move_to_trash(const String &p_path) { - SHFILEOPSTRUCTA sf; - TCHAR *from = new TCHAR[p_path.length() + 2]; - strcpy(from, p_path.utf8().get_data()); - from[p_path.length()] = 0; - from[p_path.length() + 1] = 0; - + SHFILEOPSTRUCTW sf; sf.hwnd = hWnd; sf.wFunc = FO_DELETE; - sf.pFrom = from; + sf.pFrom = p_path.c_str(); sf.pTo = NULL; sf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION; sf.fAnyOperationsAborted = FALSE; sf.hNameMappings = NULL; sf.lpszProgressTitle = NULL; - int ret = SHFileOperation(&sf); - delete[] from; + int ret = SHFileOperationW(&sf); if (ret) { ERR_PRINTS("SHFileOperation error: " + itos(ret)); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 9d1e3291b7..a1e844898e 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -1339,7 +1339,7 @@ void OS_X11::request_attention() { // // Sets the _NET_WM_STATE_DEMANDS_ATTENTION atom for WM_STATE // Will be unset by the window manager after user react on the request for attention - // + XEvent xev; Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); Atom wm_attention = XInternAtom(x11_display, "_NET_WM_STATE_DEMANDS_ATTENTION", False); @@ -1353,6 +1353,7 @@ void OS_X11::request_attention() { xev.xclient.data.l[1] = wm_attention; XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + XFlush(x11_display); } void OS_X11::get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state) { @@ -2436,7 +2437,19 @@ String OS_X11::get_system_dir(SystemDir p_dir) const { void OS_X11::move_window_to_foreground() { - XRaiseWindow(x11_display, x11_window); + XEvent xev; + Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = x11_window; + xev.xclient.message_type = net_active_window; + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; + xev.xclient.data.l[1] = CurrentTime; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + XFlush(x11_display); } void OS_X11::set_cursor_shape(CursorShape p_shape) { diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index b1c62f84e2..edfdf97c47 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -33,8 +33,8 @@ #include "color.h" #include "line_2d.h" -#include "math_2d.h" #include "scene/resources/color_ramp.h" +#include "vector2.h" class LineBuilder { public: diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 7252602a93..7de72dc41d 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -443,7 +443,7 @@ void Node2D::_bind_methods() { ADD_GROUP("Transform", ""); ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform"); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index c9e5408f06..34f4ccc03e 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -29,8 +29,10 @@ /*************************************************************************/ #include "polygon_2d.h" + #include "core/math/geometry.h" #include "skeleton_2d.h" + Dictionary Polygon2D::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); state["offset"] = offset; @@ -646,7 +648,7 @@ void Polygon2D::_bind_methods() { ADD_GROUP("Texture", "texture_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset"), "set_texture_offset", "get_texture_offset"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1"), "set_texture_rotation_degrees", "get_texture_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation"); ADD_GROUP("Skeleton", ""); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton"); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 84a0fb9b1d..e53ccb4cf4 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -2042,6 +2042,8 @@ void PhysicalBone::_bind_methods() { ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics); + ClassDB::bind_method(D_METHOD("get_bone_id"), &PhysicalBone::get_bone_id); + ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone::set_mass); ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone::get_mass); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 2782354432..a660665d3f 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1644,7 +1644,7 @@ void AnimationPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "current_animation_position", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_position"); ADD_GROUP("Playback Options", "playback_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_animation_process_mode", "get_animation_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", 0), "set_active", "is_active"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale"); @@ -1656,6 +1656,7 @@ void AnimationPlayer::_bind_methods() { BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE); + BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL); } AnimationPlayer::AnimationPlayer() { diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 49c73e54ad..f50b2454ec 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -65,6 +65,7 @@ public: enum AnimationProcessMode { ANIMATION_PROCESS_PHYSICS, ANIMATION_PROCESS_IDLE, + ANIMATION_PROCESS_MANUAL, }; private: diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index de9f82dadc..8bbc05eed3 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -1199,6 +1199,11 @@ void AnimationTree::_process_graph(float p_delta) { } } +void AnimationTree::advance(float p_time) { + + _process_graph(p_time); +} + void AnimationTree::_notification(int p_what) { if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) { @@ -1310,17 +1315,20 @@ void AnimationTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform); + ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance); + ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_tree_root", "get_tree_root"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode"); ADD_GROUP("Root Motion", "root_motion_"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track"); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE); + BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL); } AnimationTree::AnimationTree() { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 540c36437a..87092a4a0e 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -133,6 +133,7 @@ public: enum AnimationProcessMode { ANIMATION_PROCESS_PHYSICS, ANIMATION_PROCESS_IDLE, + ANIMATION_PROCESS_MANUAL, }; private: @@ -271,6 +272,8 @@ public: Transform get_root_motion_transform() const; + void advance(float p_time); + uint64_t get_last_process_pass() const; AnimationTree(); ~AnimationTree(); diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 81fdc32788..58be636e44 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -204,7 +204,7 @@ void Tween::_bind_methods() { ClassDB::bind_method(D_METHOD("resume", "object", "key"), &Tween::resume, DEFVAL("")); ClassDB::bind_method(D_METHOD("resume_all"), &Tween::resume_all); ClassDB::bind_method(D_METHOD("remove", "object", "key"), &Tween::remove, DEFVAL("")); - ClassDB::bind_method(D_METHOD("_remove", "object", "key", "first_only"), &Tween::_remove); + ClassDB::bind_method(D_METHOD("_remove_by_uid", "uid"), &Tween::_remove_by_uid); ClassDB::bind_method(D_METHOD("remove_all"), &Tween::remove_all); ClassDB::bind_method(D_METHOD("seek", "time"), &Tween::seek); ClassDB::bind_method(D_METHOD("tell"), &Tween::tell); @@ -615,7 +615,7 @@ void Tween::_tween_process(float p_delta) { emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false)); // not repeat mode, remove completed action if (!repeat) - call_deferred("_remove", object, NodePath(Vector<StringName>(), data.key, false), true); + call_deferred("_remove_by_uid", data.uid); } else if (!repeat) all_finished = all_finished && data.finish; } @@ -778,15 +778,9 @@ bool Tween::resume_all() { } bool Tween::remove(Object *p_object, StringName p_key) { - _remove(p_object, p_key, false); - return true; -} - -void Tween::_remove(Object *p_object, StringName p_key, bool first_only) { - if (pending_update != 0) { - call_deferred("_remove", p_object, p_key, first_only); - return; + call_deferred("remove", p_object, p_key); + return true; } List<List<InterpolateData>::Element *> for_removal; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { @@ -797,14 +791,33 @@ void Tween::_remove(Object *p_object, StringName p_key, bool first_only) { continue; if (object == p_object && (data.concatenated_key == p_key || p_key == "")) { for_removal.push_back(E); - if (first_only) { - break; - } } } for (List<List<InterpolateData>::Element *>::Element *E = for_removal.front(); E; E = E->next()) { interpolates.erase(E->get()); } + return true; +} + +void Tween::_remove_by_uid(int uid) { + if (pending_update != 0) { + call_deferred("_remove_by_uid", uid); + return; + } + + for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { + if (uid == E->get().uid) { + E->erase(); + break; + } + } +} + +void Tween::_push_interpolate_data(InterpolateData &p_data) { + pending_update++; + p_data.uid = ++uid; + interpolates.push_back(p_data); + pending_update--; } bool Tween::remove_all() { @@ -815,6 +828,7 @@ bool Tween::remove_all() { } set_active(false); interpolates.clear(); + uid = 0; return true; } @@ -1027,7 +1041,7 @@ bool Tween::interpolate_property(Object *p_object, NodePath p_property, Variant if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) return false; - interpolates.push_back(data); + _push_interpolate_data(data); return true; } @@ -1070,7 +1084,7 @@ bool Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_ if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) return false; - interpolates.push_back(data); + _push_interpolate_data(data); return true; } @@ -1122,9 +1136,7 @@ bool Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_c data.arg[3] = p_arg4; data.arg[4] = p_arg5; - pending_update++; - interpolates.push_back(data); - pending_update--; + _push_interpolate_data(data); return true; } @@ -1175,9 +1187,7 @@ bool Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, S data.arg[3] = p_arg4; data.arg[4] = p_arg5; - pending_update++; - interpolates.push_back(data); - pending_update--; + _push_interpolate_data(data); return true; } @@ -1232,7 +1242,7 @@ bool Tween::follow_property(Object *p_object, NodePath p_property, Variant p_ini data.ease_type = p_ease_type; data.delay = p_delay; - interpolates.push_back(data); + _push_interpolate_data(data); return true; } @@ -1283,7 +1293,7 @@ bool Tween::follow_method(Object *p_object, StringName p_method, Variant p_initi data.ease_type = p_ease_type; data.delay = p_delay; - interpolates.push_back(data); + _push_interpolate_data(data); return true; } @@ -1341,7 +1351,7 @@ bool Tween::targeting_property(Object *p_object, NodePath p_property, Object *p_ if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) return false; - interpolates.push_back(data); + _push_interpolate_data(data); return true; } @@ -1396,7 +1406,7 @@ bool Tween::targeting_method(Object *p_object, StringName p_method, Object *p_in if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) return false; - interpolates.push_back(data); + _push_interpolate_data(data); return true; } @@ -1407,6 +1417,7 @@ Tween::Tween() { repeat = false; speed_scale = 1; pending_update = 0; + uid = 0; } Tween::~Tween() { diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 9997349c64..aa47c00717 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -100,6 +100,7 @@ private: real_t delay; int args; Variant arg[5]; + int uid; }; String autoplay; @@ -107,6 +108,7 @@ private: bool repeat; float speed_scale; mutable int pending_update; + int uid; List<InterpolateData> interpolates; @@ -131,7 +133,8 @@ private: bool _apply_tween_value(InterpolateData &p_data, Variant &value); void _tween_process(float p_delta); - void _remove(Object *p_object, StringName p_key, bool first_only); + void _remove_by_uid(int uid); + void _push_interpolate_data(InterpolateData &p_data); protected: bool _set(const StringName &p_name, const Variant &p_value); diff --git a/scene/gui/control.h b/scene/gui/control.h index 6bea04345b..c6bd2f097d 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -31,13 +31,13 @@ #ifndef CONTROL_H #define CONTROL_H -#include "math_2d.h" #include "rid.h" #include "scene/2d/canvas_item.h" #include "scene/gui/shortcut.h" #include "scene/main/node.h" #include "scene/main/timer.h" #include "scene/resources/theme.h" +#include "transform_2d.h" /** @author Juan Linietsky <reduzio@gmail.com> */ diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 5c79741682..d61bd97c2a 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1423,6 +1423,9 @@ void ItemList::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_custom_bg_color", "idx", "custom_bg_color"), &ItemList::set_item_custom_bg_color); ClassDB::bind_method(D_METHOD("get_item_custom_bg_color", "idx"), &ItemList::get_item_custom_bg_color); + ClassDB::bind_method(D_METHOD("set_item_custom_fg_color", "idx", "custom_fg_color"), &ItemList::set_item_custom_fg_color); + ClassDB::bind_method(D_METHOD("get_item_custom_fg_color", "idx"), &ItemList::get_item_custom_fg_color); + ClassDB::bind_method(D_METHOD("set_item_tooltip_enabled", "idx", "enable"), &ItemList::set_item_tooltip_enabled); ClassDB::bind_method(D_METHOD("is_item_tooltip_enabled", "idx"), &ItemList::is_item_tooltip_enabled); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index ab762e19ee..436dda41a4 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1049,10 +1049,8 @@ void PopupMenu::activate_item(int p_item) { ERR_FAIL_INDEX(p_item, items.size()); ERR_FAIL_COND(items[p_item].separator); int id = items[p_item].ID >= 0 ? items[p_item].ID : p_item; - emit_signal("id_pressed", id); - emit_signal("index_pressed", p_item); - //hide all parent PopupMenue's + //hide all parent PopupMenus Node *next = get_parent(); PopupMenu *pop = Object::cast_to<PopupMenu>(next); while (pop) { @@ -1076,16 +1074,23 @@ void PopupMenu::activate_item(int p_item) { // Hides popup by default; unless otherwise specified // by using set_hide_on_item_selection and set_hide_on_checkable_item_selection + bool need_hide = true; + if (items[p_item].checkable_type) { if (!hide_on_checkable_item_selection) - return; + need_hide = false; } else if (0 < items[p_item].max_states) { if (!hide_on_multistate_item_selection) - return; + need_hide = false; } else if (!hide_on_item_selection) - return; + need_hide = false; - hide(); + emit_signal("id_pressed", id); + emit_signal("index_pressed", p_item); + + if (need_hide) { + hide(); + } } void PopupMenu::remove_item(int p_idx) { @@ -1098,6 +1103,7 @@ void PopupMenu::remove_item(int p_idx) { items.remove(p_idx); update(); + minimum_size_changed(); } void PopupMenu::add_separator(const String &p_text) { diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 4062e48640..09d8664240 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -260,8 +260,8 @@ void Range::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "ratio", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_as_ratio", "get_as_ratio"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exp_edit"), "set_exp_ratio", "is_ratio_exp"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rounded"), "set_use_rounded_values", "is_using_rounded_values"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "allow_greater"), "set_allow_greater", "is_greater_allowed"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_greater"), "set_allow_greater", "is_greater_allowed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed"); } void Range::set_use_rounded_values(bool p_enable) { diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp index 5e25f43daf..74e68598f4 100644 --- a/scene/gui/reference_rect.cpp +++ b/scene/gui/reference_rect.cpp @@ -39,9 +39,25 @@ void ReferenceRect::_notification(int p_what) { if (!is_inside_tree()) return; if (Engine::get_singleton()->is_editor_hint()) - draw_style_box(get_stylebox("border"), Rect2(Point2(), get_size())); + draw_rect(Rect2(Point2(), get_size()), border_color, false); } } +void ReferenceRect::set_border_color(const Color &color) { + border_color = color; +} + +Color ReferenceRect::get_border_color() const { + return border_color; +} + +void ReferenceRect::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_border_color"), &ReferenceRect::get_border_color); + ClassDB::bind_method(D_METHOD("set_border_color", "color"), &ReferenceRect::set_border_color); + + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color"); +} + ReferenceRect::ReferenceRect() { + border_color = Color(1, 0, 0); } diff --git a/scene/gui/reference_rect.h b/scene/gui/reference_rect.h index 473e348c85..9fad1a06b0 100644 --- a/scene/gui/reference_rect.h +++ b/scene/gui/reference_rect.h @@ -36,12 +36,17 @@ class ReferenceRect : public Control { GDCLASS(ReferenceRect, Control); + Color border_color; protected: void _notification(int p_what); + static void _bind_methods(); public: ReferenceRect(); + + void set_border_color(const Color &color); + Color get_border_color() const; }; #endif // REFERENCE_RECT_H diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c702bc70d0..9a8dc62e4e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2200,9 +2200,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { k->set_shift(false); } - if (!k->get_command()) { - _reset_caret_blink_timer(); - } + _reset_caret_blink_timer(); // save here for insert mode, just in case it is cleared in the following section bool had_selection = selection.active; @@ -5770,8 +5768,11 @@ void TextEdit::_update_completion_candidates() { } // Calculate the similarity to keep completions in good order float similarity; - if (completion_strings[i].to_lower().begins_with(s.to_lower())) { - // Substrings are the best candidates + if (completion_strings[i].begins_with(s)) { + // Substrings (same case) are the best candidates + similarity = 1.2; + } else if (completion_strings[i].to_lower().begins_with(s.to_lower())) { + // then any substrings similarity = 1.1; } else { // Otherwise compute the similarity diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 8414210952..a2e890e7a7 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -248,12 +248,10 @@ void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_custom_viewport"), &CanvasLayer::get_custom_viewport); ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasLayer::get_canvas); - //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasLayer::get_viewport); ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer"); - //ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"transform",PROPERTY_HINT_RANGE),"set_transform","get_transform") ; ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 6144240328..d6a80bfb1a 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2555,6 +2555,9 @@ void Node::clear_internal_tree_resource_paths() { String Node::get_configuration_warning() const { + if (get_script_instance() && get_script_instance()->has_method("_get_configuration_warning")) { + return get_script_instance()->call("_get_configuration_warning"); + } return String(); } @@ -2763,6 +2766,7 @@ void Node::_bind_methods() { BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_configuration_warning")); //ClassDB::bind_method(D_METHOD("get_child",&Node::get_child,PH("index"))); //ClassDB::bind_method(D_METHOD("get_node",&Node::get_node,PH("path"))); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index e717d27069..e4ef373c77 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -31,11 +31,11 @@ #ifndef VIEWPORT_H #define VIEWPORT_H -#include "math_2d.h" #include "scene/main/node.h" #include "scene/resources/texture.h" #include "scene/resources/world_2d.h" #include "servers/visual_server.h" +#include "transform_2d.h" /** @author Juan Linietsky <reduzio@gmail.com> */ diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index ec1aa7ec46..39206ed043 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "bit_mask.h" + #include "io/image_loader.h" void BitMap::create(const Size2 &p_size) { @@ -189,13 +190,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) { //square value /* - checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent - +---+---+ - | 1 | 2 | - +---+---+ - | 4 | 8 | <- current pixel (curx,cury) - +---+---+ - */ + checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent + +---+---+ + | 1 | 2 | + +---+---+ + | 4 | 8 | <- current pixel (curx,cury) + +---+---+ + */ //NOTE: due to the way we pick points from texture, rect needs to be smaller, otherwise it goes outside 1 pixel Rect2i fixed_rect = Rect2i(rect.position, rect.size - Size2i(2, 2)); Point2i tl = Point2i(curx - 1, cury - 1); @@ -215,13 +216,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) case 5: case 13: /* going UP with these cases: - 1 5 13 - +---+---+ +---+---+ +---+---+ - | 1 | | | 1 | | | 1 | | - +---+---+ +---+---+ +---+---+ - | | | | 4 | | | 4 | 8 | - +---+---+ +---+---+ +---+---+ - */ + 1 5 13 + +---+---+ +---+---+ +---+---+ + | 1 | | | 1 | | | 1 | | + +---+---+ +---+---+ +---+---+ + | | | | 4 | | | 4 | 8 | + +---+---+ +---+---+ +---+---+ + */ stepx = 0; stepy = -1; break; @@ -230,13 +231,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) case 10: case 11: /* going DOWN with these cases: - 8 10 11 - +---+---+ +---+---+ +---+---+ - | | | | | 2 | | 1 | 2 | - +---+---+ +---+---+ +---+---+ - | | 8 | | | 8 | | | 8 | - +---+---+ +---+---+ +---+---+ - */ + 8 10 11 + +---+---+ +---+---+ +---+---+ + | | | | | 2 | | 1 | 2 | + +---+---+ +---+---+ +---+---+ + | | 8 | | | 8 | | | 8 | + +---+---+ +---+---+ +---+---+ + */ stepx = 0; stepy = 1; break; @@ -245,13 +246,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) case 12: case 14: /* going LEFT with these cases: - 4 12 14 - +---+---+ +---+---+ +---+---+ - | | | | | | | | 2 | - +---+---+ +---+---+ +---+---+ - | 4 | | | 4 | 8 | | 4 | 8 | - +---+---+ +---+---+ +---+---+ - */ + 4 12 14 + +---+---+ +---+---+ +---+---+ + | | | | | | | | 2 | + +---+---+ +---+---+ +---+---+ + | 4 | | | 4 | 8 | | 4 | 8 | + +---+---+ +---+---+ +---+---+ + */ stepx = -1; stepy = 0; break; @@ -260,25 +261,25 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) case 3: case 7: /* going RIGHT with these cases: - 2 3 7 - +---+---+ +---+---+ +---+---+ - | | 2 | | 1 | 2 | | 1 | 2 | - +---+---+ +---+---+ +---+---+ - | | | | | | | 4 | | - +---+---+ +---+---+ +---+---+ - */ + 2 3 7 + +---+---+ +---+---+ +---+---+ + | | 2 | | 1 | 2 | | 1 | 2 | + +---+---+ +---+---+ +---+---+ + | | | | | | | 4 | | + +---+---+ +---+---+ +---+---+ + */ stepx = 1; stepy = 0; break; case 9: /* - +---+---+ - | 1 | | - +---+---+ - | | 8 | - +---+---+ - this should normally go UP, but if we already been here, we go down - */ + +---+---+ + | 1 | | + +---+---+ + | | 8 | + +---+---+ + this should normally go UP, but if we already been here, we go down + */ if (case9s.has(Point2i(curx, cury))) { //found, so we go down, and delete from case9s; stepx = 0; @@ -293,14 +294,14 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) break; case 6: /* - 6 - +---+---+ - | | 2 | - +---+---+ - | 4 | | - +---+---+ - this normally go RIGHT, but if its coming from UP, it should go LEFT - */ + 6 + +---+---+ + | | 2 | + +---+---+ + | 4 | | + +---+---+ + this normally go RIGHT, but if its coming from UP, it should go LEFT + */ if (case6s.has(Point2i(curx, cury))) { //found, so we go down, and delete from case6s; stepx = -1; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 2d05f5e19f..0eee2ae393 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -867,7 +867,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxTexture> ttnc = make_stylebox(full_panel_bg_png, 8, 8, 8, 8); ttnc->set_draw_center(false); - theme->set_stylebox("border", "ReferenceRect", make_stylebox(reference_border_png, 4, 4, 4, 4)); theme->set_stylebox("panelnc", "Panel", ttnc); theme->set_stylebox("panelf", "Panel", tc_sb); diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h index dfe48d94cf..c69e44a7da 100644 --- a/scene/resources/physics_material.h +++ b/scene/resources/physics_material.h @@ -37,7 +37,7 @@ class PhysicsMaterial : public Resource { GDCLASS(PhysicsMaterial, Resource); OBJ_SAVE_TYPE(PhysicsMaterial); - RES_BASE_EXTENSION("PhyMat"); + RES_BASE_EXTENSION("phymat"); real_t friction; bool rough; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 536c653a0c..96edb17eea 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -214,9 +214,10 @@ Image::Format ImageTexture::get_format() const { return format; } - +#ifndef DISABLE_DEPRECATED Error ImageTexture::load(const String &p_path) { + WARN_DEPRECATED Ref<Image> img; img.instance(); Error err = img->load(p_path); @@ -225,7 +226,7 @@ Error ImageTexture::load(const String &p_path) { } return err; } - +#endif void ImageTexture::set_data(const Ref<Image> &p_image) { ERR_FAIL_COND(p_image.is_null()); @@ -345,7 +346,9 @@ void ImageTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "width", "height", "format", "flags"), &ImageTexture::create, DEFVAL(FLAGS_DEFAULT)); ClassDB::bind_method(D_METHOD("create_from_image", "image", "flags"), &ImageTexture::create_from_image, DEFVAL(FLAGS_DEFAULT)); ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("load", "path"), &ImageTexture::load); +#endif ClassDB::bind_method(D_METHOD("set_data", "image"), &ImageTexture::set_data); ClassDB::bind_method(D_METHOD("set_storage", "mode"), &ImageTexture::set_storage); ClassDB::bind_method(D_METHOD("get_storage"), &ImageTexture::get_storage); @@ -618,7 +621,11 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla memdelete(f); - if (bytes != total_size - ofs) { + int expected = total_size - ofs; + if (bytes < expected) { + //this is a compatibility workaround for older format, which saved less mipmaps. It is still recommended the image is reimported. + zeromem(w.ptr() + bytes, (expected - bytes)); + } else if (bytes != expected) { ERR_FAIL_V(ERR_FILE_CORRUPT); } } diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 1c18189b2c..c1331fb3fe 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -33,9 +33,9 @@ #include "curve.h" #include "io/resource_loader.h" -#include "math_2d.h" #include "os/mutex.h" #include "os/thread_safe.h" +#include "rect2.h" #include "resource.h" #include "scene/resources/color_ramp.h" #include "servers/visual_server.h" @@ -125,7 +125,9 @@ public: void set_flags(uint32_t p_flags); uint32_t get_flags() const; Image::Format get_format() const; +#ifndef DISABLE_DEPRECATED Error load(const String &p_path); +#endif void set_data(const Ref<Image> &p_image); Ref<Image> get_data() const; diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 14318f282b..f3934e5c01 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -143,14 +143,19 @@ AudioDriver::AudioDriver() { #endif } -AudioDriver *AudioDriverManager::drivers[MAX_DRIVERS]; -int AudioDriverManager::driver_count = 0; AudioDriverDummy AudioDriverManager::dummy_driver; +AudioDriver *AudioDriverManager::drivers[MAX_DRIVERS] = { + &AudioDriverManager::dummy_driver, +}; +int AudioDriverManager::driver_count = 1; void AudioDriverManager::add_driver(AudioDriver *p_driver) { ERR_FAIL_COND(driver_count >= MAX_DRIVERS); - drivers[driver_count++] = p_driver; + drivers[driver_count - 1] = p_driver; + + // Last driver is always our dummy driver + drivers[driver_count++] = &AudioDriverManager::dummy_driver; } int AudioDriverManager::get_driver_count() { @@ -183,14 +188,6 @@ void AudioDriverManager::initialize(int p_driver) { return; } } - - // Fallback to our dummy driver - if (dummy_driver.init() == OK) { - ERR_PRINT("AudioDriverManager: all drivers failed, falling back to dummy driver"); - dummy_driver.set_singleton(); - } else { - ERR_PRINT("AudioDriverManager: dummy driver failed to init()"); - } } AudioDriver *AudioDriverManager::get_driver(int p_driver) { diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/broad_phase_2d_sw.h index 80ae970624..d7d236c4c6 100644 --- a/servers/physics_2d/broad_phase_2d_sw.h +++ b/servers/physics_2d/broad_phase_2d_sw.h @@ -31,8 +31,8 @@ #ifndef BROAD_PHASE_2D_SW_H #define BROAD_PHASE_2D_SW_H -#include "math_2d.h" #include "math_funcs.h" +#include "rect2.h" class CollisionObject2DSW; diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp index d49c1b8376..517dce0043 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/joints_2d_sw.cpp @@ -321,7 +321,7 @@ void GrooveJoint2DSW::solve(real_t p_step) { Vector2 jOld = jn_acc; j += jOld; - jn_acc = (((clamp * j.cross(xf_normal)) > 0) ? j : xf_normal.project(j)).clamped(jn_max); + jn_acc = (((clamp * j.cross(xf_normal)) > 0) ? j : j.project(xf_normal)).clamped(jn_max); j = jn_acc - jOld; diff --git a/servers/visual_server.h b/servers/visual_server.h index 0ec902c18c..fd7f96339e 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -34,9 +34,9 @@ #include "bsp_tree.h" #include "geometry.h" #include "image.h" -#include "math_2d.h" #include "object.h" #include "rid.h" +#include "transform_2d.h" #include "variant.h" /** diff --git a/thirdparty/b2d_convexdecomp/b2Glue.h b/thirdparty/b2d_convexdecomp/b2Glue.h index 425486356e..10c2f62361 100644 --- a/thirdparty/b2d_convexdecomp/b2Glue.h +++ b/thirdparty/b2d_convexdecomp/b2Glue.h @@ -19,7 +19,7 @@ #ifndef B2GLUE_H #define B2GLUE_H -#include "math_2d.h" +#include "vector2.h" #include <limits.h> namespace b2ConvexDecomp { diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c index dd6fe8b8f3..35469e9031 100644 --- a/thirdparty/glad/glad.c +++ b/thirdparty/glad/glad.c @@ -77,7 +77,7 @@ void close_gl(void) { #include <dlfcn.h> static void* libGL; -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__HAIKU__) typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; #endif @@ -100,7 +100,7 @@ int open_gl(void) { libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); if(libGL != NULL) { -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(__HAIKU__) return 1; #else gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, @@ -127,7 +127,7 @@ void* get_proc(const char *namez) { void* result = NULL; if(libGL == NULL) return NULL; -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__HAIKU__) if(gladGetProcAddressPtr != NULL) { result = gladGetProcAddressPtr(namez); } diff --git a/thirdparty/libwebsockets/lws_config.h b/thirdparty/libwebsockets/lws_config.h index 7185a806a5..e5e15cc2fd 100644 --- a/thirdparty/libwebsockets/lws_config.h +++ b/thirdparty/libwebsockets/lws_config.h @@ -174,7 +174,7 @@ #define LWS_HAVE_MALLOC_H #endif -#if !defined(IPHONE_ENABLED) && !defined(OSX_ENABLED) +#if !defined(IPHONE_ENABLED) && !defined(OSX_ENABLED) && !defined(__HAIKU__) #define LWS_HAVE_PIPE2 #endif diff --git a/thirdparty/libwebsockets/lws_config_private.h b/thirdparty/libwebsockets/lws_config_private.h index 9d04078fef..b26d225afa 100644 --- a/thirdparty/libwebsockets/lws_config_private.h +++ b/thirdparty/libwebsockets/lws_config_private.h @@ -81,7 +81,7 @@ /* Define to 1 if you have the <sys/prctl.h> header file. */ #define LWS_HAVE_SYS_PRCTL_H -#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) || defined(__FreeBSD__) || defined(__OpenBSD__) +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) #undef LWS_HAVE_SYS_PRCTL_H #endif diff --git a/thirdparty/misc/triangulator.h b/thirdparty/misc/triangulator.h index b6dd7e8236..d1538cfae5 100644 --- a/thirdparty/misc/triangulator.h +++ b/thirdparty/misc/triangulator.h @@ -21,9 +21,9 @@ #ifndef TRIANGULATOR_H #define TRIANGULATOR_H -#include "math_2d.h" #include "list.h" #include "set.h" +#include "vector2.h" //2D point structure diff --git a/thirdparty/thekla_atlas/nvcore/nvcore.h b/thirdparty/thekla_atlas/nvcore/nvcore.h index a3deb66be2..5ef69668d9 100644 --- a/thirdparty/thekla_atlas/nvcore/nvcore.h +++ b/thirdparty/thekla_atlas/nvcore/nvcore.h @@ -44,6 +44,9 @@ #elif defined POSH_OS_FREEBSD # define NV_OS_FREEBSD 1 # define NV_OS_UNIX 1 +#elif defined POSH_OS_HAIKU +# define NV_OS_HAIKU 1 +# define NV_OS_UNIX 1 #elif defined POSH_OS_OPENBSD # define NV_OS_OPENBSD 1 # define NV_OS_UNIX 1 @@ -341,7 +344,7 @@ template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N]; #elif NV_CC_GNUC # if NV_OS_LINUX # include "DefsGnucLinux.h" -# elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD +# elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_HAIKU # include "DefsGnucDarwin.h" # elif NV_OS_ORBIS # include "DefsOrbis.h" diff --git a/thirdparty/thekla_atlas/poshlib/posh.h b/thirdparty/thekla_atlas/poshlib/posh.h index 3038297b39..72acd20ce0 100644 --- a/thirdparty/thekla_atlas/poshlib/posh.h +++ b/thirdparty/thekla_atlas/poshlib/posh.h @@ -298,6 +298,11 @@ Metrowerks: # define POSH_OS_STRING "Linux" #endif +#if defined __HAIKU__ +# define POSH_OS_HAIKU 1 +# define POSH_OS_STRING "Haiku" +#endif + #if defined __FreeBSD__ # define POSH_OS_FREEBSD 1 # define POSH_OS_STRING "FreeBSD" |