diff options
110 files changed, 2546 insertions, 1393 deletions
diff --git a/SConstruct b/SConstruct index dbce94f296..88b29695cb 100644 --- a/SConstruct +++ b/SConstruct @@ -168,7 +168,6 @@ opts.Add(BoolVariable('vsproj', "Generate Visual Studio Project.", False)) opts.Add(EnumVariable('warnings', "Set the level of warnings emitted during compilation", 'no', ('extra', 'all', 'moderate', 'no'))) opts.Add(BoolVariable('progress', "Show a progress indicator during build", True)) opts.Add(BoolVariable('dev', "If yes, alias for verbose=yes warnings=all", False)) -opts.Add(BoolVariable('openmp', "If yes, enable OpenMP", True)) opts.Add(EnumVariable('macports_clang', "Build using clang from MacPorts", 'no', ('no', '5.0', 'devel'))) # Thirdparty libraries diff --git a/core/global_constants.cpp b/core/global_constants.cpp index a8f6e4da6c..b390590cf2 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -98,6 +98,11 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(MARGIN_RIGHT); BIND_GLOBAL_ENUM_CONSTANT(MARGIN_BOTTOM); + BIND_GLOBAL_ENUM_CONSTANT(CORNER_TOP_LEFT); + BIND_GLOBAL_ENUM_CONSTANT(CORNER_TOP_RIGHT); + BIND_GLOBAL_ENUM_CONSTANT(CORNER_BOTTOM_RIGHT); + BIND_GLOBAL_ENUM_CONSTANT(CORNER_BOTTOM_LEFT); + BIND_GLOBAL_ENUM_CONSTANT(VERTICAL); BIND_GLOBAL_ENUM_CONSTANT(HORIZONTAL); @@ -573,6 +578,38 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3_ARRAY", Variant::POOL_VECTOR3_ARRAY); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_COLOR_ARRAY", Variant::POOL_COLOR_ARRAY); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_MAX", Variant::VARIANT_MAX); + + //comparation + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_EQUAL", Variant::OP_EQUAL); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NOT_EQUAL", Variant::OP_NOT_EQUAL); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_LESS", Variant::OP_LESS); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_LESS_EQUAL", Variant::OP_LESS_EQUAL); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_GREATER", Variant::OP_GREATER); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_GREATER_EQUAL", Variant::OP_GREATER_EQUAL); + //mathematic + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_ADD", Variant::OP_ADD); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SUBTRACT", Variant::OP_SUBTRACT); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MULTIPLY", Variant::OP_MULTIPLY); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_DIVIDE", Variant::OP_DIVIDE); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_STRING_CONCAT", Variant::OP_STRING_CONCAT); + //bitwise + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_AND", Variant::OP_BIT_AND); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_OR", Variant::OP_BIT_OR); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_XOR", Variant::OP_BIT_XOR); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_NEGATE", Variant::OP_BIT_NEGATE); + //logic + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_AND", Variant::OP_AND); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_OR", Variant::OP_OR); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_XOR", Variant::OP_XOR); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NOT", Variant::OP_NOT); + //containment + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_IN", Variant::OP_IN); + BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MAX", Variant::OP_MAX); } void unregister_global_constants() { diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 4498efeb41..7c5dbc895a 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -459,7 +459,7 @@ void AStar::_bind_methods() { ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar::has_point); ClassDB::bind_method(D_METHOD("get_points"), &AStar::get_points); - ClassDB::bind_method(D_METHOD("get_point_connections"), &AStar::get_point_connections); + ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar::get_point_connections); ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true)); ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar::disconnect_points); diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp index 11003c1cd5..8ad164d4dc 100644 --- a/core/math/math_2d.cpp +++ b/core/math/math_2d.cpp @@ -102,69 +102,6 @@ Vector2 Vector2::cross(real_t p_other) const { return Vector2(p_other * y, -p_other * x); } -Vector2 Vector2::operator+(const Vector2 &p_v) const { - - return Vector2(x + p_v.x, y + p_v.y); -} -void Vector2::operator+=(const Vector2 &p_v) { - - x += p_v.x; - y += p_v.y; -} -Vector2 Vector2::operator-(const Vector2 &p_v) const { - - return Vector2(x - p_v.x, y - p_v.y); -} -void Vector2::operator-=(const Vector2 &p_v) { - - x -= p_v.x; - y -= p_v.y; -} - -Vector2 Vector2::operator*(const Vector2 &p_v1) const { - - return Vector2(x * p_v1.x, y * p_v1.y); -}; - -Vector2 Vector2::operator*(const real_t &rvalue) const { - - return Vector2(x * rvalue, y * rvalue); -}; -void Vector2::operator*=(const real_t &rvalue) { - - x *= rvalue; - y *= rvalue; -}; - -Vector2 Vector2::operator/(const Vector2 &p_v1) const { - - return Vector2(x / p_v1.x, y / p_v1.y); -}; - -Vector2 Vector2::operator/(const real_t &rvalue) const { - - return Vector2(x / rvalue, y / rvalue); -}; - -void Vector2::operator/=(const real_t &rvalue) { - - x /= rvalue; - y /= rvalue; -}; - -Vector2 Vector2::operator-() const { - - return Vector2(-x, -y); -} - -bool Vector2::operator==(const Vector2 &p_vec2) const { - - return x == p_vec2.x && y == p_vec2.y; -} -bool Vector2::operator!=(const Vector2 &p_vec2) const { - - return x != p_vec2.x || y != p_vec2.y; -} Vector2 Vector2::floor() const { return Vector2(Math::floor(x), Math::floor(y)); diff --git a/core/math/math_2d.h b/core/math/math_2d.h index 60351445c0..4635a4da55 100644 --- a/core/math/math_2d.h +++ b/core/math/math_2d.h @@ -187,6 +187,70 @@ _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; @@ -336,9 +400,10 @@ struct Rect2 { g.size.height += p_by * 2; return g; } + inline Rect2 grow_margin(Margin p_margin, real_t p_amount) const { Rect2 g = *this; - g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0, + 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); diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index ab3bca79ae..5346141470 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -311,6 +311,15 @@ void Basis::rotate(const Vector3 &p_axis, real_t p_phi) { *this = rotated(p_axis, p_phi); } +void Basis::rotate_local(const Vector3 &p_axis, real_t p_phi) { + + *this = rotated_local(p_axis, p_phi); +} +Basis Basis::rotated_local(const Vector3 &p_axis, real_t p_phi) const { + + return (*this) * Basis(p_axis, p_phi); +} + Basis Basis::rotated(const Vector3 &p_euler) const { return Basis(p_euler) * (*this); } diff --git a/core/math/matrix3.h b/core/math/matrix3.h index 9a33b8203d..9a75308f08 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -75,6 +75,9 @@ public: void rotate(const Vector3 &p_axis, real_t p_phi); Basis rotated(const Vector3 &p_axis, real_t p_phi) const; + void rotate_local(const Vector3 &p_axis, real_t p_phi); + Basis rotated_local(const Vector3 &p_axis, real_t p_phi) const; + void rotate(const Vector3 &p_euler); Basis rotated(const Vector3 &p_euler) const; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 9b2bd30868..0cab8c10ef 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -32,14 +32,6 @@ #include "input_map.h" #include "os/keyboard.h" -void InputEvent::set_id(uint32_t p_id) { - id = p_id; -} - -uint32_t InputEvent::get_id() const { - return id; -} - void InputEvent::set_device(int p_device) { device = p_device; } @@ -99,9 +91,6 @@ bool InputEvent::is_action_type() const { void InputEvent::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_id", "id"), &InputEvent::set_id); - ClassDB::bind_method(D_METHOD("get_id"), &InputEvent::get_id); - ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device); ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device); @@ -125,7 +114,6 @@ void InputEvent::_bind_methods() { InputEvent::InputEvent() { - id = 0; device = 0; } @@ -441,7 +429,6 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co Ref<InputEventMouseButton> mb; mb.instance(); - mb->set_id(get_id()); mb->set_device(get_device()); mb->set_modifiers_from_event(this); @@ -557,7 +544,6 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co Ref<InputEventMouseMotion> mm; mm.instance(); - mm->set_id(get_id()); mm->set_device(get_device()); mm->set_modifiers_from_event(this); @@ -764,7 +750,6 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co Ref<InputEventScreenTouch> st; st.instance(); - st->set_id(get_id()); st->set_device(get_device()); st->set_index(index); st->set_position(p_xform.xform(pos + p_local_ofs)); @@ -845,7 +830,6 @@ Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, con sd.instance(); - sd->set_id(get_id()); sd->set_device(get_device()); sd->set_index(index); @@ -968,7 +952,6 @@ Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform, Ref<InputEventMagnifyGesture> ev; ev.instance(); - ev->set_id(get_id()); ev->set_device(get_device()); ev->set_modifiers_from_event(this); @@ -1006,7 +989,6 @@ Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, con Ref<InputEventPanGesture> ev; ev.instance(); - ev->set_id(get_id()); ev->set_device(get_device()); ev->set_modifiers_from_event(this); diff --git a/core/os/input_event.h b/core/os/input_event.h index 614a3289ba..9b1a2736b1 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -144,16 +144,12 @@ enum JoystickList { class InputEvent : public Resource { GDCLASS(InputEvent, Resource) - uint32_t id; int device; protected: static void _bind_methods(); public: - void set_id(uint32_t p_id); - uint32_t get_id() const; - void set_device(int p_device); int get_device() const; diff --git a/core/os/threaded_array_processor.cpp b/core/os/threaded_array_processor.cpp new file mode 100644 index 0000000000..8e92508ea5 --- /dev/null +++ b/core/os/threaded_array_processor.cpp @@ -0,0 +1,2 @@ +#include "threaded_array_processor.h" + diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h new file mode 100644 index 0000000000..e584fbb193 --- /dev/null +++ b/core/os/threaded_array_processor.h @@ -0,0 +1,80 @@ +#ifndef THREADED_ARRAY_PROCESSOR_H +#define THREADED_ARRAY_PROCESSOR_H + +#include "os/mutex.h" +#include "os/os.h" +#include "os/thread.h" +#include "safe_refcount.h" +#include "thread_safe.h" + +template <class C, class U> +struct ThreadArrayProcessData { + uint32_t elements; + uint32_t index; + C *instance; + U userdata; + void (C::*method)(uint32_t, U); + + void process(uint32_t p_index) { + (instance->*method)(p_index, userdata); + } +}; + +#ifndef NO_THREADS + +template <class T> +void process_array_thread(void *ud) { + + T &data = *(T *)ud; + while (true) { + uint32_t index = atomic_increment(&data.index); + if (index >= data.elements) + break; + data.process(index); + } +} + +template <class C, class M, class U> +void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { + + ThreadArrayProcessData<C, U> data; + data.method = p_method; + data.instance = p_instance; + data.userdata = p_userdata; + data.index = 0; + data.elements = p_elements; + data.process(data.index); //process first, let threads increment for next + + Vector<Thread *> threads; + + threads.resize(OS::get_singleton()->get_processor_count()); + + for (int i = 0; i < threads.size(); i++) { + threads[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U> >, &data); + } + + for (int i = 0; i < threads.size(); i++) { + Thread::wait_to_finish(threads[i]); + memdelete(threads[i]); + } +} + +#else + +template <class C, class M, class U> +void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { + + ThreadArrayProcessData<C, U> data; + data.method = p_method; + data.instance = p_instance; + data.userdata = p_userdata; + data.index = 0; + data.elements = p_elements; + for (uint32_t i = 0; i < p_elements; i++) { + data.process(i); + } +} + +#endif + +#endif // THREADED_ARRAY_PROCESSOR_H diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index 185460eef2..87d00b7600 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -11,14 +11,14 @@ <demos> </demos> <methods> - <method name="get_picker"> + <method name="get_picker" qualifiers="const"> <return type="ColorPicker"> </return> <description> Returns the [code]ColorPicker[/code] that this [code]ColorPickerButton[/code] toggles. </description> </method> - <method name="get_popup"> + <method name="get_popup" qualifiers="const"> <return type="PopupPanel"> </return> <description> diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml index c41c86d693..22231cfdf3 100644 --- a/doc/classes/MenuButton.xml +++ b/doc/classes/MenuButton.xml @@ -11,7 +11,7 @@ <demos> </demos> <methods> - <method name="get_popup"> + <method name="get_popup" qualifiers="const"> <return type="PopupMenu"> </return> <description> diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index 76265e700a..ff3e513c79 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -91,6 +91,13 @@ Return the text of the item at index "idx". </description> </method> + <method name="get_popup" qualifiers="const"> + <return type="PopupMenu"> + </return> + <description> + Return the [PopupMenu] contained in this button. + </description> + </method> <method name="get_selected_id" qualifiers="const"> <return type="int"> </return> diff --git a/doc/classes/Physics2DDirectSpaceState.xml b/doc/classes/Physics2DDirectSpaceState.xml index f63b8f17bc..2e2d8e95f9 100644 --- a/doc/classes/Physics2DDirectSpaceState.xml +++ b/doc/classes/Physics2DDirectSpaceState.xml @@ -17,8 +17,8 @@ <argument index="0" name="shape" type="Physics2DShapeQueryParameters"> </argument> <description> - Check whether the shape can travel to a point. If it can, the method will return an array with two floats: The first is the distance the shape can move in that direction without colliding, and the second is the distance at which it will collide. - If the shape can not move, the array will be empty. + Checks how far the shape can travel toward a point. Note that both the shape and the motion are supplied through a [Physics2DShapeQueryParameters] object. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [1, 1]. + If the shape can not move, the array will be empty ([code]dir.empty()==true[/code]). </description> </method> <method name="collide_shape"> @@ -29,7 +29,7 @@ <argument index="1" name="max_results" type="int" default="32"> </argument> <description> - Check the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time. + Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time. </description> </method> <method name="get_rest_info"> @@ -38,16 +38,15 @@ <argument index="0" name="shape" type="Physics2DShapeQueryParameters"> </argument> <description> - Check the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. If it collides with more than a shape, the nearest one is selected. The returned object is a dictionary containing the following fields: - pointo: Place where the shapes intersect. - normal: Normal of the object at the point where the shapes intersect. - shape: Shape index within the object against which the shape intersected. - metadata: Metadata of the shape against which the shape intersected. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data]. - collider_id: Id of the object against which the shape intersected. - collider: Object against which the shape intersected. - rid: [RID] of the object against which the shape intersected. - linear_velocity: The movement vector of the object the shape intersected, if it was a body. If it was an area, it is (0,0). - If the shape did not intersect anything, then an empty dictionary (dir.empty()==true) is returned instead. + Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. If it collides with more than one shape, the nearest one is selected. Note that this method does not take into account the [code]motion[/code] property of the object. The returned object is a dictionary containing the following fields: + [code]collider_id[/code]: The colliding object's ID. + [code]linear_velocity[/code]: The colliding object's velocity [Vector2]. If the object is an [Area2D], the result is [code](0, 0)[/code]. + [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data]. + [code]normal[/code]: The object's surface normal at the intersection point. + [code]point[/code]: The intersection point. + [code]rid[/code]: The intersecting object's [RID]. + [code]shape[/code]: The shape index of the colliding shape. + If the shape did not intersect anything, then an empty dictionary ([code]dir.empty()==true[/code]) is returned instead. </description> </method> <method name="intersect_point"> @@ -62,12 +61,12 @@ <argument index="3" name="collision_layer" type="int" default="2147483647"> </argument> <description> - Check whether a point is inside any shape. The shapes the point is inside of are returned in an array containing dictionaries with the following fields: - shape: Shape index within the object the point is in. - metadata: Metadata of the shape the point is in. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data]. - collider_id: Id of the object the point is in. - collider: Object the point is inside of. - rid: [RID] of the object the point is in. + Checks whether a point is inside any shape. The shapes the point is inside of are returned in an array containing dictionaries with the following fields: + [code]collider[/code]: The colliding object. + [code]collider_id[/code]: The colliding object's ID. + [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data]. + [code]rid[/code]: The intersecting object's [RID]. + [code]shape[/code]: The shape index of the colliding shape. Additionally, the method can take an array of objects or [RID]s that are to be excluded from collisions, or a bitmask representing the physics layers to check in. </description> </method> @@ -83,15 +82,15 @@ <argument index="3" name="collision_layer" type="int" default="2147483647"> </argument> <description> - Intersect a ray in a given space. The returned object is a dictionary with the following fields: - position: Place where ray is stopped. - normal: Normal of the object at the point where the ray was stopped. - shape: Shape index within the object against which the ray was stopped. - metadata: Metadata of the shape against which the ray was stopped. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data]. - collider_id: Id of the object against which the ray was stopped. - collider: Object against which the ray was stopped. - rid: [RID] of the object against which the ray was stopped. - If the ray did not intersect anything, then an empty dictionary (dir.empty()==true) is returned instead. + Intersects a ray in a given space. The returned object is a dictionary with the following fields: + [code]collider[/code]: The colliding object. + [code]collider_id[/code]: The colliding object's ID. + [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data]. + [code]normal[/code]: The object's surface normal at the intersection point. + [code]position[/code]: The intersection point. + [code]rid[/code]: The intersecting object's [RID]. + [code]shape[/code]: The shape index of the colliding shape. + If the ray did not intersect anything, then an empty dictionary ([code]dir.empty()==true[/code]) is returned instead. Additionally, the method can take an array of objects or [RID]s that are to be excluded from collisions, or a bitmask representing the physics layers to check in. </description> </method> @@ -103,12 +102,12 @@ <argument index="1" name="max_results" type="int" default="32"> </argument> <description> - Check the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. The intersected shapes are returned in an array containing dictionaries with the following fields: - shape: Shape index within the object the shape intersected. - metadata: Metadata of the shape intersected by the shape given through the [Physics2DShapeQueryParameters]. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data]. - collider_id: Id of the object the shape intersected. - collider: Object the shape intersected. - rid: [RID] of the object the shape intersected. + Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. Note that this method does not take into account the [code]motion[/code] property of the object. The intersected shapes are returned in an array containing dictionaries with the following fields: + [code]collider[/code]: The colliding object. + [code]collider_id[/code]: The colliding object's ID. + [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data]. + [code]rid[/code]: The intersecting object's [RID]. + [code]shape[/code]: The shape index of the colliding shape. The number of intersections can be limited with the second parameter, to reduce the processing time. </description> </method> diff --git a/doc/classes/PhysicsDirectSpaceState.xml b/doc/classes/PhysicsDirectSpaceState.xml index 21576646f9..d93550eb47 100644 --- a/doc/classes/PhysicsDirectSpaceState.xml +++ b/doc/classes/PhysicsDirectSpaceState.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="PhysicsDirectSpaceState" inherits="Object" category="Core" version="3.0-beta"> <brief_description> + Direct access object to a space in the [PhysicsServer]. </brief_description> <description> + Direct access object to a space in the [PhysicsServer]. It's used mainly to do queries against objects and areas residing in a given space. </description> <tutorials> </tutorials> @@ -17,6 +19,8 @@ <argument index="1" name="motion" type="Vector3"> </argument> <description> + Checks whether the shape can travel to a point. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [1, 1]. + If the shape can not move, the array will be empty ([code]dir.empty()==true[/code]). </description> </method> <method name="collide_shape"> @@ -27,6 +31,7 @@ <argument index="1" name="max_results" type="int" default="32"> </argument> <description> + Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time. </description> </method> <method name="get_rest_info"> @@ -35,6 +40,14 @@ <argument index="0" name="shape" type="PhysicsShapeQueryParameters"> </argument> <description> + Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. If it collides with more than a shape, the nearest one is selected. The returned object is a dictionary containing the following fields: + [code]collider_id[/code]: The colliding object's ID. + [code]linear_velocity[/code]: The colliding object's velocity [Vector3]. If the object is an [Area], the result is [code](0, 0, 0)[/code]. + [code]normal[/code]: The object's surface normal at the intersection point. + [code]point[/code]: The intersection point. + [code]rid[/code]: The intersecting object's [RID]. + [code]shape[/code]: The shape index of the colliding shape. + If the shape did not intersect anything, then an empty dictionary ([code]dir.empty()==true[/code]) is returned instead. </description> </method> <method name="intersect_ray"> @@ -49,6 +62,15 @@ <argument index="3" name="collision_layer" type="int" default="2147483647"> </argument> <description> + Intersects a ray in a given space. The returned object is a dictionary with the following fields: + [code]collider[/code]: The colliding object. + [code]collider_id[/code]: The colliding object's ID. + [code]normal[/code]: The object's surface normal at the intersection point. + [code]position[/code]: The intersection point. + [code]rid[/code]: The intersecting object's [RID]. + [code]shape[/code]: The shape index of the colliding shape. + If the ray did not intersect anything, then an empty dictionary ([code]dir.empty()==true[/code]) is returned instead. + Additionally, the method can take an array of objects or [RID]s that are to be excluded from collisions, or a bitmask representing the physics layers to check in. </description> </method> <method name="intersect_shape"> @@ -59,6 +81,12 @@ <argument index="1" name="max_results" type="int" default="32"> </argument> <description> + Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. The intersected shapes are returned in an array containing dictionaries with the following fields: + [code]collider[/code]: The colliding object. + [code]collider_id[/code]: The colliding object's ID. + [code]rid[/code]: The intersecting object's [RID]. + [code]shape[/code]: The shape index of the colliding shape. + The number of intersections can be limited with the second parameter, to reduce the processing time. </description> </method> </methods> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 85cbeaaa03..ab722a24c3 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -345,18 +345,28 @@ </methods> <members> <member name="caret_blink" type="bool" setter="cursor_set_blink_enabled" getter="cursor_get_blink_enabled"> + If [code]true[/code] the caret (visual cursor) blinks. </member> <member name="caret_blink_speed" type="float" setter="cursor_set_blink_speed" getter="cursor_get_blink_speed"> + Duration (in seconds) of a caret's blinking cycle. </member> <member name="caret_block_mode" type="bool" setter="cursor_set_block_mode" getter="cursor_is_block_mode"> + If [code]true[/code] the caret displays as a rectangle. + If [code]false[/code] the caret displays as a bar. + </member> + <member name="caret_moving_by_right_click" type="bool" setter="set_right_click_moves_caret" getter="is_right_click_moving_caret"> + If [code]true[/code] a right click moves the cursor at the mouse position before displaying the context menu. + If [code]false[/code] the context menu disregards mouse location. </member> <member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled"> + If [code]true[/code] a right click displays the context menu. </member> <member name="hiding_enabled" type="int" setter="set_hiding_enabled" getter="is_hiding_enabled"> </member> <member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled"> </member> <member name="highlight_current_line" type="bool" setter="set_highlight_current_line" getter="is_highlight_current_line_enabled"> + If [code]true[/code] the line containing the cursor is highlighted. </member> <member name="override_selected_font_color" type="bool" setter="set_override_selected_font_color" getter="is_overriding_selected_font_color"> </member> @@ -364,6 +374,7 @@ If [code]true[/code] read-only mode is enabled. Existing text cannot be modified and new text cannot be added. </member> <member name="show_line_numbers" type="bool" setter="set_show_line_numbers" getter="is_show_line_numbers_enabled"> + If [code]true[/code] line numbers are displayed to the left of the text. </member> <member name="smooth_scrolling" type="bool" setter="set_smooth_scroll_enable" getter="is_smooth_scroll_enabled"> </member> @@ -419,16 +430,22 @@ Search from end to beginning. </constant> <constant name="MENU_CUT" value="0" enum="MenuItems"> + Cuts (Copies and clears) the selected text. </constant> <constant name="MENU_COPY" value="1" enum="MenuItems"> + Copies the selected text. </constant> <constant name="MENU_PASTE" value="2" enum="MenuItems"> + Pastes the clipboard text over the selected text (or at the cursor's position). </constant> <constant name="MENU_CLEAR" value="3" enum="MenuItems"> + Erases the whole [TextEdit] text. </constant> <constant name="MENU_SELECT_ALL" value="4" enum="MenuItems"> + Selects the whole [TextEdit] text. </constant> <constant name="MENU_UNDO" value="5" enum="MenuItems"> + Undoes the previous action. </constant> <constant name="MENU_MAX" value="6" enum="MenuItems"> </constant> diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml index 17576f33ed..f4717aa995 100644 --- a/doc/classes/Transform2D.xml +++ b/doc/classes/Transform2D.xml @@ -4,7 +4,7 @@ 2D Transformation. 3x2 matrix. </brief_description> <description> - Represents one or many transformations in 3D space such as translation, rotation, or scaling. It consists of a two [Vector2] x, y and [Vector2] "origin". It is similar to a 3x2 matrix. + Represents one or many transformations in 2D space such as translation, rotation, or scaling. It consists of a two [Vector2] x, y and [Vector2] "origin". It is similar to a 3x2 matrix. </description> <tutorials> </tutorials> @@ -17,7 +17,7 @@ <argument index="0" name="from" type="Transform"> </argument> <description> - Constructs the [code]Transform2D[/code] from a 3D [Transform]. + Constructs the transform from a 3D [Transform]. </description> </method> <method name="Transform2D"> @@ -30,7 +30,7 @@ <argument index="2" name="origin" type="Vector2"> </argument> <description> - Constructs the [code]Transform2D[/code] from 3 [Vector2] consisting of rows x, y and origin. + Constructs the transform from 3 [Vector2]s representing x, y, and origin. </description> </method> <method name="Transform2D"> @@ -41,7 +41,7 @@ <argument index="1" name="position" type="Vector2"> </argument> <description> - Constructs the [code]Transform2D[/code] from rotation angle in radians and position [Vector2]. + Constructs the transform from a given angle (in radians) and position. </description> </method> <method name="affine_inverse"> @@ -57,7 +57,7 @@ <argument index="0" name="v" type="var"> </argument> <description> - Transforms the given vector "v" by this transform basis (no translation). + Transforms the given vector by this transform's basis (no translation). </description> </method> <method name="basis_xform_inv"> @@ -66,21 +66,21 @@ <argument index="0" name="v" type="var"> </argument> <description> - Inverse-transforms the given vector "v" by this transform basis (no translation). + Inverse-transforms the given vector by this transform's basis (no translation). </description> </method> <method name="get_origin"> <return type="Vector2"> </return> <description> - Returns the origin [Vector2] (translation). + Returns the transform's origin (translation). </description> </method> <method name="get_rotation"> <return type="float"> </return> <description> - Returns the rotation (in radians). + Returns the transform's rotation (in radians). </description> </method> <method name="get_scale"> @@ -98,7 +98,7 @@ <argument index="1" name="weight" type="float"> </argument> <description> - Interpolates the transform to other Transform2D by weight amount (0-1). + Returns a transform interpolated between this transform and another by a given weight (0-1). </description> </method> <method name="inverse"> @@ -121,7 +121,7 @@ <argument index="0" name="phi" type="float"> </argument> <description> - Rotates the transform by phi. + Rotates the transform by the given angle (in radians). </description> </method> <method name="scaled"> @@ -130,7 +130,7 @@ <argument index="0" name="scale" type="Vector2"> </argument> <description> - Scales the transform by the specified 2D scaling factors. + Scales the transform by the given factor. </description> </method> <method name="translated"> @@ -139,7 +139,7 @@ <argument index="0" name="offset" type="Vector2"> </argument> <description> - Translates the transform by the specified offset. + Translates the transform by the given offset. </description> </method> <method name="xform"> @@ -163,13 +163,13 @@ </methods> <members> <member name="origin" type="Vector2" setter="" getter=""> - The translation offset of the transform. + The transform's translation offset. </member> <member name="x" type="Vector2" setter="" getter=""> - The X axis of 2x2 basis matrix containing 2 [Vector2] as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object. + The X axis of 2x2 basis matrix containing 2 [Vector2]s as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object. </member> <member name="y" type="Vector2" setter="" getter=""> - The Y axis of 2x2 basis matrix containing 2 [Vector2] as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object. + The Y axis of 2x2 basis matrix containing 2 [Vector2]s as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object. </member> </members> <constants> diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index a4daa77b50..86415ea740 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1086,19 +1086,22 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons } } - if (shader_ptr && shader_ptr != shader_cache) { + if (shader_ptr) { if (shader_ptr->canvas_item.uses_screen_texture && !state.canvas_texscreen_used) { //copy if not copied before _copy_texscreen(Rect2()); } - if (shader_ptr->canvas_item.uses_time) { - VisualServerRaster::redraw_request(); - } + if (shader_ptr != shader_cache) { - state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); - state.canvas_shader.bind(); + if (shader_ptr->canvas_item.uses_time) { + VisualServerRaster::redraw_request(); + } + + state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); + state.canvas_shader.bind(); + } if (material_ptr->ubo_id) { glBindBufferBase(GL_UNIFORM_BUFFER, 2, material_ptr->ubo_id); @@ -1147,7 +1150,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons glBindTexture(t->target, t->tex_id); } - } else if (!shader_ptr) { + } else { state.canvas_shader.set_custom_shader(0); state.canvas_shader.bind(); } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index b777f9343a..1c3361d2de 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1541,7 +1541,19 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) { - const RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(c.texture); + RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(c.texture); + + t = t->get_ptr(); //resolve for proxies +#ifdef TOOLS_ENABLED + if (t->detect_3d) { + t->detect_3d(t->detect_3d_ud); + } +#endif + + if (t->render_target) { + t->render_target->used_in_frame = true; + } + glActiveTexture(GL_TEXTURE0); glBindTexture(t->target, t->tex_id); restore_tex = true; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 101978548d..ec00c057b2 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -806,7 +806,6 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer"; - actions[VS::SHADER_SPATIAL].renames["SIDE"] = "side"; actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; //for light @@ -847,6 +846,8 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index bb9ff29a8e..6427e3d967 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -174,7 +174,7 @@ void light_compute(vec3 N, vec3 L,vec3 V, vec3 light_color, float roughness, ino vec3 H = normalize(V + L); float dotNH = max(dot(N,H), 0.0 ); - float intensity = pow( dotNH, (1.0-roughness) * 256.0); + float intensity = (roughness >= 1.0 ? 1.0 : pow( dotNH, (1.0-roughness) * 256.0)); specular += light_color * intensity; } @@ -1615,7 +1615,7 @@ void main() { float alpha = 1.0; -#ifdef METERIAL_DOUBLESIDED +#if defined(DO_SIDE_CHECK) float side=float(gl_FrontFacing)*2.0-1.0; #else float side=1.0; diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 2584d26fc4..e904fd94be 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -267,7 +267,6 @@ void CreateDialog::_update_search() { if (EditorNode::get_editor_data().get_custom_types().has(type) && ClassDB::is_parent_class(type, base_type)) { //there are custom types based on this... cool. - //print_line("there are custom types"); const Vector<EditorData::CustomType> &ct = EditorNode::get_editor_data().get_custom_types()[type]; for (int i = 0; i < ct.size(); i++) { @@ -630,31 +629,40 @@ CreateDialog::CreateDialog() { set_resizable(true); - HSplitContainer *hbc = memnew(HSplitContainer); + HSplitContainer *hsc = memnew(HSplitContainer); + add_child(hsc); - add_child(hbc); + VSplitContainer *vsc = memnew(VSplitContainer); + hsc->add_child(vsc); - VBoxContainer *lvbc = memnew(VBoxContainer); - hbc->add_child(lvbc); - lvbc->set_custom_minimum_size(Size2(150, 0) * EDSCALE); + VBoxContainer *fav_vb = memnew(VBoxContainer); + vsc->add_child(fav_vb); + fav_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE); + fav_vb->set_v_size_flags(SIZE_EXPAND_FILL); favorites = memnew(Tree); - lvbc->add_margin_child(TTR("Favorites:"), favorites, true); + fav_vb->add_margin_child(TTR("Favorites:"), favorites, true); favorites->set_hide_root(true); favorites->set_hide_folding(true); favorites->connect("cell_selected", this, "_favorite_selected"); favorites->connect("item_activated", this, "_favorite_activated"); favorites->set_drag_forwarding(this); + VBoxContainer *rec_vb = memnew(VBoxContainer); + vsc->add_child(rec_vb); + rec_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE); + rec_vb->set_v_size_flags(SIZE_EXPAND_FILL); + recent = memnew(Tree); - lvbc->add_margin_child(TTR("Recent:"), recent, true); + rec_vb->add_margin_child(TTR("Recent:"), recent, true); recent->set_hide_root(true); recent->set_hide_folding(true); recent->connect("cell_selected", this, "_history_selected"); recent->connect("item_activated", this, "_history_activated"); VBoxContainer *vbc = memnew(VBoxContainer); - hbc->add_child(vbc); + hsc->add_child(vbc); + vbc->set_custom_minimum_size(Size2(300, 0) * EDSCALE); vbc->set_h_size_flags(SIZE_EXPAND_FILL); HBoxContainer *search_hb = memnew(HBoxContainer); search_box = memnew(LineEdit); @@ -676,7 +684,6 @@ CreateDialog::CreateDialog() { set_hide_on_ok(false); search_options->connect("item_activated", this, "_confirmed"); search_options->connect("cell_selected", this, "_item_selected"); - //search_options->set_hide_root(true); base_type = "Object"; preferred_search_result_type = ""; diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 5f026abb6d..6db3c09673 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -145,7 +145,7 @@ EditorAbout::EditorAbout() { List<String> dev_sections; dev_sections.push_back(TTR("Project Founders")); dev_sections.push_back(TTR("Lead Developer")); - dev_sections.push_back(TTR("Project Manager")); + dev_sections.push_back(TTR("Project Manager ")); // " " appended to distinguish between 'project supervisor' and 'project list' dev_sections.push_back(TTR("Developers")); const char **dev_src[] = { dev_founders, dev_lead, dev_manager, dev_names }; tc->add_child(_populate_list(TTR("Authors"), dev_sections, dev_src, 1)); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 49d55e6305..214b1cac89 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -701,6 +701,15 @@ String EditorData::get_scene_title(int p_idx) const { return name; } +void EditorData::set_scene_path(int p_idx, const String &p_path) { + + ERR_FAIL_INDEX(p_idx, edited_scene.size()); + + if (!edited_scene[p_idx].root) + return; + edited_scene[p_idx].root->set_filename(p_path); +} + String EditorData::get_scene_path(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String()); diff --git a/editor/editor_data.h b/editor/editor_data.h index 33a4091a65..f15b7e37f1 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -185,6 +185,7 @@ public: String get_scene_title(int p_idx) const; String get_scene_path(int p_idx) const; String get_scene_type(int p_idx) const; + void set_scene_path(int p_idx, const String &p_path); Ref<Script> get_scene_root_script(int p_idx) const; void set_edited_scene_version(uint64_t version, int p_scene_idx = -1); uint64_t get_edited_scene_version() const; diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index deba16a524..4bf138354d 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -54,7 +54,7 @@ void EditorFileDialog::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - //_update_icons + // update icons mode_thumbnails->set_icon(get_icon("FileThumbnail", "EditorIcons")); mode_list->set_icon(get_icon("FileList", "EditorIcons")); dir_prev->set_icon(get_icon("Back", "EditorIcons")); @@ -65,7 +65,6 @@ void EditorFileDialog::_notification(int p_what) { fav_up->set_icon(get_icon("MoveUp", "EditorIcons")); fav_down->set_icon(get_icon("MoveDown", "EditorIcons")); - fav_rm->set_icon(get_icon("Remove", "EditorIcons")); } else if (p_what == NOTIFICATION_PROCESS) { @@ -80,10 +79,6 @@ void EditorFileDialog::_notification(int p_what) { preview_wheel_timeout = 0.1; } } - } else if (p_what == NOTIFICATION_DRAW) { - - //RID ci = get_canvas_item(); - //get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size())); } else if (p_what == NOTIFICATION_POPUP_HIDE) { set_process_unhandled_input(false); @@ -95,7 +90,7 @@ void EditorFileDialog::_notification(int p_what) { set_show_hidden_files(show_hidden); set_display_mode((DisplayMode)EditorSettings::get_singleton()->get("filesystem/file_dialog/display_mode").operator int()); - //_update_icons + // update icons mode_thumbnails->set_icon(get_icon("FileThumbnail", "EditorIcons")); mode_list->set_icon(get_icon("FileList", "EditorIcons")); dir_prev->set_icon(get_icon("Back", "EditorIcons")); @@ -106,7 +101,6 @@ void EditorFileDialog::_notification(int p_what) { fav_up->set_icon(get_icon("MoveUp", "EditorIcons")); fav_down->set_icon(get_icon("MoveDown", "EditorIcons")); - fav_rm->set_icon(get_icon("Remove", "EditorIcons")); // DO NOT CALL UPDATE FILE LIST HERE, ALL HUNDREDS OF HIDDEN DIALOGS WILL RESPOND, CALL INVALIDATE INSTEAD invalidate(); } @@ -260,7 +254,6 @@ void EditorFileDialog::_post_popup() { name = name.get_file() + "/"; } - //print_line("file: "+name); recent->add_item(name, folder); recent->set_item_metadata(recent->get_item_count() - 1, recentd[i]); } @@ -316,7 +309,7 @@ void EditorFileDialog::_request_single_thumbnail(const String &p_path) { return; EditorResourcePreview::get_singleton()->queue_resource_preview(p_path, this, "_thumbnail_done", p_path); - //print_line("want file "+p_path); + set_process(true); preview_waiting = true; preview_wheel_timeout = 0; @@ -376,7 +369,7 @@ void EditorFileDialog::_action_pressed() { bool valid = false; if (filter->get_selected() == filter->get_item_count() - 1) { - valid = true; //match none + valid = true; // match none } else if (filters.size() > 1 && filter->get_selected() == 0) { // match all filters for (int i = 0; i < filters.size(); i++) { @@ -777,14 +770,12 @@ void EditorFileDialog::update_file_list() { } if (match) { - //TreeItem *ti=tree->create_item(root); - //ti->set_text(0,files.front()->get()); + item_list->add_item(files.front()->get()); if (get_icon_func) { Ref<Texture> icon = get_icon_func(cdir.plus_file(files.front()->get())); - //ti->set_icon(0,icon); if (display_mode == DISPLAY_THUMBNAILS) { item_list->set_item_icon(item_list->get_item_count() - 1, file_thumbnail); @@ -794,11 +785,6 @@ void EditorFileDialog::update_file_list() { } } - if (mode == MODE_OPEN_DIR) { - //disabled mode? - //ti->set_custom_color(0,get_color("files_disabled")); - //ti->set_selectable(0,false); - } Dictionary d; d["name"] = files.front()->get(); d["dir"] = false; @@ -807,7 +793,6 @@ void EditorFileDialog::update_file_list() { EditorResourcePreview::get_singleton()->queue_resource_preview(fullpath, this, "_thumbnail_result", fullpath); } d["path"] = fullpath; - //ti->set_metadata(0,d); item_list->set_item_metadata(item_list->get_item_count() - 1, d); if (file->get_text() == files.front()->get()) @@ -838,11 +823,6 @@ void EditorFileDialog::update_file_list() { break; } } - // ?? - /* - if (tree->get_root() && tree->get_root()->get_children()) - tree->get_root()->get_children()->select(0); - */ files.clear(); } @@ -916,7 +896,6 @@ void EditorFileDialog::set_current_dir(const String &p_dir) { dir_access->change_dir(p_dir); update_dir(); invalidate(); - //_push_history(); } void EditorFileDialog::set_current_file(const String &p_file) { @@ -1191,7 +1170,6 @@ void EditorFileDialog::_update_favorites() { name = name.get_file() + "/"; } - //print_line("file: "+name); favorites->add_item(name, star); favorites->set_item_metadata(favorites->get_item_count() - 1, favorited[i]); @@ -1442,6 +1420,8 @@ bool EditorFileDialog::is_overwrite_warning_disabled() const { EditorFileDialog::EditorFileDialog() { + set_resizable(true); + show_hidden_files = default_show_hidden_files; display_mode = default_display_mode; local_history_pos = 0; @@ -1499,6 +1479,8 @@ EditorFileDialog::EditorFileDialog() { Ref<ButtonGroup> view_mode_group; view_mode_group.instance(); + pathhb->add_child(memnew(VSeparator)); + mode_thumbnails = memnew(ToolButton); mode_thumbnails->connect("pressed", this, "set_display_mode", varray(DISPLAY_THUMBNAILS)); mode_thumbnails->set_toggle_mode(true); @@ -1528,8 +1510,13 @@ EditorFileDialog::EditorFileDialog() { vbc->add_child(list_hb); list_hb->set_v_size_flags(SIZE_EXPAND_FILL); + VSplitContainer *vsc = memnew(VSplitContainer); + list_hb->add_child(vsc); + VBoxContainer *fav_vb = memnew(VBoxContainer); - list_hb->add_child(fav_vb); + vsc->add_child(fav_vb); + fav_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE); + fav_vb->set_v_size_flags(SIZE_EXPAND_FILL); HBoxContainer *fav_hb = memnew(HBoxContainer); fav_vb->add_child(fav_hb); fav_hb->add_child(memnew(Label(TTR("Favorites:")))); @@ -1540,23 +1527,23 @@ EditorFileDialog::EditorFileDialog() { fav_down = memnew(ToolButton); fav_hb->add_child(fav_down); fav_down->connect("pressed", this, "_favorite_move_down"); - fav_rm = memnew(ToolButton); - fav_hb->add_child(fav_rm); - fav_rm->hide(); // redundant - MarginContainer *fav_mv = memnew(MarginContainer); - fav_vb->add_child(fav_mv); - fav_mv->set_v_size_flags(SIZE_EXPAND_FILL); favorites = memnew(ItemList); - fav_mv->add_child(favorites); + fav_vb->add_child(favorites); + favorites->set_v_size_flags(SIZE_EXPAND_FILL); favorites->connect("item_selected", this, "_favorite_selected"); + VBoxContainer *rec_vb = memnew(VBoxContainer); + vsc->add_child(rec_vb); + rec_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE); + rec_vb->set_v_size_flags(SIZE_EXPAND_FILL); recent = memnew(ItemList); - fav_vb->add_margin_child(TTR("Recent:"), recent, true); + rec_vb->add_margin_child(TTR("Recent:"), recent, true); recent->connect("item_selected", this, "_recent_selected"); VBoxContainer *item_vb = memnew(VBoxContainer); list_hb->add_child(item_vb); + item_vb->set_custom_minimum_size(Size2(320, 0) * EDSCALE); HBoxContainer *preview_hb = memnew(HBoxContainer); preview_hb->set_v_size_flags(SIZE_EXPAND_FILL); @@ -1599,7 +1586,7 @@ EditorFileDialog::EditorFileDialog() { filter = memnew(OptionButton); filter->set_stretch_ratio(3); filter->set_h_size_flags(SIZE_EXPAND_FILL); - filter->set_clip_text(true); //too many extensions overflow it + filter->set_clip_text(true); // too many extensions overflow it filename_hbc->add_child(filter); filename_hbc->set_h_size_flags(SIZE_EXPAND_FILL); item_vb->add_child(filename_hbc); @@ -1609,7 +1596,6 @@ EditorFileDialog::EditorFileDialog() { _update_drives(); connect("confirmed", this, "_action_pressed"); - //cancel->connect("pressed", this,"_cancel_pressed"); item_list->connect("item_selected", this, "_item_selected", varray(), CONNECT_DEFERRED); item_list->connect("item_activated", this, "_item_db_selected", varray()); item_list->connect("nothing_selected", this, "_items_clear_selection"); @@ -1643,7 +1629,6 @@ EditorFileDialog::EditorFileDialog() { exterr->set_text(TTR("Must use a valid extension.")); add_child(exterr); - //update_file_list(); update_filters(); update_dir(); diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index f4a9a174e7..281ded6889 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -36,6 +36,7 @@ #include "scene/gui/item_list.h" #include "scene/gui/line_edit.h" #include "scene/gui/option_button.h" +#include "scene/gui/separator.h" #include "scene/gui/split_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index 8aca007e6b..a76c419152 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -173,11 +173,12 @@ void editor_register_fonts(Ref<Theme> p_theme) { p_theme->set_font("output_source", "EditorFonts", df_output_code); Ref<DynamicFont> df_text_editor_status_code; - df_output_code.instance(); - df_output_code->set_size(14 * EDSCALE); - df_output_code->set_spacing(DynamicFont::SPACING_TOP, -EDSCALE); - df_output_code->set_spacing(DynamicFont::SPACING_BOTTOM, -EDSCALE); - df_output_code->set_font_data(dfmono); - MAKE_FALLBACKS(df_output_code); - p_theme->set_font("status_source", "EditorFonts", df_output_code); + df_text_editor_status_code.instance(); + df_text_editor_status_code->set_size(14 * EDSCALE); + df_text_editor_status_code->set_spacing(DynamicFont::SPACING_TOP, -EDSCALE); + df_text_editor_status_code->set_spacing(DynamicFont::SPACING_BOTTOM, -EDSCALE); + df_text_editor_status_code->set_font_data(dfmono); + MAKE_FALLBACKS(df_text_editor_status_code); + + p_theme->set_font("status_source", "EditorFonts", df_text_editor_status_code); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 46badc8c86..814da4b5f4 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -324,23 +324,14 @@ EditorHelpSearch::EditorHelpSearch() { set_hide_on_ok(false); search_options->connect("item_activated", this, "_confirmed"); set_title(TTR("Search Help")); - - //search_options->set_hide_root(true); } ///////////////////////////////// -//////////////////////////////////// -/// ///////////////////////////////// - void EditorHelpIndex::add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root) { if (p_types.has(p_type)) return; - /* - if (!ClassDB::is_type(p_type,base) || p_type==base) - return; - */ String inherits = EditorHelp::get_doc_data()->class_list[p_type].inherits; @@ -379,8 +370,6 @@ void EditorHelpIndex::_tree_item_selected() { EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT); emit_signal("open_class", s->get_text(0)); hide(); - - //_goto_desc(s->get_text(0)); } void EditorHelpIndex::select_class(const String &p_class) { @@ -518,8 +507,6 @@ EditorHelpIndex::EditorHelpIndex() { ///////////////////////////////// -//////////////////////////////////// -/// ///////////////////////////////// DocData *EditorHelp::doc = NULL; void EditorHelp::_init_colors() { @@ -572,9 +559,7 @@ void EditorHelp::_class_list_select(const String &p_select) { void EditorHelp::_class_desc_select(const String &p_select) { - //print_line("LINK: "+p_select); if (p_select.begins_with("$")) { //enum - //_goto_desc(p_select.substr(1,p_select.length())); String select = p_select.substr(1, p_select.length()); String class_name; if (select.find(".") != -1) { @@ -585,7 +570,6 @@ void EditorHelp::_class_desc_select(const String &p_select) { emit_signal("go_to_help", "class_enum:" + class_name + ":" + select); return; } else if (p_select.begins_with("#")) { - //_goto_desc(p_select.substr(1,p_select.length())); emit_signal("go_to_help", "class_name:" + p_select.substr(1, p_select.length())); return; } else if (p_select.begins_with("@")) { @@ -612,7 +596,6 @@ void EditorHelp::_class_desc_select(const String &p_select) { } if (link.find(".") != -1) { - //must go somewhere else emit_signal("go_to_help", topic + ":" + link.get_slice(".", 0) + ":" + link.get_slice(".", 1)); } else { @@ -749,16 +732,13 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { - //ERR_FAIL_COND(!doc->class_list.has(p_class)); if (!doc->class_list.has(p_class)) return ERR_DOES_NOT_EXIST; - //if (tree_item_map.has(p_class)) { select_locked = true; - //} class_desc->show(); - //tabs->set_current_tab(PAGE_CLASS_DESC); + description_line = 0; if (p_class == edited_class) @@ -770,7 +750,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { method_line.clear(); section_line.clear(); edited_class = p_class; - //edited_class->show(); _init_colors(); @@ -866,7 +845,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->pop(); class_desc->pop(); - //class_desc->add_newline(); class_desc->add_newline(); class_desc->push_color(text_color); class_desc->push_font(doc_font); @@ -891,7 +869,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->add_text(TTR("Members:")); class_desc->pop(); class_desc->pop(); - //class_desc->add_newline(); class_desc->push_indent(1); class_desc->push_table(2); @@ -970,9 +947,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->pop(); class_desc->pop(); - //class_desc->add_newline(); - //class_desc->add_newline(); - class_desc->push_indent(1); class_desc->push_table(2); class_desc->set_table_column_expand(1, 1); @@ -1098,7 +1072,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->pop(); class_desc->add_newline(); - //class_desc->add_newline(); class_desc->push_indent(1); @@ -1106,8 +1079,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { signal_line[cd.signals[i].name] = class_desc->get_line_count() - 2; //gets overridden if description class_desc->push_font(doc_code_font); // monofont - //_add_type("void"); - //class_desc->add_text(" "); class_desc->push_color(headline_color); _add_text(cd.signals[i].name); class_desc->pop(); @@ -1141,7 +1112,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->push_font(doc_font); class_desc->push_color(comment_color); class_desc->push_indent(1); - // class_desc->add_text(" "); _add_text(cd.signals[i].description); class_desc->pop(); // indent class_desc->pop(); @@ -1185,7 +1155,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->push_indent(1); class_desc->add_newline(); - //class_desc->add_newline(); for (Map<String, Vector<DocData::ConstantDoc> >::Element *E = enums.front(); E; E = E->next()) { @@ -1260,7 +1229,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->push_indent(1); class_desc->add_newline(); - //class_desc->add_newline(); for (int i = 0; i < constants.size(); i++) { @@ -1279,7 +1247,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { if (constants[i].description != "") { class_desc->push_font(doc_font); class_desc->push_indent(1); - //class_desc->add_text(" "); class_desc->push_color(comment_color); _add_text(constants[i].description); class_desc->pop(); @@ -1353,8 +1320,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->pop(); // font class_desc->pop(); // cell - //class_desc->add_text(" "); - if (cd.properties[i].setter != "") { class_desc->push_cell(); @@ -1538,7 +1503,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { } if (brk_pos == bbcode.length()) - break; //nothing else o add + break; //nothing else to add int brk_end = bbcode.find("]", brk_pos + 1); @@ -1734,10 +1699,6 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { pos = brk_pos + 1; } } - - /*p_rt->pop(); - p_rt->pop(); - p_rt->pop();*/ } void EditorHelp::_add_text(const String &p_bbcode) { @@ -1762,8 +1723,7 @@ void EditorHelp::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { - //forward->set_icon(get_icon("Forward","EditorIcons")); - //back->set_icon(get_icon("Back","EditorIcons")); + _update_doc(); } break; @@ -1836,7 +1796,6 @@ void EditorHelp::_bind_methods() { ClassDB::bind_method("_class_list_select", &EditorHelp::_class_list_select); ClassDB::bind_method("_class_desc_select", &EditorHelp::_class_desc_select); ClassDB::bind_method("_class_desc_input", &EditorHelp::_class_desc_input); - //ClassDB::bind_method("_button_pressed",&EditorHelp::_button_pressed); ClassDB::bind_method("_request_help", &EditorHelp::_request_help); ClassDB::bind_method("_unhandled_key_input", &EditorHelp::_unhandled_key_input); ClassDB::bind_method("_search", &EditorHelp::_search); @@ -1848,21 +1807,16 @@ void EditorHelp::_bind_methods() { EditorHelp::EditorHelp() { - VBoxContainer *vbc = this; + set_custom_minimum_size(Size2(150 * EDSCALE, 0)); EDITOR_DEF("text_editor/help/sort_functions_alphabetically", true); - //class_list->connect("meta_clicked",this,"_class_list_select"); - //class_list->set_selection_enabled(true); - - { - class_desc = memnew(RichTextLabel); - vbc->add_child(class_desc); - class_desc->set_v_size_flags(SIZE_EXPAND_FILL); - class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor")); - class_desc->connect("meta_clicked", this, "_class_desc_select"); - class_desc->connect("gui_input", this, "_class_desc_input"); - } + class_desc = memnew(RichTextLabel); + add_child(class_desc); + class_desc->set_v_size_flags(SIZE_EXPAND_FILL); + class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor")); + class_desc->connect("meta_clicked", this, "_class_desc_select"); + class_desc->connect("gui_input", this, "_class_desc_input"); class_desc->set_selection_enabled(true); @@ -1882,12 +1836,6 @@ EditorHelp::EditorHelp() { search_dialog->get_ok()->set_text(TTR("Find")); search_dialog->connect("confirmed", this, "_search_cbk"); search_dialog->set_hide_on_ok(false); - - /*class_search = memnew( EditorHelpSearch(editor) ); - editor->get_gui_base()->add_child(class_search); - class_search->connect("go_to_help",this,"_help_callback");*/ - - //prev_search_page=-1; } EditorHelp::~EditorHelp() { @@ -1905,9 +1853,9 @@ void EditorHelpBit::_go_to_help(String p_what) { void EditorHelpBit::_meta_clicked(String p_select) { print_line("got meta " + p_select); - //print_line("LINK: "+p_select); + if (p_select.begins_with("$")) { //enum - //_goto_desc(p_select.substr(1,p_select.length())); + String select = p_select.substr(1, p_select.length()); String class_name; if (select.find(".") != -1) { @@ -1918,24 +1866,15 @@ void EditorHelpBit::_meta_clicked(String p_select) { _go_to_help("class_enum:" + class_name + ":" + select); return; } else if (p_select.begins_with("#")) { - //_goto_desc(p_select.substr(1,p_select.length())); + _go_to_help("class_name:" + p_select.substr(1, p_select.length())); return; } else if (p_select.begins_with("@")) { String m = p_select.substr(1, p_select.length()); - if (m.find(".") != -1) { - //must go somewhere else - - _go_to_help("class_method:" + m.get_slice(".", 0) + ":" + m.get_slice(".", 0)); - } else { - /* - if (!method_line.has(m)) - return; - class_desc->scroll_to_line(method_line[m]); - */ - } + if (m.find(".") != -1) + _go_to_help("class_method:" + m.get_slice(".", 0) + ":" + m.get_slice(".", 0)); //must go somewhere else } } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index bd85927223..3bd592e934 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -351,6 +351,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/cursor/caret_blink", true); _initial_set("text_editor/cursor/caret_blink_speed", 0.65); hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.1"); + _initial_set("text_editor/cursor/right_click_moves_caret", true); _initial_set("text_editor/theme/font", ""); hints["text_editor/theme/font"] = PropertyInfo(Variant::STRING, "text_editor/theme/font", PROPERTY_HINT_GLOBAL_FILE, "*.font,*.tres,*.res"); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index cc0b292cc4..5610baa775 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -972,6 +972,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("commentfocus", "GraphNode", graphsbcommentselected); theme->set_stylebox("breakpoint", "GraphNode", graphsbbreakpoint); theme->set_stylebox("position", "GraphNode", graphsbposition); + + Color default_node_color = Color(mv2, mv2, mv2); + theme->set_color("title_color", "GraphNode", default_node_color); + default_node_color.a = 0.7; + theme->set_color("close_color", "GraphNode", default_node_color); + theme->set_constant("port_offset", "GraphNode", 14 * EDSCALE); theme->set_constant("title_h_offset", "GraphNode", -16 * EDSCALE); theme->set_constant("close_h_offset", "GraphNode", 20 * EDSCALE); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 75e4f39e25..dce5a10d67 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -834,6 +834,58 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin memdelete(da); } +void FileSystemDock::_update_resource_paths_after_move(const Map<String, String> &p_renames) const { + + //Rename all resources loaded, be it subresources or actual resources + List<Ref<Resource> > cached; + ResourceCache::get_cached_resources(&cached); + + for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) { + + Ref<Resource> r = E->get(); + + String base_path = r->get_path(); + String extra_path; + int sep_pos = r->get_path().find("::"); + if (sep_pos >= 0) { + extra_path = base_path.substr(sep_pos, base_path.length()); + base_path = base_path.substr(0, sep_pos); + } + + if (p_renames.has(base_path)) { + base_path = p_renames[base_path]; + } + + r->set_path(base_path + extra_path); + } + + for (int i = 0; i < EditorNode::get_editor_data().get_edited_scene_count(); i++) { + + String path; + if (i == EditorNode::get_editor_data().get_edited_scene()) { + if (!get_tree()->get_edited_scene_root()) + continue; + + path = get_tree()->get_edited_scene_root()->get_filename(); + } else { + + path = EditorNode::get_editor_data().get_scene_path(i); + } + + if (p_renames.has(path)) { + path = p_renames[path]; + } + + if (i == EditorNode::get_editor_data().get_edited_scene()) { + + get_tree()->get_edited_scene_root()->set_filename(path); + } else { + + EditorNode::get_editor_data().set_scene_path(i, path); + } + } +} + void FileSystemDock::_update_dependencies_after_move(const Map<String, String> &p_renames) const { //The following code assumes that the following holds: // 1) EditorFileSystem contains the old paths/folder structure from before the rename/move. @@ -910,6 +962,7 @@ void FileSystemDock::_rename_operation_confirm() { Map<String, String> renames; _try_move_item(to_rename, new_path, renames); _update_dependencies_after_move(renames); + _update_resource_paths_after_move(renames); //Rescan everything print_line("call rescan!"); @@ -959,6 +1012,8 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path) { } _update_dependencies_after_move(renames); + _update_resource_paths_after_move(renames); + print_line("call rescan!"); _rescan(); } diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index bc8d835ba1..65a71b86e0 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -178,6 +178,7 @@ private: void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, Map<String, String> &p_renames) const; void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const; void _update_dependencies_after_move(const Map<String, String> &p_renames) const; + void _update_resource_paths_after_move(const Map<String, String> &p_renames) const; void _make_dir_confirm(); void _rename_operation_confirm(); diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 8fe6538653..0c6c608d3d 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -1435,7 +1435,7 @@ AnimationTreeEditorPlugin::AnimationTreeEditorPlugin(EditorNode *p_node) { anim_tree_editor = memnew(AnimationTreeEditor); anim_tree_editor->set_custom_minimum_size(Size2(0, 300)); - button = editor->add_bottom_panel_item("AnimationTree", anim_tree_editor); + button = editor->add_bottom_panel_item(TTR("AnimationTree"), anim_tree_editor); button->hide(); } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index ceb1ec09fc..1241441d43 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4344,7 +4344,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { additive_selection = false; // Update the menus checkboxes - call_deferred("set_state", get_state()); + set_state(get_state()); } CanvasItemEditor *CanvasItemEditor::singleton = NULL; diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 3210af1433..88649ca267 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -444,7 +444,7 @@ ResourcePreloaderEditorPlugin::ResourcePreloaderEditorPlugin(EditorNode *p_node) preloader_editor = memnew(ResourcePreloaderEditor); preloader_editor->set_custom_minimum_size(Size2(0, 250)); - button = editor->add_bottom_panel_item("ResourcePreloader", preloader_editor); + button = editor->add_bottom_panel_item(TTR("ResourcePreloader"), preloader_editor); button->hide(); //preloader_editor->set_anchor( MARGIN_TOP, Control::ANCHOR_END); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 591e6dac56..2f0f21cc0e 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -132,7 +132,7 @@ public: I = I->next(); } - if (O != E) { //should never heppane.. + if (O != E) { //should never happen.. cached.erase(O); } } @@ -234,7 +234,6 @@ ScriptEditorQuickOpen::ScriptEditorQuickOpen() { VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); - //set_child_rect(vbc); search_box = memnew(LineEdit); vbc->add_margin_child(TTR("Search:"), search_box); search_box->connect("text_changed", this, "_text_changed"); @@ -257,8 +256,6 @@ ScriptEditor *ScriptEditor::script_editor = NULL; String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) { - //ScriptEditorBase *se=Object::cast_to<ScriptEditorBase>(_se); - String val = debugger->get_var_value(p_text); if (val != String()) { return p_text + ": " + val; @@ -551,8 +548,6 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save) { idx = history[history_pos].control->get_index(); } tab_container->set_current_tab(idx); - - //script_list->select(idx); } _update_history_arrows(); @@ -698,7 +693,6 @@ void ScriptEditor::_reload_scripts() { uint64_t last_date = script->get_last_modified_time(); uint64_t date = FileAccess::get_modified_time(script->get_path()); - //printf("last date: %lli vs date: %lli\n",last_date,date); if (last_date == date) { continue; } @@ -776,7 +770,6 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { uint64_t last_date = script->get_last_modified_time(); uint64_t date = FileAccess::get_modified_time(script->get_path()); - //printf("last date: %lli vs date: %lli\n",last_date,date); if (last_date != date) { TreeItem *ti = disk_changed_list->create_item(r); @@ -786,7 +779,6 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { need_ask = true; } need_reload = true; - //r->set_metadata(0,); } } } @@ -1205,9 +1197,6 @@ void ScriptEditor::_notification(int p_what) { _update_modified_scripts_for_external_editor(); } break; - case NOTIFICATION_PROCESS: { - } break; - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { help_search->set_icon(get_icon("HelpSearch", "EditorIcons")); @@ -1367,18 +1356,9 @@ void ScriptEditor::ensure_select_current() { if (!grab_focus_block && is_visible_in_tree()) se->ensure_focus(); - - //edit_menu->show(); - //search_menu->show(); } EditorHelp *eh = Object::cast_to<EditorHelp>(current); - - if (eh) { - //edit_menu->hide(); - //search_menu->hide(); - //script_search_menu->show(); - } } _update_selected_editor_menu(); @@ -1823,12 +1803,8 @@ void ScriptEditor::save_all_scripts() { if (script.is_valid()) se->apply_code(); - if (script->get_path() != "" && script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { - //external script, save it - - editor->save_resource(script); - //ResourceSaver::save(script->get_path(),script); - } + if (script->get_path() != "" && script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) + editor->save_resource(script); //external script, save it } _update_script_names(); @@ -1886,7 +1862,6 @@ void ScriptEditor::_editor_stop() { void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const PoolStringArray &p_args) { - //print_line("add callback! hohoho"); kinda sad to remove this ERR_FAIL_COND(!p_obj); Ref<Script> script = p_obj->get_script(); ERR_FAIL_COND(!script.is_valid()); @@ -1981,8 +1956,6 @@ void ScriptEditor::_script_split_dragged(float) { Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { - // return Variant(); // return this if drag disabled - Node *cur_node = tab_container->get_child(tab_container->get_current_tab()); HBoxContainer *drag_preview = memnew(HBoxContainer); @@ -2202,9 +2175,6 @@ void ScriptEditor::_make_script_list_context_menu() { } EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(selected)); - if (eh) { - // nothing - } context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_up"), WINDOW_MOVE_UP); @@ -2547,9 +2517,9 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_script_changed", &ScriptEditor::_script_changed); ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts); - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ScriptEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ScriptEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &ScriptEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw); ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script); ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts); @@ -2588,10 +2558,9 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_list = memnew(ItemList); list_split->add_child(script_list); - script_list->set_custom_minimum_size(Size2(150 * EDSCALE, 100)); //need to give a bit of limit to avoid it from disappearing + script_list->set_custom_minimum_size(Size2(150 * EDSCALE, 90)); //need to give a bit of limit to avoid it from disappearing script_list->set_v_size_flags(SIZE_EXPAND_FILL); script_split->set_split_offset(140); - //list_split->set_split_offset(500); _sort_list_on_update = true; script_list->connect("gui_input", this, "_script_list_gui_input"); script_list->set_allow_rmb_select(true); @@ -2603,18 +2572,18 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { members_overview = memnew(ItemList); list_split->add_child(members_overview); - members_overview->set_custom_minimum_size(Size2(0, 100)); //need to give a bit of limit to avoid it from disappearing + members_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing members_overview->set_v_size_flags(SIZE_EXPAND_FILL); help_overview = memnew(ItemList); list_split->add_child(help_overview); - help_overview->set_custom_minimum_size(Size2(0, 100)); //need to give a bit of limit to avoid it from disappearing + help_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing help_overview->set_v_size_flags(SIZE_EXPAND_FILL); tab_container = memnew(TabContainer); tab_container->set_tabs_visible(false); + tab_container->set_custom_minimum_size(Size2(200 * EDSCALE, 0)); script_split->add_child(tab_container); - tab_container->set_h_size_flags(SIZE_EXPAND_FILL); ED_SHORTCUT("script_editor/window_sort", TTR("Sort")); @@ -2762,7 +2731,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { { VBoxContainer *vbc = memnew(VBoxContainer); disk_changed->add_child(vbc); - //disk_changed->set_child_rect(vbc); Label *dl = memnew(Label); dl->set_text(TTR("The following files are newer on disk.\nWhat action should be taken?:")); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 0610f55b3f..3c9cd74aa1 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1396,48 +1396,70 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_RIGHT && !mb->is_pressed()) { + if (mb->get_button_index() == BUTTON_RIGHT) { int col, row; TextEdit *tx = code_editor->get_text_edit(); tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); Vector2 mpos = mb->get_global_position() - tx->get_global_position(); - bool have_selection = (tx->get_selection_text().length() > 0); - bool have_color = (tx->get_word_at_pos(mpos) == "Color"); + + tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret")); + bool has_color = (tx->get_word_at_pos(mpos) == "Color"); int fold_state = 0; bool can_fold = tx->can_fold(row); bool is_folded = tx->is_folded(row); - if (have_color) { - - String line = tx->get_line(row); - color_line = row; - int begin = 0; - int end = 0; - bool valid = false; - for (int i = col; i < line.length(); i++) { - if (line[i] == '(') { - begin = i; - continue; - } else if (line[i] == ')') { - end = i + 1; - valid = true; - break; + + if (tx->is_right_click_moving_caret()) { + if (tx->is_selection_active()) { + + int from_line = tx->get_selection_from_line(); + int to_line = tx->get_selection_to_line(); + int from_column = tx->get_selection_from_column(); + int to_column = tx->get_selection_to_column(); + + if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { + // Right click is outside the seleted text + tx->deselect(); } } - if (valid) { - color_args = line.substr(begin, end - begin); - String stripped = color_args.replace(" ", "").replace("(", "").replace(")", ""); - Vector<float> color = stripped.split_floats(","); - if (color.size() > 2) { - float alpha = color.size() > 3 ? color[3] : 1.0f; - color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha)); + if (!tx->is_selection_active()) { + tx->cursor_set_line(row, true, false); + tx->cursor_set_column(col); + } + } + + if (!mb->is_pressed()) { + if (has_color) { + String line = tx->get_line(row); + color_line = row; + int begin = 0; + int end = 0; + bool valid = false; + for (int i = col; i < line.length(); i++) { + if (line[i] == '(') { + begin = i; + continue; + } else if (line[i] == ')') { + end = i + 1; + valid = true; + break; + } + } + if (valid) { + color_args = line.substr(begin, end - begin); + String stripped = color_args.replace(" ", "").replace("(", "").replace(")", ""); + Vector<float> color = stripped.split_floats(","); + if (color.size() > 2) { + float alpha = color.size() > 3 ? color[3] : 1.0f; + color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha)); + } + color_panel->set_position(get_global_transform().xform(get_local_mouse_position())); + } else { + has_color = false; } - color_panel->set_position(get_global_transform().xform(get_local_mouse_position())); - } else { - have_color = false; } + _make_context_menu(tx->is_selection_active(), has_color, can_fold, is_folded); } - _make_context_menu(have_selection, have_color, can_fold, is_folded); } } } diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 3e00776dfd..d0b0d3690a 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -620,14 +620,36 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_RIGHT && !mb->is_pressed()) { + if (mb->get_button_index() == BUTTON_RIGHT) { int col, row; TextEdit *tx = shader_editor->get_text_edit(); tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); Vector2 mpos = mb->get_global_position() - tx->get_global_position(); - bool have_selection = (tx->get_selection_text().length() > 0); - _make_context_menu(have_selection); + tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret")); + + if (tx->is_right_click_moving_caret()) { + if (tx->is_selection_active()) { + + int from_line = tx->get_selection_from_line(); + int to_line = tx->get_selection_to_line(); + int from_column = tx->get_selection_from_column(); + int to_column = tx->get_selection_to_column(); + + if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { + // Right click is outside the seleted text + tx->deselect(); + } + } + if (!tx->is_selection_active()) { + tx->cursor_set_line(row, true, false); + tx->cursor_set_column(col); + } + } + + if (!mb->is_pressed()) { + _make_context_menu(tx->is_selection_active()); + } } } } diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 59da5112ae..b26038fe09 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -51,7 +51,6 @@ #define GIZMO_ARROW_SIZE 0.35 #define GIZMO_RING_HALF_WIDTH 0.1 -//#define GIZMO_SCALE_DEFAULT 0.28 #define GIZMO_SCALE_DEFAULT 0.15 #define GIZMO_PLANE_SIZE 0.2 #define GIZMO_PLANE_DST 0.3 @@ -94,7 +93,6 @@ void SpatialEditorViewport::_update_camera(float p_interp_delta) { // We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos camera_cursor.eye_pos = old_camera_cursor.eye_pos.linear_interpolate(cursor.eye_pos, CLAMP(factor, 0, 1)); - //camera_cursor.pos = camera_cursor.eye_pos + (cursor.pos - cursor.eye_pos); float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia"); orbit_inertia = MAX(0.0001, orbit_inertia); @@ -153,13 +151,13 @@ void SpatialEditorViewport::_update_camera(float p_interp_delta) { if (!equal || p_interp_delta == 0 || is_freelook_active() || is_orthogonal != orthogonal) { camera->set_global_transform(to_camera_transform(camera_cursor)); - update_transform_gizmo_view(); - if (orthogonal) { - //camera->set_orthogonal(size.width*cursor.distance,get_znear(),get_zfar()); + if (orthogonal) camera->set_orthogonal(2 * cursor.distance, 0.1, 8192); - } else + else camera->set_perspective(get_fov(), get_znear(), get_zfar()); + + update_transform_gizmo_view(); } } @@ -392,9 +390,6 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, ERR_PRINT("Bug?"); } } - - // if (editor_selection->is_selected(spat)) - // r_includes_current=true; } if (!item) @@ -561,6 +556,8 @@ void SpatialEditorViewport::_update_name() { view_menu->set_text("[ " + name + " " + ortho + " ]"); else view_menu->set_text("[ " + ortho + " ]"); + + view_menu->set_size(Vector2(0, 0)); // resets the button size } void SpatialEditorViewport::_compute_edit(const Point2 &p_point) { @@ -812,17 +809,27 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig return false; } -void SpatialEditorViewport::_smouseenter() { +void SpatialEditorViewport::_surface_mouse_enter() { if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) surface->grab_focus(); } -void SpatialEditorViewport::_smouseexit() { +void SpatialEditorViewport::_surface_mouse_exit() { _remove_preview(); } +void SpatialEditorViewport::_surface_focus_enter() { + + view_menu->set_disable_shortcuts(false); +} + +void SpatialEditorViewport::_surface_focus_exit() { + + view_menu->set_disable_shortcuts(true); +} + void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) { _find_items_at_pos(b->get_position(), clicked_includes_current, selection_results, b->get_shift()); @@ -949,7 +956,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (_edit.mode != TRANSFORM_NONE && b->is_pressed()) { //cancel motion _edit.mode = TRANSFORM_NONE; - //_validate_selection(); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -966,7 +972,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { sp->set_global_transform(se->original); } surface->update(); - //VisualServer::get_singleton()->poly_clear(indicators); set_message(TTR("Transform Aborted."), 3); } @@ -1059,7 +1064,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { _edit.gizmo = seg; _edit.gizmo_handle = handle; - //_edit.gizmo_initial_pos=seg->get_handle_pos(gizmo_handle); _edit.gizmo_initial_value = seg->get_handle_value(handle); break; } @@ -1134,13 +1138,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { _edit.gizmo = seg; _edit.gizmo_handle = gizmo_handle; - //_edit.gizmo_initial_pos=seg->get_handle_pos(gizmo_handle); _edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle); - //print_line("GIZMO: "+itos(gizmo_handle)+" FROMPOS: "+_edit.orig_gizmo_pos); break; } } - //_compute_edit(Point2(b.x,b.y)); //in case a motion happens.. } surface->update(); @@ -1186,7 +1187,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } undo_redo->commit_action(); _edit.mode = TRANSFORM_NONE; - //VisualServer::get_singleton()->poly_clear(indicators); set_message(""); } @@ -1785,51 +1785,36 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) { - cursor.y_rot = 0; - cursor.x_rot = -Math_PI / 2.0; - set_message(TTR("Bottom View."), 2); - name = TTR("Bottom"); - _update_name(); + _menu_option(VIEW_BOTTOM); } if (ED_IS_SHORTCUT("spatial_editor/top_view", p_event)) { - cursor.y_rot = 0; - cursor.x_rot = Math_PI / 2.0; - set_message(TTR("Top View."), 2); - name = TTR("Top"); - _update_name(); + _menu_option(VIEW_TOP); } if (ED_IS_SHORTCUT("spatial_editor/rear_view", p_event)) { - cursor.x_rot = 0; - cursor.y_rot = Math_PI; - set_message(TTR("Rear View."), 2); - name = TTR("Rear"); - _update_name(); + _menu_option(VIEW_REAR); } if (ED_IS_SHORTCUT("spatial_editor/front_view", p_event)) { - cursor.x_rot = 0; - cursor.y_rot = 0; - set_message(TTR("Front View."), 2); - name = TTR("Front"); - _update_name(); + _menu_option(VIEW_FRONT); } if (ED_IS_SHORTCUT("spatial_editor/left_view", p_event)) { - cursor.x_rot = 0; - cursor.y_rot = Math_PI / 2.0; - set_message(TTR("Left View."), 2); - name = TTR("Left"); - _update_name(); + _menu_option(VIEW_LEFT); } if (ED_IS_SHORTCUT("spatial_editor/right_view", p_event)) { - cursor.x_rot = 0; - cursor.y_rot = -Math_PI / 2.0; - set_message(TTR("Right View."), 2); - name = TTR("Right"); - _update_name(); + _menu_option(VIEW_RIGHT); + } + if (ED_IS_SHORTCUT("spatial_editor/focus_origin", p_event)) { + _menu_option(VIEW_CENTER_TO_ORIGIN); + } + if (ED_IS_SHORTCUT("spatial_editor/focus_selection", p_event)) { + _menu_option(VIEW_CENTER_TO_SELECTION); } if (ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) { _menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL); _update_name(); } + if (ED_IS_SHORTCUT("spatial_editor/align_selection_with_view", p_event)) { + _menu_option(VIEW_ALIGN_SELECTION_WITH_VIEW); + } if (ED_IS_SHORTCUT("spatial_editor/insert_anim_key", p_event)) { if (!get_selected_count() || _edit.mode != TRANSFORM_NONE) return; @@ -2114,15 +2099,6 @@ void SpatialEditorViewport::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { - //force editr camera - /* - current_camera=get_root_node()->get_current_camera(); - if (current_camera!=camera) { - - - } - */ - real_t delta = get_process_delta_time(); if (zoom_indicator_delay > 0) { @@ -2248,8 +2224,10 @@ void SpatialEditorViewport::_notification(int p_what) { surface->connect("draw", this, "_draw"); surface->connect("gui_input", this, "_sinput"); - surface->connect("mouse_entered", this, "_smouseenter"); - surface->connect("mouse_exited", this, "_smouseexit"); + surface->connect("mouse_entered", this, "_surface_mouse_enter"); + surface->connect("mouse_exited", this, "_surface_mouse_exit"); + surface->connect("focus_entered", this, "_surface_focus_enter"); + surface->connect("focus_exited", this, "_surface_focus_exit"); info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); preview_camera->set_icon(get_icon("Camera", "EditorIcons")); @@ -2423,47 +2401,54 @@ void SpatialEditorViewport::_menu_option(int p_option) { case VIEW_TOP: { - cursor.x_rot = Math_PI / 2.0; cursor.y_rot = 0; + cursor.x_rot = Math_PI / 2.0; + set_message(TTR("Top View."), 2); name = TTR("Top"); _update_name(); + } break; case VIEW_BOTTOM: { - cursor.x_rot = -Math_PI / 2.0; cursor.y_rot = 0; + cursor.x_rot = -Math_PI / 2.0; + set_message(TTR("Bottom View."), 2); name = TTR("Bottom"); _update_name(); } break; case VIEW_LEFT: { - cursor.y_rot = Math_PI / 2.0; cursor.x_rot = 0; + cursor.y_rot = Math_PI / 2.0; + set_message(TTR("Left View."), 2); name = TTR("Left"); _update_name(); } break; case VIEW_RIGHT: { - cursor.y_rot = -Math_PI / 2.0; cursor.x_rot = 0; + cursor.y_rot = -Math_PI / 2.0; + set_message(TTR("Right View."), 2); name = TTR("Right"); _update_name(); } break; case VIEW_FRONT: { - cursor.y_rot = 0; cursor.x_rot = 0; + cursor.y_rot = 0; + set_message(TTR("Front View."), 2); name = TTR("Front"); _update_name(); } break; case VIEW_REAR: { - cursor.y_rot = Math_PI; cursor.x_rot = 0; + cursor.y_rot = Math_PI; + set_message(TTR("Rear View."), 2); name = TTR("Rear"); _update_name(); @@ -2590,6 +2575,11 @@ void SpatialEditorViewport::_menu_option(int p_option) { bool current = view_menu->get_popup()->is_item_checked(idx); view_menu->get_popup()->set_item_checked(idx, !current); + if (current) + preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE); + else + preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 15 * EDSCALE + fps_label->get_size().height); + } break; case VIEW_DISPLAY_NORMAL: { @@ -2641,14 +2631,13 @@ void SpatialEditorViewport::_preview_exited_scene() { void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { - uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx); //|(1<<GIZMO_GRID_LAYER); + uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx); for (int i = 0; i < 3; i++) { move_gizmo_instance[i] = VS::get_singleton()->instance_create(); VS::get_singleton()->instance_set_base(move_gizmo_instance[i], spatial_editor->get_move_gizmo(i)->get_rid()); VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); VS::get_singleton()->instance_set_visible(move_gizmo_instance[i], false); - //VS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer); @@ -2656,7 +2645,6 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { VS::get_singleton()->instance_set_base(move_plane_gizmo_instance[i], spatial_editor->get_move_plane_gizmo(i)->get_rid()); VS::get_singleton()->instance_set_scenario(move_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); VS::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false); - //VS::get_singleton()->instance_geometry_set_flag(move_plane_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_set_layer_mask(move_plane_gizmo_instance[i], layer); @@ -2664,7 +2652,6 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { VS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid()); VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); VS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false); - //VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer); @@ -2672,7 +2659,6 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { VS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid()); VS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); VS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false); - //VS::get_singleton()->instance_geometry_set_flag(scale_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer); @@ -2680,7 +2666,6 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { VS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid()); VS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); VS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); - //VS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer); } @@ -2745,16 +2730,8 @@ void SpatialEditorViewport::set_can_preview(Camera *p_preview) { preview = p_preview; - if (!preview_camera->is_pressed()) { - - if (p_preview) { - fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 15 * EDSCALE + preview_camera->get_size().height); - preview_camera->show(); - } else { - fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE); - preview_camera->hide(); - } - } + if (!preview_camera->is_pressed()) + preview_camera->set_visible(p_preview); } void SpatialEditorViewport::update_transform_gizmo_view() { @@ -2781,8 +2758,6 @@ void SpatialEditorViewport::update_transform_gizmo_view() { xform.basis.scale(scale); - //xform.basis.scale(GIZMO_SCALE_DEFAULT*Vector3(1,1,1)); - for (int i = 0; i < 3; i++) { VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform); VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE)); @@ -2799,18 +2774,36 @@ void SpatialEditorViewport::update_transform_gizmo_view() { void SpatialEditorViewport::set_state(const Dictionary &p_state) { - cursor.pos = p_state["position"]; - cursor.x_rot = p_state["x_rotation"]; - cursor.y_rot = p_state["y_rotation"]; - cursor.distance = p_state["distance"]; - bool env = p_state["use_environment"]; - bool orth = p_state["use_orthogonal"]; - if (orth) - _menu_option(VIEW_ORTHOGONAL); - else - _menu_option(VIEW_PERSPECTIVE); - if (env != camera->get_environment().is_valid()) - _menu_option(VIEW_ENVIRONMENT); + if (p_state.has("position")) + cursor.pos = p_state["position"]; + if (p_state.has("x_rotation")) + cursor.x_rot = p_state["x_rotation"]; + if (p_state.has("y_rotation")) + cursor.y_rot = p_state["y_rotation"]; + if (p_state.has("distance")) + cursor.distance = p_state["distance"]; + + if (p_state.has("use_orthogonal")) { + bool orth = p_state["use_orthogonal"]; + + if (orth) + _menu_option(VIEW_ORTHOGONAL); + else + _menu_option(VIEW_PERSPECTIVE); + } + if (p_state.has("display_mode")) { + int display = p_state["display_mode"]; + + int idx = view_menu->get_popup()->get_item_index(display); + if (!view_menu->get_popup()->is_item_checked(idx)) + _menu_option(display); + } + if (p_state.has("use_environment")) { + bool env = p_state["use_environment"]; + + if (env != camera->get_environment().is_valid()) + _menu_option(VIEW_ENVIRONMENT); + } if (p_state.has("listener")) { bool listener = p_state["listener"]; @@ -2839,6 +2832,13 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) { if (view_menu->get_popup()->is_item_checked(idx) != information) _menu_option(VIEW_INFORMATION); } + if (p_state.has("fps")) { + bool fps = p_state["fps"]; + + int idx = view_menu->get_popup()->get_item_index(VIEW_FPS); + if (view_menu->get_popup()->is_item_checked(idx) != fps) + _menu_option(VIEW_FPS); + } if (p_state.has("half_res")) { bool half_res = p_state["half_res"]; @@ -2869,14 +2869,22 @@ Dictionary SpatialEditorViewport::get_state() const { d["distance"] = cursor.distance; d["use_environment"] = camera->get_environment().is_valid(); d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL; + if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL))) + d["display_mode"] = VIEW_DISPLAY_NORMAL; + else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME))) + d["display_mode"] = VIEW_DISPLAY_WIREFRAME; + else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW))) + d["display_mode"] = VIEW_DISPLAY_OVERDRAW; + else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS))) + d["display_mode"] = VIEW_DISPLAY_SHADELESS; d["listener"] = viewport->is_audio_listener(); d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER)); d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS)); d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); + d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS)); d["half_res"] = viewport_container->get_stretch_shrink() > 1; - if (previewing) { + if (previewing) d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); - } return d; } @@ -2884,8 +2892,11 @@ Dictionary SpatialEditorViewport::get_state() const { void SpatialEditorViewport::_bind_methods() { ClassDB::bind_method(D_METHOD("_draw"), &SpatialEditorViewport::_draw); - ClassDB::bind_method(D_METHOD("_smouseenter"), &SpatialEditorViewport::_smouseenter); - ClassDB::bind_method(D_METHOD("_smouseexit"), &SpatialEditorViewport::_smouseexit); + + ClassDB::bind_method(D_METHOD("_surface_mouse_enter"), &SpatialEditorViewport::_surface_mouse_enter); + ClassDB::bind_method(D_METHOD("_surface_mouse_exit"), &SpatialEditorViewport::_surface_mouse_exit); + ClassDB::bind_method(D_METHOD("_surface_focus_enter"), &SpatialEditorViewport::_surface_focus_enter); + ClassDB::bind_method(D_METHOD("_surface_focus_exit"), &SpatialEditorViewport::_surface_focus_exit); ClassDB::bind_method(D_METHOD("_sinput"), &SpatialEditorViewport::_sinput); ClassDB::bind_method(D_METHOD("_menu_option"), &SpatialEditorViewport::_menu_option); ClassDB::bind_method(D_METHOD("_toggle_camera_preview"), &SpatialEditorViewport::_toggle_camera_preview); @@ -3309,7 +3320,6 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed camera = memnew(Camera); camera->set_disable_gizmo(true); camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + p_index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER)); - //camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment()); viewport->add_child(camera); camera->make_current(); surface->set_focus_mode(FOCUS_ALL); @@ -3353,6 +3363,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_selection_with_view"), VIEW_ALIGN_SELECTION_WITH_VIEW); view_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + view_menu->set_disable_shortcuts(true); + ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A); ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D); ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W); @@ -3367,7 +3379,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE); preview_camera->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE); preview_camera->set_h_grow_direction(GROW_DIRECTION_BEGIN); - preview_camera->set_text(TTR("preview")); + preview_camera->set_text(TTR("Preview")); surface->add_child(preview_camera); preview_camera->hide(); preview_camera->connect("toggled", this, "_toggle_camera_preview"); @@ -3771,7 +3783,6 @@ void SpatialEditor::update_transform_gizmo() { center.expand_to(xf.origin); gizmo_basis = Basis(); } - //count++; } Vector3 pcenter = center.position + center.size * 0.5; @@ -3994,17 +4005,6 @@ void SpatialEditor::edit(Spatial *p_spatial) { } } } - - /* - if (p_spatial) { - _validate_selection(); - if (selected.has(p_spatial->get_instance_id()) && selected.size()==1) - return; - _select(p_spatial->get_instance_id(),false,true); - - // should become the selection - } - */ } void SpatialEditor::_xform_dialog_action() { @@ -4348,9 +4348,6 @@ void SpatialEditor::_init_indicators() { VisualServer::get_singleton()->mesh_add_surface_from_arrays(origin, VisualServer::PRIMITIVE_LINES, d); VisualServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid()); - //origin = VisualServer::get_singleton()->poly_create(); - //VisualServer::get_singleton()->poly_add_primitive(origin,origin_points,Vector<Vector3>(),origin_colors,Vector<Vector3>()); - //VisualServer::get_singleton()->poly_set_material(origin,indicator_mat,true); origin_instance = VisualServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world()->get_scenario()); VS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << SpatialEditorViewport::GIZMO_GRID_LAYER); @@ -4635,9 +4632,6 @@ void SpatialEditor::_finish_indicators() { VisualServer::get_singleton()->free(grid_instance[i]); VisualServer::get_singleton()->free(grid[i]); } - //VisualServer::get_singleton()->free(poly); - //VisualServer::get_singleton()->free(indicators_instance); - //VisualServer::get_singleton()->free(indicators); } bool SpatialEditor::is_any_freelook_active() const { @@ -4879,7 +4873,6 @@ void SpatialEditor::_node_removed(Node *p_node) { void SpatialEditor::_bind_methods() { - //ClassDB::bind_method("_gui_input",&SpatialEditor::_gui_input); ClassDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input); ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed); ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed); @@ -4940,8 +4933,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { snap_enabled = false; tool_mode = TOOL_MODE_SELECT; - //set_focus_mode(FOCUS_ALL); - hbc_menu = memnew(HBoxContainer); vbc->add_child(hbc_menu); @@ -5116,7 +5107,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept); viewport_base->add_child(viewports[i]); } - //vbc->add_child(viewport_base); /* SNAP DIALOG */ @@ -5126,7 +5116,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer); snap_dialog->add_child(snap_dialog_vbc); - //snap_dialog->set_child_rect(snap_dialog_vbc); snap_translate = memnew(LineEdit); snap_translate->set_text("1"); @@ -5148,7 +5137,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { settings_vbc = memnew(VBoxContainer); settings_vbc->set_custom_minimum_size(Size2(200, 0) * EDSCALE); settings_dialog->add_child(settings_vbc); - //settings_dialog->set_child_rect(settings_vbc); settings_fov = memnew(SpinBox); settings_fov->set_max(MAX_FOV); @@ -5171,7 +5159,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500)); settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar); - //settings_dialog->get_cancel()->hide(); /* XFORM DIALOG */ xform_dialog = memnew(ConfirmationDialog); @@ -5257,14 +5244,12 @@ void SpatialEditorPlugin::make_visible(bool p_visible) { spatial_editor->show(); spatial_editor->set_process(true); - //VisualServer::get_singleton()->viewport_set_hide_scenario(editor->get_scene_root()->get_viewport(),false); spatial_editor->grab_focus(); } else { spatial_editor->hide(); spatial_editor->set_process(false); - //VisualServer::get_singleton()->viewport_set_hide_scenario(editor->get_scene_root()->get_viewport(),true); } } void SpatialEditorPlugin::edit(Object *p_object) { @@ -5317,11 +5302,8 @@ SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) { spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); editor->get_viewport()->add_child(spatial_editor); - //spatial_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); spatial_editor->hide(); spatial_editor->connect("transform_key_request", editor, "_transform_keyed"); - - //spatial_editor->set_process(true); } SpatialEditorPlugin::~SpatialEditorPlugin() { diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 4aa1d9c0c1..d080745dc9 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -273,8 +273,11 @@ private: Transform to_camera_transform(const Cursor &p_cursor) const; void _draw(); - void _smouseenter(); - void _smouseexit(); + void _surface_mouse_enter(); + void _surface_mouse_exit(); + void _surface_focus_enter(); + void _surface_focus_exit(); + void _sinput(const Ref<InputEvent> &p_event); void _update_freelook(real_t delta); SpatialEditor *spatial_editor; diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 175655119f..71c81f7111 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -840,7 +840,7 @@ SpriteFramesEditorPlugin::SpriteFramesEditorPlugin(EditorNode *p_node) { editor = p_node; frames_editor = memnew(SpriteFramesEditor); frames_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE); - button = editor->add_bottom_panel_item("SpriteFrames", frames_editor); + button = editor->add_bottom_panel_item(TTR("SpriteFrames"), frames_editor); button->hide(); } diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index 5c965e4a05..9840d9021c 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -103,6 +103,6 @@ StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) { stylebox_editor->set_custom_minimum_size(Size2(0, 250)); //p_node->get_viewport()->add_child(stylebox_editor); - button = p_node->add_bottom_panel_item("StyleBox", stylebox_editor); + button = p_node->add_bottom_panel_item(TTR("StyleBox"), stylebox_editor); button->hide(); } diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 7f956b01ff..38a4bfbfc6 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -934,6 +934,6 @@ ThemeEditorPlugin::ThemeEditorPlugin(EditorNode *p_node) { theme_editor->set_custom_minimum_size(Size2(0, 200)); //p_node->get_viewport()->add_child(theme_editor); - button = editor->add_bottom_panel_item("Theme", theme_editor); + button = editor->add_bottom_panel_item(TTR("Theme"), theme_editor); button->hide(); } diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 5eb3435e24..b56585f62c 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -314,7 +314,7 @@ TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) { autotile_editor->side_panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); autotile_editor->side_panel->set_custom_minimum_size(Size2(200, 0)); autotile_editor->side_panel->hide(); - autotile_button = p_node->add_bottom_panel_item("Autotiles", autotile_editor); + autotile_button = p_node->add_bottom_panel_item(TTR("Autotiles"), autotile_editor); autotile_button->hide(); } @@ -387,7 +387,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { tools[TOOL_SELECT] = memnew(ToolButton); tool_containers[TOOLBAR_DUMMY]->add_child(tools[TOOL_SELECT]); - tools[TOOL_SELECT]->set_tooltip("Select sub-tile to use as icon, this will be also used on invalid autotile bindings."); + tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.")); tools[TOOL_SELECT]->set_toggle_mode(true); tools[TOOL_SELECT]->set_button_group(tg); tools[TOOL_SELECT]->set_pressed(true); @@ -533,7 +533,7 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) { tool_containers[TOOLBAR_BITMASK]->show(); tool_containers[TOOLBAR_SHAPE]->hide(); tools[TOOL_SELECT]->set_pressed(true); - tools[TOOL_SELECT]->set_tooltip("LMB: set bit on.\nRMB: set bit off."); + tools[TOOL_SELECT]->set_tooltip(TTR("LMB: set bit on.\nRMB: set bit off.")); spin_priority->hide(); } break; case EDITMODE_COLLISION: @@ -542,7 +542,7 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) { tool_containers[TOOLBAR_DUMMY]->show(); tool_containers[TOOLBAR_BITMASK]->hide(); tool_containers[TOOLBAR_SHAPE]->show(); - tools[TOOL_SELECT]->set_tooltip("Select current edited sub-tile."); + tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.")); spin_priority->hide(); } break; default: { @@ -550,10 +550,10 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) { tool_containers[TOOLBAR_BITMASK]->hide(); tool_containers[TOOLBAR_SHAPE]->hide(); if (edit_mode == EDITMODE_ICON) { - tools[TOOL_SELECT]->set_tooltip("Select sub-tile to use as icon, this will be also used on invalid autotile bindings."); + tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.")); spin_priority->hide(); } else { - tools[TOOL_SELECT]->set_tooltip("Select sub-tile to change it's priority."); + tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change it's priority.")); spin_priority->show(); } } break; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 00488a2a88..04e9f0adc1 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -536,21 +536,21 @@ public: if (mode == MODE_IMPORT) { set_title(TTR("Import Existing Project")); - get_ok()->set_text(TTR("Import")); + get_ok()->set_text(TTR("Import & Edit")); name_container->hide(); project_path->grab_focus(); } else if (mode == MODE_NEW) { set_title(TTR("Create New Project")); - get_ok()->set_text(TTR("Create")); + get_ok()->set_text(TTR("Create & Edit")); name_container->show(); project_name->grab_focus(); } else if (mode == MODE_INSTALL) { set_title(TTR("Install Project:") + " " + zip_title); - get_ok()->set_text(TTR("Install")); + get_ok()->set_text(TTR("Install & Edit")); name_container->hide(); project_path->grab_focus(); } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 6f8573cd70..e69577489e 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -1460,7 +1460,6 @@ void ProjectSettingsEditor::_update_translations() { t2->set_editable(1, true); t2->set_metadata(1, path); int idx = langs.find(locale); - //print_line("find " + locale + " at " + itos(idx)); if (idx < 0) idx = 0; @@ -1709,7 +1708,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { add = memnew(Button); hbc->add_child(add); - add->set_custom_minimum_size(Size2(150, 0) * EDSCALE); add->set_text(TTR("Add")); add->set_disabled(true); add->connect("pressed", this, "_action_add"); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 47feac9a12..16cf325bc2 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -335,6 +335,8 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: easing_draw->hide(); spinbox->hide(); slider->hide(); + menu->clear(); + menu->set_size(Size2(1, 1) * EDSCALE); for (int i = 0; i < MAX_VALUE_EDITORS; i++) { @@ -413,7 +415,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: } else if (hint == PROPERTY_HINT_ENUM) { - menu->clear(); Vector<String> options = hint_text.split(","); for (int i = 0; i < options.size(); i++) { if (options[i].find(":") != -1) { @@ -494,7 +495,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: easing_draw->show(); set_size(Size2(200, 150) * EDSCALE); } else if (hint == PROPERTY_HINT_FLAGS) { - menu->clear(); Vector<String> flags = hint_text.split(","); for (int i = 0; i < flags.size(); i++) { String flag = flags[i]; @@ -536,7 +536,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: config_action_buttons(names); } else if (hint == PROPERTY_HINT_ENUM) { - menu->clear(); Vector<String> options = hint_text.split(","); for (int i = 0; i < options.size(); i++) { menu->add_item(options[i], i); @@ -869,9 +868,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: if (hint != PROPERTY_HINT_RESOURCE_TYPE) break; - menu->clear(); - menu->set_size(Size2(1, 1) * EDSCALE); - if (p_name == "script" && hint_text == "Script" && Object::cast_to<Node>(owner)) { menu->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT); menu->add_separator(); @@ -1764,24 +1760,40 @@ void CustomPropertyEditor::_focus_exit() { void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) { - int cell_width = 60; - int cell_height = 25; - int cell_margin = 5; + Ref<StyleBox> sb = get_stylebox("panel"); + int margin_top = sb->get_margin(MARGIN_TOP); + int margin_left = sb->get_margin(MARGIN_LEFT); + int margin_bottom = sb->get_margin(MARGIN_BOTTOM); + int margin_right = sb->get_margin(MARGIN_RIGHT); - set_size(Size2(cell_margin + (cell_width + cell_margin) * p_strings.size(), (cell_margin * 2) + cell_height) * EDSCALE); + int max_width = 0; + int height = 0; for (int i = 0; i < MAX_ACTION_BUTTONS; i++) { if (i < p_strings.size()) { + action_buttons[i]->show(); action_buttons[i]->set_text(p_strings[i]); - action_buttons[i]->set_position(Point2(cell_margin + (cell_width + cell_margin) * i, cell_margin) * EDSCALE); - action_buttons[i]->set_size(Size2(cell_width, cell_height - cell_margin * 2) * EDSCALE); - action_buttons[i]->set_flat(true); + + Size2 btn_m_size = action_buttons[i]->get_minimum_size(); + if (btn_m_size.width > max_width) + max_width = btn_m_size.width; + } else { action_buttons[i]->hide(); } } + + for (int i = 0; i < p_strings.size(); i++) { + + Size2 btn_m_size = action_buttons[i]->get_size(); + action_buttons[i]->set_position(Point2(0, height) + Point2(margin_left, margin_top)); + action_buttons[i]->set_size(Size2(max_width, btn_m_size.height)); + + height += btn_m_size.height; + } + set_size(Size2(max_width, height) + Size2(margin_left + margin_right, margin_top + margin_bottom)); } void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns, int p_label_w, const List<String> &p_strings) { @@ -1902,6 +1914,7 @@ CustomPropertyEditor::CustomPropertyEditor() { Vector<Variant> binds; binds.push_back(i); action_buttons[i]->connect("pressed", this, "_action_pressed", binds); + action_buttons[i]->set_flat(true); } color_picker = NULL; @@ -3956,11 +3969,13 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { if (t == Variant::NODE_PATH) { Variant v = obj->get(n); - custom_editor->edit(obj, n, (Variant::Type)t, v, h, ht); Rect2 where = tree->get_item_rect(ti, 1); where.position -= tree->get_scroll(); - where.position += tree->get_global_position(); + where.position += tree->get_global_position() + Point2(where.size.width, 0); + for (int i = ti->get_button_count(p_column) - 1; i >= p_button; i--) + where.position.x -= ti->get_button(p_column, i)->get_width(); custom_editor->set_position(where.position); + custom_editor->edit(obj, n, (Variant::Type)t, v, h, ht); custom_editor->popup(); } else if (t == Variant::STRING) { @@ -3971,7 +3986,9 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { Rect2 where = tree->get_item_rect(ti, 1); where.position -= tree->get_scroll(); - where.position += tree->get_global_position(); + where.position += tree->get_global_position() + Point2(where.size.width, 0); + for (int i = ti->get_button_count(p_column) - 1; i >= p_button; i--) + where.position.x -= ti->get_button(p_column, i)->get_width(); custom_editor->set_position(where.position); custom_editor->popup(); } else { @@ -4591,6 +4608,8 @@ SectionedPropertyEditor::SectionedPropertyEditor() { search_box = NULL; + add_constant_override("autohide", 1); // Fixes the dragger always showing up + VBoxContainer *left_vb = memnew(VBoxContainer); left_vb->set_custom_minimum_size(Size2(170, 0) * EDSCALE); add_child(left_vb); @@ -4602,6 +4621,7 @@ SectionedPropertyEditor::SectionedPropertyEditor() { left_vb->add_child(sections, true); VBoxContainer *right_vb = memnew(VBoxContainer); + right_vb->set_custom_minimum_size(Size2(300, 0) * EDSCALE); right_vb->set_h_size_flags(SIZE_EXPAND_FILL); add_child(right_vb); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 6fbca5c904..06dd6bd375 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1360,6 +1360,7 @@ void SceneTreeDock::_create() { editor_data->get_undo_redo().commit_action(); editor->push_item(c); editor_selection->clear(); + editor_selection->add_node(child); if (Object::cast_to<Control>(c)) { //make editor more comfortable, so some controls don't appear super shrunk Control *ct = Object::cast_to<Control>(c); @@ -1699,7 +1700,7 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) { icon = get_icon("Object", "EditorIcons"); if (menu->get_item_count() == 0) { - menu->add_submenu_item(TTR("Sub-Resources:"), "Sub-Resources"); + menu->add_submenu_item(TTR("Sub-Resources"), "Sub-Resources"); } int index = menu_subresources->get_item_count(); menu_subresources->add_icon_item(icon, E->get().name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size()); @@ -1733,6 +1734,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (selection.size() == 1) { subresources.clear(); + menu_subresources->clear(); _add_children_to_popup(selection.front()->get(), 0); if (menu->get_item_count() > 0) menu->add_separator(); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 7342dd5b5d..1a3ab309f7 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -2964,227 +2964,220 @@ NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p navmesh = p_navmesh; } -////// -/// -/// + ////// + /// + /// + /// -void PinJointSpatialGizmo::redraw() { +#define BODY_A_RADIUS 0.25 +#define BODY_B_RADIUS 0.27 - clear(); - Vector<Vector3> cursor_points; - float cs = 0.25; - cursor_points.push_back(Vector3(+cs, 0, 0)); - cursor_points.push_back(Vector3(-cs, 0, 0)); - cursor_points.push_back(Vector3(0, +cs, 0)); - cursor_points.push_back(Vector3(0, -cs, 0)); - cursor_points.push_back(Vector3(0, 0, +cs)); - cursor_points.push_back(Vector3(0, 0, -cs)); - add_collision_segments(cursor_points); +Basis JointGizmosDrawer::look_body(const Transform &p_joint_transform, const Transform &p_body_transform) { + const Vector3 &p_eye(p_joint_transform.origin); + const Vector3 &p_target(p_body_transform.origin); - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + Vector3 v_x, v_y, v_z; - add_lines(cursor_points, material); + // Look the body with X + v_x = p_target - p_eye; + v_x.normalize(); + + v_z = v_x.cross(Vector3(0, 1, 0)); + v_z.normalize(); + + v_y = v_z.cross(v_x); + v_y.normalize(); + + Basis base; + base.set(v_x, v_y, v_z); + + // Absorb current joint transform + base = p_joint_transform.basis.inverse() * base; + + return base; } -PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint *p_p3d) { +Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform) { - p3d = p_p3d; - set_spatial_node(p3d); + switch (p_axis) { + case Vector3::AXIS_X: + return look_body_toward_x(joint_transform, body_transform); + case Vector3::AXIS_Y: + return look_body_toward_y(joint_transform, body_transform); + case Vector3::AXIS_Z: + return look_body_toward_z(joint_transform, body_transform); + default: + return Basis(); + } } -//// +Basis JointGizmosDrawer::look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform) { -void HingeJointSpatialGizmo::redraw() { + const Vector3 &p_eye(p_joint_transform.origin); + const Vector3 &p_target(p_body_transform.origin); - clear(); - Vector<Vector3> cursor_points; - float cs = 0.25; - /*cursor_points.push_back(Vector3(+cs,0,0)); - cursor_points.push_back(Vector3(-cs,0,0)); - cursor_points.push_back(Vector3(0,+cs,0)); - cursor_points.push_back(Vector3(0,-cs,0));*/ - cursor_points.push_back(Vector3(0, 0, +cs * 2)); - cursor_points.push_back(Vector3(0, 0, -cs * 2)); + const Vector3 p_front(p_joint_transform.basis.get_axis(0)); - float ll = p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER); - float ul = p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER); + Vector3 v_x, v_y, v_z; - if (p3d->get_flag(HingeJoint::FLAG_USE_LIMIT) && ll < ul) { + // Look the body with X + v_x = p_target - p_eye; + v_x.normalize(); - const int points = 32; + v_y = p_front.cross(v_x); + v_y.normalize(); - for (int i = 0; i < points; i++) { + v_z = v_y.cross(p_front); + v_z.normalize(); - float s = ll + i * (ul - ll) / points; - float n = ll + (i + 1) * (ul - ll) / points; + // Clamp X to FRONT axis + v_x = p_front; + v_x.normalize(); - Vector3 from = Vector3(-Math::sin(s), Math::cos(s), 0) * cs; - Vector3 to = Vector3(-Math::sin(n), Math::cos(n), 0) * cs; + Basis base; + base.set(v_x, v_y, v_z); - if (i == points - 1) { - cursor_points.push_back(to); - cursor_points.push_back(Vector3()); - } - if (i == 0) { - cursor_points.push_back(from); - cursor_points.push_back(Vector3()); - } + // Absorb current joint transform + base = p_joint_transform.basis.inverse() * base; - cursor_points.push_back(from); - cursor_points.push_back(to); - } + return base; +} - cursor_points.push_back(Vector3(0, cs * 1.5, 0)); - cursor_points.push_back(Vector3()); +Basis JointGizmosDrawer::look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform) { - } else { + const Vector3 &p_eye(p_joint_transform.origin); + const Vector3 &p_target(p_body_transform.origin); - const int points = 32; + const Vector3 p_up(p_joint_transform.basis.get_axis(1)); - for (int i = 0; i < points; i++) { + Vector3 v_x, v_y, v_z; - float s = ll + i * (Math_PI * 2.0) / points; - float n = ll + (i + 1) * (Math_PI * 2.0) / points; + // Look the body with X + v_x = p_target - p_eye; + v_x.normalize(); - Vector3 from = Vector3(-Math::sin(s), Math::cos(s), 0) * cs; - Vector3 to = Vector3(-Math::sin(n), Math::cos(n), 0) * cs; + v_z = v_x.cross(p_up); + v_z.normalize(); - cursor_points.push_back(from); - cursor_points.push_back(to); - } - } + v_x = p_up.cross(v_z); + v_x.normalize(); - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + // Clamp Y to UP axis + v_y = p_up; + v_y.normalize(); - add_collision_segments(cursor_points); - add_lines(cursor_points, material); -} + Basis base; + base.set(v_x, v_y, v_z); -HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint *p_p3d) { + // Absorb current joint transform + base = p_joint_transform.basis.inverse() * base; - p3d = p_p3d; - set_spatial_node(p3d); + return base; } -/////// -/// -//// +Basis JointGizmosDrawer::look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform) { -void SliderJointSpatialGizmo::redraw() { + const Vector3 &p_eye(p_joint_transform.origin); + const Vector3 &p_target(p_body_transform.origin); - clear(); - Vector<Vector3> cursor_points; - float cs = 0.25; - /*cursor_points.push_back(Vector3(+cs,0,0)); - cursor_points.push_back(Vector3(-cs,0,0)); - cursor_points.push_back(Vector3(0,+cs,0)); - cursor_points.push_back(Vector3(0,-cs,0));*/ - cursor_points.push_back(Vector3(0, 0, +cs * 2)); - cursor_points.push_back(Vector3(0, 0, -cs * 2)); - - float ll = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER); - float ul = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER); - float lll = p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER); - float lul = p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER); - - if (lll <= lul) { - - cursor_points.push_back(Vector3(lul, 0, 0)); - cursor_points.push_back(Vector3(lll, 0, 0)); - - cursor_points.push_back(Vector3(lul, -cs, -cs)); - cursor_points.push_back(Vector3(lul, -cs, cs)); - cursor_points.push_back(Vector3(lul, -cs, cs)); - cursor_points.push_back(Vector3(lul, cs, cs)); - cursor_points.push_back(Vector3(lul, cs, cs)); - cursor_points.push_back(Vector3(lul, cs, -cs)); - cursor_points.push_back(Vector3(lul, cs, -cs)); - cursor_points.push_back(Vector3(lul, -cs, -cs)); - - cursor_points.push_back(Vector3(lll, -cs, -cs)); - cursor_points.push_back(Vector3(lll, -cs, cs)); - cursor_points.push_back(Vector3(lll, -cs, cs)); - cursor_points.push_back(Vector3(lll, cs, cs)); - cursor_points.push_back(Vector3(lll, cs, cs)); - cursor_points.push_back(Vector3(lll, cs, -cs)); - cursor_points.push_back(Vector3(lll, cs, -cs)); - cursor_points.push_back(Vector3(lll, -cs, -cs)); + const Vector3 p_lateral(p_joint_transform.basis.get_axis(2)); - } else { + Vector3 v_x, v_y, v_z; - cursor_points.push_back(Vector3(+cs * 2, 0, 0)); - cursor_points.push_back(Vector3(-cs * 2, 0, 0)); - } + // Look the body with X + v_x = p_target - p_eye; + v_x.normalize(); - if (ll < ul) { + v_z = p_lateral; + v_z.normalize(); - const int points = 32; + v_y = v_z.cross(v_x); + v_y.normalize(); - for (int i = 0; i < points; i++) { + // Clamp X to Z axis + v_x = v_y.cross(v_z); + v_x.normalize(); - float s = ll + i * (ul - ll) / points; - float n = ll + (i + 1) * (ul - ll) / points; + Basis base; + base.set(v_x, v_y, v_z); - Vector3 from = Vector3(0, Math::cos(s), -Math::sin(s)) * cs; - Vector3 to = Vector3(0, Math::cos(n), -Math::sin(n)) * cs; + // Absorb current joint transform + base = p_joint_transform.basis.inverse() * base; - if (i == points - 1) { - cursor_points.push_back(to); - cursor_points.push_back(Vector3()); - } - if (i == 0) { - cursor_points.push_back(from); - cursor_points.push_back(Vector3()); - } + return base; +} - cursor_points.push_back(from); - cursor_points.push_back(to); - } +void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse) { + + if (p_limit_lower == p_limit_upper) { - cursor_points.push_back(Vector3(0, cs * 1.5, 0)); - cursor_points.push_back(Vector3()); + r_points.push_back(p_offset.translated(Vector3()).origin); + r_points.push_back(p_offset.translated(p_base.xform(Vector3(0.5, 0, 0))).origin); } else { + if (p_limit_lower > p_limit_upper) { + p_limit_lower = -Math_PI; + p_limit_upper = Math_PI; + } + const int points = 32; for (int i = 0; i < points; i++) { - float s = ll + i * (Math_PI * 2.0) / points; - float n = ll + (i + 1) * (Math_PI * 2.0) / points; + real_t s = p_limit_lower + i * (p_limit_upper - p_limit_lower) / points; + real_t n = p_limit_lower + (i + 1) * (p_limit_upper - p_limit_lower) / points; + + Vector3 from; + Vector3 to; + switch (p_axis) { + case Vector3::AXIS_X: + if (p_inverse) { + from = p_base.xform(Vector3(0, Math::sin(s), Math::cos(s))) * p_radius; + to = p_base.xform(Vector3(0, Math::sin(n), Math::cos(n))) * p_radius; + } else { + from = p_base.xform(Vector3(0, -Math::sin(s), Math::cos(s))) * p_radius; + to = p_base.xform(Vector3(0, -Math::sin(n), Math::cos(n))) * p_radius; + } + break; + case Vector3::AXIS_Y: + if (p_inverse) { + from = p_base.xform(Vector3(Math::cos(s), 0, -Math::sin(s))) * p_radius; + to = p_base.xform(Vector3(Math::cos(n), 0, -Math::sin(n))) * p_radius; + } else { + from = p_base.xform(Vector3(Math::cos(s), 0, Math::sin(s))) * p_radius; + to = p_base.xform(Vector3(Math::cos(n), 0, Math::sin(n))) * p_radius; + } + break; + case Vector3::AXIS_Z: + from = p_base.xform(Vector3(Math::cos(s), Math::sin(s), 0)) * p_radius; + to = p_base.xform(Vector3(Math::cos(n), Math::sin(n), 0)) * p_radius; + break; + } - Vector3 from = Vector3(0, Math::cos(s), -Math::sin(s)) * cs; - Vector3 to = Vector3(0, Math::cos(n), -Math::sin(n)) * cs; + if (i == points - 1) { + r_points.push_back(p_offset.translated(to).origin); + r_points.push_back(p_offset.translated(Vector3()).origin); + } + if (i == 0) { + r_points.push_back(p_offset.translated(from).origin); + r_points.push_back(p_offset.translated(Vector3()).origin); + } - cursor_points.push_back(from); - cursor_points.push_back(to); + r_points.push_back(p_offset.translated(from).origin); + r_points.push_back(p_offset.translated(to).origin); } - } - - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - - add_collision_segments(cursor_points); - add_lines(cursor_points, material); -} - -SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint *p_p3d) { - p3d = p_p3d; - set_spatial_node(p3d); + r_points.push_back(p_offset.translated(Vector3(0, p_radius * 1.5, 0)).origin); + r_points.push_back(p_offset.translated(Vector3()).origin); + } } -/////// -/// -//// - -void ConeTwistJointSpatialGizmo::redraw() { - - clear(); - Vector<Vector3> points; +void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points) { float r = 1.0; - float w = r * Math::sin(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN)); - float d = r * Math::cos(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN)); + float w = r * Math::sin(p_swing); + float d = r * Math::cos(p_swing); //swing for (int i = 0; i < 360; i += 10) { @@ -3194,27 +3187,21 @@ void ConeTwistJointSpatialGizmo::redraw() { Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w; - /*points.push_back(Vector3(a.x,0,a.y)); - points.push_back(Vector3(b.x,0,b.y)); - points.push_back(Vector3(0,a.x,a.y)); - points.push_back(Vector3(0,b.x,b.y));*/ - points.push_back(Vector3(d, a.x, a.y)); - points.push_back(Vector3(d, b.x, b.y)); + r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, a.x, a.y))).origin); + r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, b.x, b.y))).origin); if (i % 90 == 0) { - points.push_back(Vector3(d, a.x, a.y)); - points.push_back(Vector3()); + r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, a.x, a.y))).origin); + r_points.push_back(p_offset.translated(p_base.xform(Vector3())).origin); } } - points.push_back(Vector3()); - points.push_back(Vector3(1, 0, 0)); + r_points.push_back(p_offset.translated(p_base.xform(Vector3())).origin); + r_points.push_back(p_offset.translated(p_base.xform(Vector3(1, 0, 0))).origin); - //twist - /* - */ - float ts = Math::rad2deg(p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN)); + /// Twist + float ts = Math::rad2deg(p_twist); ts = MIN(ts, 720); for (int i = 0; i < int(ts); i += 5) { @@ -3226,18 +3213,276 @@ void ConeTwistJointSpatialGizmo::redraw() { Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c; Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w * cn; - /*points.push_back(Vector3(a.x,0,a.y)); - points.push_back(Vector3(b.x,0,b.y)); - points.push_back(Vector3(0,a.x,a.y)); - points.push_back(Vector3(0,b.x,b.y));*/ + r_points.push_back(p_offset.translated(p_base.xform(Vector3(c, a.x, a.y))).origin); + r_points.push_back(p_offset.translated(p_base.xform(Vector3(cn, b.x, b.y))).origin); + } +} + +void PinJointSpatialGizmo::CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) { + float cs = 0.25; + + r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin); +} + +void PinJointSpatialGizmo::redraw() { + + clear(); + Vector<Vector3> cursor_points; + CreateGizmo(Transform(), cursor_points); + add_collision_segments(cursor_points); + + Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + + add_lines(cursor_points, material); +} + +PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint *p_p3d) { + + p3d = p_p3d; + set_spatial_node(p3d); +} + +//// + +void HingeJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { + + r_common_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin); + r_common_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin); + + if (!p_use_limit) { + p_limit_upper = -1; + p_limit_lower = 0; + } + + if (r_body_a_points) { + + JointGizmosDrawer::draw_circle(Vector3::AXIS_Z, + BODY_A_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_a), + p_limit_lower, + p_limit_upper, + *r_body_a_points); + } - points.push_back(Vector3(c, a.x, a.y)); - points.push_back(Vector3(cn, b.x, b.y)); + if (r_body_b_points) { + JointGizmosDrawer::draw_circle(Vector3::AXIS_Z, + BODY_B_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_b), + p_limit_lower, + p_limit_upper, + *r_body_b_points); } +} + +void HingeJointSpatialGizmo::redraw() { + + const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); + const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); + + Vector<Vector3> points; + Vector<Vector3> body_a_points; + Vector<Vector3> body_b_points; + CreateGizmo( + Transform(), + p3d->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER), + p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER), + p3d->get_flag(HingeJoint::FLAG_USE_LIMIT), + points, + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); + + clear(); + + Ref<Material> common_material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); + Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); + + add_collision_segments(points); + add_collision_segments(body_a_points); + add_collision_segments(body_b_points); + + add_lines(points, common_material); + add_lines(body_a_points, body_a_material); + add_lines(body_b_points, body_b_material); +} + +HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint *p_p3d) { + + p3d = p_p3d; + set_spatial_node(p3d); +} + +/////// +/// +//// + +void SliderJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { + + p_linear_limit_lower = -p_linear_limit_lower; + p_linear_limit_upper = -p_linear_limit_upper; + + float cs = 0.25; + r_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin); + r_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin); + + if (p_linear_limit_lower >= p_linear_limit_upper) { + + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, 0, 0)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, 0, 0)).origin); + + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, -cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, -cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, -cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, -cs)).origin); + + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, -cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, -cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, -cs)).origin); + r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, -cs)).origin); + + } else { + + r_points.push_back(p_offset.translated(Vector3(+cs * 2, 0, 0)).origin); + r_points.push_back(p_offset.translated(Vector3(-cs * 2, 0, 0)).origin); + } + + if (r_body_a_points) + JointGizmosDrawer::draw_circle( + Vector3::AXIS_X, + BODY_A_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_a), + p_angular_limit_lower, + p_angular_limit_upper, + *r_body_a_points); + + if (r_body_b_points) + JointGizmosDrawer::draw_circle( + Vector3::AXIS_X, + BODY_B_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_b), + p_angular_limit_lower, + p_angular_limit_upper, + *r_body_b_points, + true); +} + +void SliderJointSpatialGizmo::redraw() { + + const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); + const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); + + clear(); + Vector<Vector3> cursor_points; + Vector<Vector3> body_a_points; + Vector<Vector3> body_b_points; + + CreateGizmo( + Transform(), + p3d->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER), + p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER), + p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER), + p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER), + cursor_points, + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); + + Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); + Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); + + add_collision_segments(cursor_points); + add_collision_segments(body_a_points); + add_collision_segments(body_b_points); + + add_lines(cursor_points, material); + add_lines(body_a_points, body_a_material); + add_lines(body_b_points, body_b_material); +} + +SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint *p_p3d) { + + p3d = p_p3d; + set_spatial_node(p3d); +} + +/////// +/// +//// + +void ConeTwistJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { + + if (r_body_a_points) + JointGizmosDrawer::draw_cone( + p_offset, + JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_a), + p_swing, + p_twist, + *r_body_a_points); + + if (r_body_b_points) + JointGizmosDrawer::draw_cone( + p_offset, + JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_b), + p_swing, + p_twist, + *r_body_b_points); +} + +void ConeTwistJointSpatialGizmo::redraw() { + + const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); + const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); + + clear(); + Vector<Vector3> points; + Vector<Vector3> body_a_points; + Vector<Vector3> body_b_points; + + CreateGizmo( + Transform(), + p3d->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN), + p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN), + points, + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); + Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); + add_collision_segments(points); + add_collision_segments(body_a_points); + add_collision_segments(body_b_points); + add_lines(points, material); + add_lines(body_a_points, body_a_material); + add_lines(body_b_points, body_b_material); } ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d) { @@ -3246,26 +3491,46 @@ ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d) { set_spatial_node(p3d); } -//////// -/// \brief SpatialEditorGizmos::singleton -/// /////// /// //// -void Generic6DOFJointSpatialGizmo::redraw() { +void Generic6DOFJointSpatialGizmo::CreateGizmo( + const Transform &p_offset, + const Transform &p_trs_joint, + const Transform &p_trs_body_a, + const Transform &p_trs_body_b, + real_t p_angular_limit_lower_x, + real_t p_angular_limit_upper_x, + real_t p_linear_limit_lower_x, + real_t p_linear_limit_upper_x, + bool p_enable_angular_limit_x, + bool p_enable_linear_limit_x, + real_t p_angular_limit_lower_y, + real_t p_angular_limit_upper_y, + real_t p_linear_limit_lower_y, + real_t p_linear_limit_upper_y, + bool p_enable_angular_limit_y, + bool p_enable_linear_limit_y, + real_t p_angular_limit_lower_z, + real_t p_angular_limit_upper_z, + real_t p_linear_limit_lower_z, + real_t p_linear_limit_upper_z, + bool p_enable_angular_limit_z, + bool p_enable_linear_limit_z, + Vector<Vector3> &r_points, + Vector<Vector3> *r_body_a_points, + Vector<Vector3> *r_body_b_points) { - clear(); - Vector<Vector3> cursor_points; float cs = 0.25; for (int ax = 0; ax < 3; ax++) { - /*cursor_points.push_back(Vector3(+cs,0,0)); - cursor_points.push_back(Vector3(-cs,0,0)); - cursor_points.push_back(Vector3(0,+cs,0)); - cursor_points.push_back(Vector3(0,-cs,0)); - cursor_points.push_back(Vector3(0,0,+cs*2)); - cursor_points.push_back(Vector3(0,0,-cs*2)); */ + /*r_points.push_back(p_offset.translated(Vector3(+cs,0,0)).origin); + r_points.push_back(p_offset.translated(Vector3(-cs,0,0)).origin); + r_points.push_back(p_offset.translated(Vector3(0,+cs,0)).origin); + r_points.push_back(p_offset.translated(Vector3(0,-cs,0)).origin); + r_points.push_back(p_offset.translated(Vector3(0,0,+cs*2)).origin); + r_points.push_back(p_offset.translated(Vector3(0,0,-cs*2)).origin); */ float ll; float ul; @@ -3278,61 +3543,50 @@ void Generic6DOFJointSpatialGizmo::redraw() { switch (ax) { case 0: - ll = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT); - ul = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT); - lll = p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT); - lul = p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT); - enable_ang = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT); - enable_lin = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT); + ll = p_angular_limit_lower_x; + ul = p_angular_limit_upper_x; + lll = -p_linear_limit_lower_x; + lul = -p_linear_limit_upper_x; + enable_ang = p_enable_angular_limit_x; + enable_lin = p_enable_linear_limit_x; a1 = 0; a2 = 1; a3 = 2; break; case 1: - ll = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT); - ul = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT); - lll = p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT); - lul = p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT); - enable_ang = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT); - enable_lin = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT); - + ll = p_angular_limit_lower_y; + ul = p_angular_limit_upper_y; + lll = -p_linear_limit_lower_y; + lul = -p_linear_limit_upper_y; + enable_ang = p_enable_angular_limit_y; + enable_lin = p_enable_linear_limit_y; a1 = 1; a2 = 2; a3 = 0; break; case 2: - ll = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT); - ul = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT); - lll = p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT); - lul = p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT); - enable_ang = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT); - enable_lin = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT); - + ll = p_angular_limit_lower_z; + ul = p_angular_limit_upper_z; + lll = -p_linear_limit_lower_z; + lul = -p_linear_limit_upper_z; + enable_ang = p_enable_angular_limit_z; + enable_lin = p_enable_linear_limit_z; a1 = 2; a2 = 0; a3 = 1; break; } -#define ADD_VTX(x, y, z) \ - { \ - Vector3 v; \ - v[a1] = (x); \ - v[a2] = (y); \ - v[a3] = (z); \ - cursor_points.push_back(v); \ - } - -#define SET_VTX(what, x, y, z) \ - { \ - Vector3 v; \ - v[a1] = (x); \ - v[a2] = (y); \ - v[a3] = (z); \ - what = v; \ +#define ADD_VTX(x, y, z) \ + { \ + Vector3 v; \ + v[a1] = (x); \ + v[a2] = (y); \ + v[a3] = (z); \ + r_points.push_back(p_offset.translated(v).origin); \ } - if (enable_lin && lll <= lul) { + if (enable_lin && lll >= lul) { ADD_VTX(lul, 0, 0); ADD_VTX(lll, 0, 0); @@ -3361,69 +3615,88 @@ void Generic6DOFJointSpatialGizmo::redraw() { ADD_VTX(-cs * 2, 0, 0); } - if (enable_ang && ll <= ul) { - - const int points = 32; - - for (int i = 0; i < points; i++) { - - float s = ll + i * (ul - ll) / points; - float n = ll + (i + 1) * (ul - ll) / points; - - Vector3 from; - SET_VTX(from, 0, Math::cos(s), -Math::sin(s)); - from *= cs; - Vector3 to; - SET_VTX(to, 0, Math::cos(n), -Math::sin(n)); - to *= cs; - - if (i == points - 1) { - cursor_points.push_back(to); - cursor_points.push_back(Vector3()); - } - if (i == 0) { - cursor_points.push_back(from); - cursor_points.push_back(Vector3()); - } - - cursor_points.push_back(from); - cursor_points.push_back(to); - } - - ADD_VTX(0, cs * 1.5, 0); - cursor_points.push_back(Vector3()); - - } else { - - const int points = 32; - - for (int i = 0; i < points; i++) { + if (!enable_ang) { + ll = 0; + ul = -1; + } - float s = ll + i * (Math_PI * 2.0) / points; - float n = ll + (i + 1) * (Math_PI * 2.0) / points; + if (r_body_a_points) + JointGizmosDrawer::draw_circle( + static_cast<Vector3::Axis>(ax), + BODY_A_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_a), + ll, + ul, + *r_body_a_points, + true); + + if (r_body_b_points) + JointGizmosDrawer::draw_circle( + static_cast<Vector3::Axis>(ax), + BODY_B_RADIUS, + p_offset, + JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_b), + ll, + ul, + *r_body_b_points); + } - //Vector3 from=Vector3(0,Math::cos(s),-Math::sin(s) )*cs; - //Vector3 to=Vector3( 0,Math::cos(n),-Math::sin(n) )*cs; +#undef ADD_VTX +} - Vector3 from; - SET_VTX(from, 0, Math::cos(s), -Math::sin(s)); - from *= cs; - Vector3 to; - SET_VTX(to, 0, Math::cos(n), -Math::sin(n)); - to *= cs; +void Generic6DOFJointSpatialGizmo::redraw() { - cursor_points.push_back(from); - cursor_points.push_back(to); - } - } - } + const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); + const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); -#undef ADD_VTX -#undef SET_VTX + clear(); + Vector<Vector3> cursor_points; + Vector<Vector3> body_a_points; + Vector<Vector3> body_b_points; + + CreateGizmo( + Transform(), + p3d->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + + p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + cursor_points, + node_body_a ? &body_a_points : NULL, + node_body_a ? &body_b_points : NULL); Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); + Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); + add_collision_segments(cursor_points); + add_collision_segments(body_a_points); + add_collision_segments(body_b_points); + add_lines(cursor_points, material); + add_lines(body_a_points, body_a_material); + add_lines(body_b_points, body_b_material); } Generic6DOFJointSpatialGizmo::Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d) { @@ -3616,6 +3889,8 @@ SpatialEditorGizmos::SpatialEditorGizmos() { EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)); + EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1)); + EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4)); diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index ea8a33d2c6..7bf632d371 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -107,6 +107,7 @@ protected: void add_solid_box(Ref<Material> &p_material, Vector3 size); void set_spatial_node(Spatial *p_node); + const Spatial *get_spatial_node() const { return spatial_node; } static void _bind_methods(); @@ -372,6 +373,21 @@ public: NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh = NULL); }; +class JointGizmosDrawer { +public: + static Basis look_body(const Transform &joint_transform, const Transform &body_transform); + static Basis look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform); + static Basis look_body_toward_x(const Transform &joint_transform, const Transform &body_transform); + static Basis look_body_toward_y(const Transform &joint_transform, const Transform &body_transform); + /// Special function just used for physics joints, it that returns a basis constrained toward Joint Z axis + /// with axis X and Y that are looking toward the body and oriented toward up + static Basis look_body_toward_z(const Transform &joint_transform, const Transform &body_transform); + + // Draw circle around p_axis + static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse = false); + static void draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points); +}; + class PinJointSpatialGizmo : public EditorSpatialGizmo { GDCLASS(PinJointSpatialGizmo, EditorSpatialGizmo); @@ -379,6 +395,8 @@ class PinJointSpatialGizmo : public EditorSpatialGizmo { PinJoint *p3d; public: + static void CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points); + void redraw(); PinJointSpatialGizmo(PinJoint *p_p3d = NULL); }; @@ -390,6 +408,8 @@ class HingeJointSpatialGizmo : public EditorSpatialGizmo { HingeJoint *p3d; public: + static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + void redraw(); HingeJointSpatialGizmo(HingeJoint *p_p3d = NULL); }; @@ -401,6 +421,8 @@ class SliderJointSpatialGizmo : public EditorSpatialGizmo { SliderJoint *p3d; public: + static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + void redraw(); SliderJointSpatialGizmo(SliderJoint *p_p3d = NULL); }; @@ -412,6 +434,8 @@ class ConeTwistJointSpatialGizmo : public EditorSpatialGizmo { ConeTwistJoint *p3d; public: + static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + void redraw(); ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d = NULL); }; @@ -423,6 +447,33 @@ class Generic6DOFJointSpatialGizmo : public EditorSpatialGizmo { Generic6DOFJoint *p3d; public: + static void CreateGizmo( + const Transform &p_offset, + const Transform &p_trs_joint, + const Transform &p_trs_body_a, + const Transform &p_trs_body_b, + real_t p_angular_limit_lower_x, + real_t p_angular_limit_upper_x, + real_t p_linear_limit_lower_x, + real_t p_linear_limit_upper_x, + bool p_enable_angular_limit_x, + bool p_enable_linear_limit_x, + real_t p_angular_limit_lower_y, + real_t p_angular_limit_upper_y, + real_t p_linear_limit_lower_y, + real_t p_linear_limit_upper_y, + bool p_enable_angular_limit_y, + bool p_enable_linear_limit_y, + real_t p_angular_limit_lower_z, + real_t p_angular_limit_upper_z, + real_t p_linear_limit_lower_z, + real_t p_linear_limit_upper_z, + bool p_enable_angular_limit_z, + bool p_enable_linear_limit_z, + Vector<Vector3> &r_points, + Vector<Vector3> *r_body_a_points, + Vector<Vector3> *r_body_b_points); + void redraw(); Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d = NULL); }; diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index cbf30c8a2e..37e45cfff8 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -142,6 +142,9 @@ bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) co btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { + if (m_count >= m_resultMax) + return cp.getDistance(); + if (cp.getDistance() <= 0) { PhysicsDirectSpaceState::ShapeResult &result = m_results[m_count]; @@ -165,7 +168,7 @@ btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, con ++m_count; } - return m_count < m_resultMax; + return cp.getDistance(); } bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 669b2c3f0c..5e736c1856 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -264,6 +264,7 @@ RigidBodyBullet::RigidBodyBullet() : can_sleep(true), force_integration_callback(NULL), isTransformChanged(false), + previousActiveState(true), maxCollisionsDetection(0), collisionsCount(0), maxAreasWhereIam(10), @@ -287,6 +288,7 @@ RigidBodyBullet::RigidBodyBullet() : for (int i = areasWhereIam.size() - 1; 0 <= i; --i) { areasWhereIam[i] = NULL; } + btBody->setSleepingThresholds(0.2, 0.2); } RigidBodyBullet::~RigidBodyBullet() { @@ -337,7 +339,7 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) { void RigidBodyBullet::dispatch_callbacks() { /// The check isTransformChanged is necessary in order to call integrated forces only when the first transform is sent - if (btBody->isActive() && force_integration_callback && isTransformChanged) { + if ((btBody->isActive() || previousActiveState != btBody->isActive()) && force_integration_callback && isTransformChanged) { BulletPhysicsDirectBodyState *bodyDirect = BulletPhysicsDirectBodyState::get_singleton(this); @@ -364,6 +366,8 @@ void RigidBodyBullet::dispatch_callbacks() { /// Lock axis btBody->setLinearVelocity(btBody->getLinearVelocity() * btBody->getLinearFactor()); btBody->setAngularVelocity(btBody->getAngularVelocity() * btBody->getAngularFactor()); + + previousActiveState = btBody->isActive(); } void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) { @@ -580,7 +584,8 @@ Variant RigidBodyBullet::get_state(PhysicsServer::BodyState p_state) const { void RigidBodyBullet::apply_central_impulse(const Vector3 &p_impulse) { btVector3 btImpu; G_TO_B(p_impulse, btImpu); - btBody->activate(); + if (Vector3() != p_impulse) + btBody->activate(); btBody->applyCentralImpulse(btImpu); } @@ -589,14 +594,16 @@ void RigidBodyBullet::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impul btVector3 btPos; G_TO_B(p_impulse, btImpu); G_TO_B(p_pos, btPos); - btBody->activate(); + if (Vector3() != p_impulse) + btBody->activate(); btBody->applyImpulse(btImpu, btPos); } void RigidBodyBullet::apply_torque_impulse(const Vector3 &p_impulse) { btVector3 btImp; G_TO_B(p_impulse, btImp); - btBody->activate(); + if (Vector3() != p_impulse) + btBody->activate(); btBody->applyTorqueImpulse(btImp); } @@ -605,28 +612,32 @@ void RigidBodyBullet::apply_force(const Vector3 &p_force, const Vector3 &p_pos) btVector3 btPos; G_TO_B(p_force, btForce); G_TO_B(p_pos, btPos); - btBody->activate(); + if (Vector3() != p_force) + btBody->activate(); btBody->applyForce(btForce, btPos); } void RigidBodyBullet::apply_central_force(const Vector3 &p_force) { btVector3 btForce; G_TO_B(p_force, btForce); - btBody->activate(); + if (Vector3() != p_force) + btBody->activate(); btBody->applyCentralForce(btForce); } void RigidBodyBullet::apply_torque(const Vector3 &p_torque) { btVector3 btTorq; G_TO_B(p_torque, btTorq); - btBody->activate(); + if (Vector3() != p_torque) + btBody->activate(); btBody->applyTorque(btTorq); } void RigidBodyBullet::set_applied_force(const Vector3 &p_force) { btVector3 btVec = btBody->getTotalTorque(); - btBody->activate(); + if (Vector3() != p_force) + btBody->activate(); btBody->clearForces(); btBody->applyTorque(btVec); @@ -644,7 +655,8 @@ Vector3 RigidBodyBullet::get_applied_force() const { void RigidBodyBullet::set_applied_torque(const Vector3 &p_torque) { btVector3 btVec = btBody->getTotalForce(); - btBody->activate(); + if (Vector3() != p_torque) + btBody->activate(); btBody->clearForces(); btBody->applyCentralForce(btVec); @@ -711,7 +723,8 @@ bool RigidBodyBullet::is_continuous_collision_detection_enabled() const { void RigidBodyBullet::set_linear_velocity(const Vector3 &p_velocity) { btVector3 btVec; G_TO_B(p_velocity, btVec); - btBody->activate(); + if (Vector3() != p_velocity) + btBody->activate(); btBody->setLinearVelocity(btVec); } @@ -724,7 +737,8 @@ Vector3 RigidBodyBullet::get_linear_velocity() const { void RigidBodyBullet::set_angular_velocity(const Vector3 &p_velocity) { btVector3 btVec; G_TO_B(p_velocity, btVec); - btBody->activate(); + if (Vector3() != p_velocity) + btBody->activate(); btBody->setAngularVelocity(btVec); } @@ -833,6 +847,9 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { void RigidBodyBullet::reload_space_override_modificator() { + if (!is_active()) + return; + Vector3 newGravity(space->get_gravity_direction() * space->get_gravity_magnitude()); real_t newLinearDamp(linearDamp); real_t newAngularDamp(angularDamp); diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index c0eb148e24..c3b72172d9 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -207,6 +207,7 @@ private: bool isScratchedSpaceOverrideModificator; bool isTransformChanged; + bool previousActiveState; // Last check state ForceIntegrationCallback *force_integration_callback; diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index af5a0334c3..44dd776e9a 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1376,7 +1376,7 @@ bool CSharpScript::_update_exports() { hint_string = NATIVE_GDMONOCLASS_NAME(field_type.type_class); } else { hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); - hint_string = CACHED_FIELD(ExportAttribute, hint_string)->get_string_value(attr); + hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); } PropertyInfo prop_info = PropertyInfo(type, name, hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index fbb9b2ed14..d7885ade61 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -108,7 +108,7 @@ const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in bool BindingsGenerator::verbose_output = false; -static String snake_to_pascal_case(const String &p_identifier) { +static String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper = false) { String ret; Vector<String> parts = p_identifier.split("_", true); @@ -118,6 +118,10 @@ static String snake_to_pascal_case(const String &p_identifier) { if (part.length()) { part[0] = _find_upper(part[0]); + if (p_input_is_upper) { + for (int j = 1; j < part.length(); j++) + part[j] = _find_lower(part[j]); + } ret += part; } else { if (i == 0 || i == (parts.size() - 1)) { @@ -137,7 +141,7 @@ static String snake_to_pascal_case(const String &p_identifier) { return ret; } -static String snake_to_camel_case(const String &p_identifier) { +static String snake_to_camel_case(const String &p_identifier, bool p_input_is_upper = false) { String ret; Vector<String> parts = p_identifier.split("_", true); @@ -146,8 +150,13 @@ static String snake_to_camel_case(const String &p_identifier) { String part = parts[i]; if (part.length()) { - if (i != 0) + if (i != 0) { part[0] = _find_upper(part[0]); + } + if (p_input_is_upper) { + for (int j = i != 0 ? 1 : 0; j < part.length(); j++) + part[j] = _find_lower(part[j]); + } ret += part; } else { if (i == 0 || i == (parts.size() - 1)) { @@ -167,6 +176,25 @@ static String snake_to_camel_case(const String &p_identifier) { return ret; } +String BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) { + + CRASH_COND(p_ienum.constants.empty()); + + const List<ConstantInterface>::Element *front = p_ienum.constants.front(); + int candidate_len = front->get().name.length(); + + for (const List<ConstantInterface>::Element *E = front->next(); E; E = E->next()) { + int j = 0; + for (j = 0; j < candidate_len && j < E->get().name.length(); j++) { + if (front->get().name[j] != E->get().name[j]) + break; + } + candidate_len = j; + } + + return front->get().name.substr(0, candidate_len); +} + void BindingsGenerator::_generate_header_icalls() { core_custom_icalls.clear(); @@ -220,7 +248,7 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) { const TypeInterface *return_type = _get_type_by_name_or_placeholder(imethod.return_type); String im_sig = "IntPtr " CS_PARAM_METHODBIND ", IntPtr " CS_PARAM_INSTANCE; - String im_unique_sig = imethod.return_type + ",IntPtr,IntPtr"; + String im_unique_sig = imethod.return_type.operator String() + ",IntPtr,IntPtr"; // Get arguments information int i = 0; @@ -256,6 +284,129 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) { } } +void BindingsGenerator::_generate_global_constants(List<String> &p_output) { + + // Constants (in partial GD class) + + p_output.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); + p_output.push_back(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{"); + + for (const List<ConstantInterface>::Element *E = global_constants.front(); E; E = E->next()) { + const ConstantInterface &iconstant = E->get(); + + if (iconstant.const_doc && iconstant.const_doc->description.size()) { + p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); + + Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + + for (int i = 0; i < description_lines.size(); i++) { + String description_line = description_lines[i].strip_edges(); + if (description_line.size()) { + p_output.push_back(INDENT2 "/// "); + p_output.push_back(description_line.xml_escape()); + p_output.push_back("\n"); + } + } + + p_output.push_back(INDENT2 "/// </summary>"); + } + + p_output.push_back(MEMBER_BEGIN "public const int "); + p_output.push_back(iconstant.name); + p_output.push_back(" = "); + p_output.push_back(itos(iconstant.value)); + p_output.push_back(";"); + } + + if (!global_constants.empty()) + p_output.push_back("\n"); + + p_output.push_back(INDENT1 CLOSE_BLOCK); // end of GD class + + // Enums + + for (List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) { + const EnumInterface &ienum = E->get(); + + CRASH_COND(ienum.constants.empty()); + + String enum_proxy_name = ienum.cname.operator String(); + + bool enum_in_static_class = false; + + if (enum_proxy_name.find(".") > 0) { + enum_in_static_class = true; + String enum_class_name = enum_proxy_name.get_slicec('.', 0); + enum_proxy_name = enum_proxy_name.get_slicec('.', 1); + + CRASH_COND(enum_class_name != "Variant"); // Hard-coded... + + if (verbose_output) { + WARN_PRINTS("Declaring global enum `" + enum_proxy_name + "` inside static class `" + enum_class_name + "`"); + } + + p_output.push_back("\n" INDENT1 "public static partial class "); + p_output.push_back(enum_class_name); + p_output.push_back("\n" INDENT1 OPEN_BLOCK); + } + + p_output.push_back("\n" INDENT1 "public enum "); + p_output.push_back(enum_proxy_name); + p_output.push_back("\n" INDENT1 OPEN_BLOCK); + + for (const List<ConstantInterface>::Element *E = ienum.constants.front(); E; E = E->next()) { + const ConstantInterface &iconstant = E->get(); + + if (iconstant.const_doc && iconstant.const_doc->description.size()) { + p_output.push_back(INDENT2 "/// <summary>\n"); + + Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + + for (int i = 0; i < description_lines.size(); i++) { + String description_line = description_lines[i].strip_edges(); + if (description_line.size()) { + p_output.push_back(INDENT2 "/// "); + p_output.push_back(description_line.xml_escape()); + p_output.push_back("\n"); + } + } + + p_output.push_back(INDENT2 "/// </summary>\n"); + } + + String constant_name = iconstant.name; + + if (!ienum.prefix.empty() && constant_name.begins_with(ienum.prefix)) { + constant_name = constant_name.substr(ienum.prefix.length(), constant_name.length()); + } + + if (constant_name[0] >= '0' && constant_name[0] <= '9') { + // The name of enum constants may begin with a numeric digit when strip from the enum prefix, + // so we make the prefix one word shorter in those cases. + int i = 0; + for (i = ienum.prefix.length() - 1; i >= 0; i--) { + if (ienum.prefix[i] >= 'A' && ienum.prefix[i] <= 'Z') + break; + } + constant_name = ienum.prefix.substr(i, ienum.prefix.length()) + constant_name; + } + + p_output.push_back(INDENT2); + p_output.push_back(constant_name); + p_output.push_back(" = "); + p_output.push_back(itos(iconstant.value)); + p_output.push_back(E != ienum.constants.back() ? ",\n" : "\n"); + } + + p_output.push_back(INDENT1 CLOSE_BLOCK); + + if (enum_in_static_class) + p_output.push_back(INDENT1 CLOSE_BLOCK); + } + + p_output.push_back(CLOSE_BLOCK); // end of namespace +} + Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bool p_verbose_output) { verbose_output = p_verbose_output; @@ -282,7 +433,19 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo if (!solution.set_path(p_output_dir)) return ERR_FILE_NOT_FOUND; - for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) { + // Generate source file for global scope constants and enums + { + List<String> constants_source; + _generate_global_constants(constants_source); + String output_file = path_join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs"); + Error save_err = _save_file(output_file, constants_source); + if (save_err != OK) + return save_err; + + compile_items.push_back(output_file); + } + + for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) { const TypeInterface &itype = E->get(); if (itype.api_type == ClassDB::API_EDITOR) @@ -314,49 +477,6 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo #undef GENERATE_BUILTIN_TYPE - // Generate source for GlobalConstants - - String constants_source; - int global_constants_count = GlobalConstants::get_global_constant_count(); - - if (global_constants_count > 0) { - Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope"); - - ERR_EXPLAIN("Could not find `@GlobalScope` in DocData"); - ERR_FAIL_COND_V(!match, ERR_BUG); - - const DocData::ClassDoc &global_scope_doc = match->value(); - - for (int i = 0; i < global_constants_count; i++) { - const DocData::ConstantDoc &const_doc = global_scope_doc.constants[i]; - - if (i > 0) - constants_source += MEMBER_BEGIN; - - if (const_doc.description.size()) { - constants_source += "/// <summary>\n"; - - Vector<String> description_lines = const_doc.description.split("\n"); - - for (int i = 0; i < description_lines.size(); i++) { - if (description_lines[i].size()) { - constants_source += INDENT2 "/// "; - constants_source += description_lines[i].strip_edges().xml_escape(); - constants_source += "\n"; - } - } - - constants_source += INDENT2 "/// </summary>" MEMBER_BEGIN; - } - - constants_source += "public const int "; - constants_source += GlobalConstants::get_global_constant_name(i); - constants_source += " = "; - constants_source += itos(GlobalConstants::get_global_constant_value(i)); - constants_source += ";"; - } - } - // Generate sources from compressed files Map<String, CompressedFile> compressed_files; @@ -372,19 +492,6 @@ 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); - if (file_name.get_basename() == BINDINGS_GLOBAL_SCOPE_CLASS) { - // GD.cs must be formatted to include the generated global constants - String data_str = String::utf8(reinterpret_cast<const char *>(data.ptr()), data.size()); - - Dictionary format_keys; - format_keys["GodotGlobalConstants"] = constants_source; - data_str = data_str.format(format_keys, "/*{_}*/"); - - CharString data_utf8 = data_str.utf8(); - data.resize(data_utf8.length()); - copymem(data.ptrw(), reinterpret_cast<const uint8_t *>(data_utf8.get_data()), data_utf8.length()); - } - FileAccessRef file = FileAccess::open(output_file, FileAccess::WRITE); ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); file->store_buffer(data.ptr(), data.size()); @@ -470,7 +577,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, if (!solution.set_path(p_output_dir)) return ERR_FILE_NOT_FOUND; - for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) { + for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) { const TypeInterface &itype = E->get(); if (itype.api_type != ClassDB::API_EDITOR) @@ -543,7 +650,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, // e.g.: warning CS0108: 'SpriteBase3D.FLAG_MAX' hides inherited member 'GeometryInstance.FLAG_MAX'. Use the new keyword if hiding was intended. Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const String &p_output_file) { - bool is_derived_type = itype.base_name.length(); + bool is_derived_type = itype.base_name != StringName(); List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls; @@ -569,9 +676,10 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str Vector<String> description_lines = class_doc->description.split("\n"); for (int i = 0; i < description_lines.size(); i++) { - if (description_lines[i].size()) { + String description_line = description_lines[i].strip_edges(); + if (description_line.size()) { output.push_back(INDENT1 "/// "); - output.push_back(description_lines[i].strip_edges().xml_escape()); + output.push_back(description_line.xml_escape()); output.push_back("\n"); } } @@ -592,7 +700,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back(obj_types[itype.base_name].proxy_name); output.push_back("\n"); } else { - ERR_PRINTS("Base type '" + itype.base_name + "' does not exist, for class " + itype.name); + ERR_PRINTS("Base type '" + itype.base_name.operator String() + "' does not exist, for class " + itype.name); return ERR_INVALID_DATA; } @@ -602,18 +710,19 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // Add constants - for (int i = 0; i < class_doc->constants.size(); i++) { - const DocData::ConstantDoc &const_doc = class_doc->constants[i]; + for (const List<ConstantInterface>::Element *E = itype.constants.front(); E; E = E->next()) { + const ConstantInterface &iconstant = E->get(); - if (const_doc.description.size()) { + if (iconstant.const_doc && iconstant.const_doc->description.size()) { output.push_back(MEMBER_BEGIN "/// <summary>\n"); - Vector<String> description_lines = const_doc.description.split("\n"); + Vector<String> description_lines = iconstant.const_doc->description.split("\n"); for (int i = 0; i < description_lines.size(); i++) { - if (description_lines[i].size()) { + String description_line = description_lines[i].strip_edges(); + if (description_line.size()) { output.push_back(INDENT2 "/// "); - output.push_back(description_lines[i].strip_edges().xml_escape()); + output.push_back(description_line.xml_escape()); output.push_back("\n"); } } @@ -622,24 +731,84 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } output.push_back(MEMBER_BEGIN "public const int "); - output.push_back(const_doc.name); + output.push_back(iconstant.name); output.push_back(" = "); - output.push_back(const_doc.value); + output.push_back(itos(iconstant.value)); output.push_back(";"); } - if (class_doc->constants.size()) + if (itype.constants.size()) output.push_back("\n"); - // Add properties + // Add enums + + for (const List<EnumInterface>::Element *E = itype.enums.front(); E; E = E->next()) { + const EnumInterface &ienum = E->get(); + + ERR_FAIL_COND_V(ienum.constants.empty(), ERR_BUG); + + output.push_back(MEMBER_BEGIN "public enum "); + output.push_back(ienum.cname.operator String()); + output.push_back(MEMBER_BEGIN OPEN_BLOCK); + + for (const List<ConstantInterface>::Element *E = ienum.constants.front(); E; E = E->next()) { + const ConstantInterface &iconstant = E->get(); + + if (iconstant.const_doc && iconstant.const_doc->description.size()) { + output.push_back(INDENT3 "/// <summary>\n"); + + Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + + for (int i = 0; i < description_lines.size(); i++) { + String description_line = description_lines[i].strip_edges(); + if (description_line.size()) { + output.push_back(INDENT3 "/// "); + output.push_back(description_line.xml_escape()); + output.push_back("\n"); + } + } + + output.push_back(INDENT3 "/// </summary>\n"); + } + + String constant_name = iconstant.name; + + if (!ienum.prefix.empty() && constant_name.begins_with(ienum.prefix)) { + constant_name = constant_name.substr(ienum.prefix.length(), constant_name.length()); + } + + if (constant_name[0] >= '0' && constant_name[0] <= '9') { + // The name of enum constants may begin with a numeric digit when strip from the enum prefix, + // so we make the prefix one word shorter in those cases. + int i = 0; + for (i = ienum.prefix.length() - 1; i >= 0; i--) { + if (ienum.prefix[i] >= 'A' && ienum.prefix[i] <= 'Z') + break; + } + constant_name = ienum.prefix.substr(i, ienum.prefix.length()) + constant_name; + } + + output.push_back(INDENT3); + output.push_back(constant_name); + output.push_back(" = "); + output.push_back(itos(iconstant.value)); + output.push_back(E != ienum.constants.back() ? ",\n" : "\n"); + } + + output.push_back(INDENT2 CLOSE_BLOCK); + } + + if (itype.enums.size()) + output.push_back("\n"); - const Vector<DocData::PropertyDoc> &properties = class_doc->properties; + // Add properties - for (int i = 0; i < properties.size(); i++) { - const DocData::PropertyDoc &prop_doc = properties[i]; - Error prop_err = _generate_cs_property(itype, prop_doc, output); + for (const List<PropertyInterface>::Element *E = itype.properties.front(); E; E = E->next()) { + const PropertyInterface &iprop = E->get(); + Error prop_err = _generate_cs_property(itype, iprop, output); if (prop_err != OK) { - ERR_EXPLAIN("Failed to generate property '" + prop_doc.name + "' for class '" + itype.name + "'"); + ERR_EXPLAIN("Failed to generate property '" + iprop.cname.operator String() + + "' for class '" + itype.name + "'"); ERR_FAIL_V(prop_err); } } @@ -766,14 +935,14 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str " = IntPtr.Zero;\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3 "GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2); - Map<String, TypeInterface>::Element *array_itype = builtin_types.find("Array"); + Map<StringName, TypeInterface>::Element *array_itype = builtin_types.find(name_cache.type_Array); if (!array_itype) { ERR_PRINT("BUG: Array type interface not found!"); return ERR_BUG; } - Map<String, TypeInterface>::Element *object_itype = obj_types.find("Object"); + Map<StringName, TypeInterface>::Element *object_itype = obj_types.find("Object"); if (!object_itype) { ERR_PRINT("BUG: Object type interface not found!"); @@ -787,7 +956,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } } - Map<String, String>::Element *extra_member = extra_members.find(itype.name); + Map<StringName, String>::Element *extra_member = extra_members.find(itype.cname); if (extra_member) output.push_back(extra_member->get()); @@ -820,43 +989,39 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str return _save_file(p_output_file, output); } -Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInterface &p_itype, const DocData::PropertyDoc &p_prop_doc, List<String> &p_output) { +Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInterface &p_itype, const PropertyInterface &p_iprop, List<String> &p_output) { - const MethodInterface *setter = p_itype.find_method_by_name(p_prop_doc.setter); + const MethodInterface *setter = p_itype.find_method_by_name(p_iprop.setter); // Search it in base types too const TypeInterface *current_type = &p_itype; - while (!setter && current_type->base_name.length()) { - Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name); + while (!setter && current_type->base_name != StringName()) { + Map<StringName, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name); ERR_FAIL_NULL_V(base_match, ERR_BUG); current_type = &base_match->get(); - setter = current_type->find_method_by_name(p_prop_doc.setter); + setter = current_type->find_method_by_name(p_iprop.setter); } - const MethodInterface *getter = p_itype.find_method_by_name(p_prop_doc.getter); + const MethodInterface *getter = p_itype.find_method_by_name(p_iprop.getter); // Search it in base types too current_type = &p_itype; - while (!getter && current_type->base_name.length()) { - Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name); + while (!getter && current_type->base_name != StringName()) { + Map<StringName, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name); ERR_FAIL_NULL_V(base_match, ERR_BUG); current_type = &base_match->get(); - getter = current_type->find_method_by_name(p_prop_doc.getter); + getter = current_type->find_method_by_name(p_iprop.getter); } ERR_FAIL_COND_V(!setter && !getter, ERR_BUG); - bool is_valid = false; - int prop_index = ClassDB::get_property_index(p_itype.name, p_prop_doc.name, &is_valid); - ERR_FAIL_COND_V(!is_valid, ERR_BUG); - if (setter) { - int setter_argc = prop_index != -1 ? 2 : 1; + int setter_argc = p_iprop.index != -1 ? 2 : 1; ERR_FAIL_COND_V(setter->arguments.size() != setter_argc, ERR_BUG); } if (getter) { - int getter_argc = prop_index != -1 ? 1 : 0; + int getter_argc = p_iprop.index != -1 ? 1 : 0; ERR_FAIL_COND_V(getter->arguments.size() != getter_argc, ERR_BUG); } @@ -864,18 +1029,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte ERR_FAIL_COND_V(getter->return_type != setter->arguments.back()->get().type, ERR_BUG); } - // Let's not trust PropertyDoc::type - String proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type; + StringName proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type; const TypeInterface *prop_itype = _get_type_by_name_or_null(proptype_name); - if (!prop_itype) { - // Try with underscore prefix - prop_itype = _get_type_by_name_or_null("_" + proptype_name); - } + ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found - ERR_FAIL_NULL_V(prop_itype, ERR_BUG); - - String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_prop_doc.name)); + String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname)); // Prevent property and enclosing type from sharing the same name if (prop_proxy_name == p_itype.proxy_name) { @@ -887,15 +1046,16 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte prop_proxy_name += "_"; } - if (p_prop_doc.description.size()) { + if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) { p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); - Vector<String> description_lines = p_prop_doc.description.split("\n"); + Vector<String> description_lines = p_iprop.prop_doc->description.split("\n"); for (int i = 0; i < description_lines.size(); i++) { - if (description_lines[i].size()) { + String description_line = description_lines[i].strip_edges(); + if (description_line.size()) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_lines[i].strip_edges().xml_escape()); + p_output.push_back(description_line.xml_escape()); p_output.push_back("\n"); } } @@ -917,16 +1077,34 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.push_back(INDENT3 "get\n" OPEN_BLOCK_L3); p_output.push_back("return "); p_output.push_back(getter->proxy_name + "("); - if (prop_index != -1) - p_output.push_back(itos(prop_index)); + if (p_iprop.index != -1) { + const ArgumentInterface &idx_arg = getter->arguments.front()->get(); + if (idx_arg.type != name_cache.type_int) { + // Assume the index parameter is an enum + const TypeInterface *idx_arg_type = _get_type_by_name_or_null(idx_arg.type); + CRASH_COND(idx_arg_type == NULL); + p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index)); + } else { + p_output.push_back(itos(p_iprop.index)); + } + } p_output.push_back(");\n" CLOSE_BLOCK_L3); } if (setter) { p_output.push_back(INDENT3 "set\n" OPEN_BLOCK_L3); p_output.push_back(setter->proxy_name + "("); - if (prop_index != -1) - p_output.push_back(itos(prop_index) + ", "); + if (p_iprop.index != -1) { + const ArgumentInterface &idx_arg = setter->arguments.front()->get(); + if (idx_arg.type != name_cache.type_int) { + // Assume the index parameter is an enum + const TypeInterface *idx_arg_type = _get_type_by_name_or_null(idx_arg.type); + CRASH_COND(idx_arg_type == NULL); + p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index) + ", "); + } else { + p_output.push_back(itos(p_iprop.index) + ", "); + } + } p_output.push_back("value);\n" CLOSE_BLOCK_L3); } @@ -1033,9 +1211,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf Vector<String> description_lines = p_imethod.method_doc->description.split("\n"); for (int i = 0; i < description_lines.size(); i++) { - if (description_lines[i].size()) { + String description_line = description_lines[i].strip_edges(); + if (description_line.size()) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_lines[i].strip_edges().xml_escape()); + p_output.push_back(description_line.xml_escape()); p_output.push_back("\n"); } } @@ -1069,7 +1248,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf if (p_imethod.is_virtual) { // Godot virtual method must be overridden, therefore we return a default value by default. - if (return_type->name == "void") { + if (return_type->cname == name_cache.type_void) { p_output.push_back("return;\n" CLOSE_BLOCK_L2); } else { p_output.push_back("return default("); @@ -1108,7 +1287,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf if (p_imethod.arguments.size()) p_output.push_back(cs_in_statements); - if (return_type->name == "void") { + if (return_type->cname == name_cache.type_void) { p_output.push_back(im_call); } else if (return_type->cs_out.empty()) { p_output.push_back("return " + im_call); @@ -1142,7 +1321,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { generated_icall_funcs.clear(); - for (Map<String, TypeInterface>::Element *type_elem = obj_types.front(); type_elem; type_elem = type_elem->next()) { + for (Map<StringName, TypeInterface>::Element *type_elem = obj_types.front(); type_elem; type_elem = type_elem->next()) { const TypeInterface &itype = type_elem->get(); List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls; @@ -1295,7 +1474,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte if (p_imethod.is_virtual) return OK; // Ignore - bool ret_void = p_imethod.return_type == "void"; + bool ret_void = p_imethod.return_type == name_cache.type_void; const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type); @@ -1447,14 +1626,19 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte return OK; } -const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const String &p_name) { +const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const StringName &p_cname) { + + const Map<StringName, TypeInterface>::Element *match = builtin_types.find(p_cname); - const Map<String, TypeInterface>::Element *match = builtin_types.find(p_name); + if (match) + return &match->get(); + + match = obj_types.find(p_cname); if (match) return &match->get(); - match = obj_types.find(p_name); + match = enum_types.find(p_cname); if (match) return &match->get(); @@ -1462,24 +1646,27 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_ return NULL; } -const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_placeholder(const String &p_name) { +const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_placeholder(const StringName &p_cname) { - const TypeInterface *found = _get_type_by_name_or_null(p_name); + const TypeInterface *found = _get_type_by_name_or_null(p_cname); if (found) return found; - ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_name); + ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_cname.operator String()); - const Map<String, TypeInterface>::Element *match = placeholder_types.find(p_name); + const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_cname); if (match) return &match->get(); TypeInterface placeholder; - TypeInterface::create_placeholder_type(placeholder, p_name); + TypeInterface::create_placeholder_type(placeholder, p_cname); - return &placeholder_types.insert(placeholder.name, placeholder)->get(); + return &placeholder_types.insert(placeholder.cname, placeholder)->get(); +} + +static void _create_constant_interface_from(const StringName &p_constant, const DocData::ClassDoc &p_classdoc) { } void BindingsGenerator::_populate_object_type_interfaces() { @@ -1490,8 +1677,6 @@ void BindingsGenerator::_populate_object_type_interfaces() { ClassDB::get_class_list(&class_list); class_list.sort_custom<StringName::AlphCompare>(); - StringName refclass_name = String("Reference"); - while (class_list.size()) { StringName type_cname = class_list.front()->get(); @@ -1502,21 +1687,23 @@ void BindingsGenerator::_populate_object_type_interfaces() { continue; } + if (!ClassDB::is_class_exposed(type_cname)) { + if (verbose_output) + WARN_PRINTS("Ignoring type " + type_cname.operator String() + " because it's not exposed"); + class_list.pop_front(); + continue; + } + + ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(type_cname); + TypeInterface itype = TypeInterface::create_object_type(type_cname, api_type); itype.base_name = ClassDB::get_parent_class(type_cname); itype.is_singleton = Engine::get_singleton()->has_singleton(itype.proxy_name); itype.is_instantiable = ClassDB::can_instance(type_cname) && !itype.is_singleton; - itype.is_reference = ClassDB::is_parent_class(type_cname, refclass_name); + itype.is_reference = ClassDB::is_parent_class(type_cname, name_cache.type_Reference); itype.memory_own = itype.is_reference; - if (!ClassDB::is_class_exposed(type_cname)) { - if (verbose_output) - WARN_PRINTS("Ignoring type " + String(type_cname) + " because it's not exposed"); - class_list.pop_front(); - continue; - } - itype.c_out = "\treturn "; itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED; itype.c_out += itype.is_reference ? "(%1.ptr());\n" : "(%1);\n"; @@ -1530,6 +1717,8 @@ void BindingsGenerator::_populate_object_type_interfaces() { itype.im_type_in = "IntPtr"; itype.im_type_out = itype.proxy_name; + // Populate methods + List<MethodInfo> virtual_method_list; ClassDB::get_virtual_methods(type_cname, &virtual_method_list, true); @@ -1547,6 +1736,7 @@ void BindingsGenerator::_populate_object_type_interfaces() { MethodInterface imethod; imethod.name = method_info.name; + imethod.cname = imethod.name; if (method_info.flags & METHOD_FLAG_VIRTUAL) imethod.is_virtual = true; @@ -1570,12 +1760,12 @@ void BindingsGenerator::_populate_object_type_interfaces() { // The method Object.free is registered as a virtual method, but without the virtual flag. // This is because this method is not supposed to be overridden, but called. // We assume the return type is void. - imethod.return_type = "void"; + imethod.return_type = name_cache.type_void; // Actually, more methods like this may be added in the future, // which could actually will return something differnet. // Let's put this to notify us if that ever happens. - if (itype.name != "Object" || imethod.name != "free") { + if (itype.cname != name_cache.type_Object || imethod.name != "free") { if (verbose_output) { WARN_PRINTS("Notification: New unexpected virtual non-overridable method found.\n" "We only expected Object.free, but found " + @@ -1585,22 +1775,21 @@ void BindingsGenerator::_populate_object_type_interfaces() { } else { ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name); } - } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { - //imethod.return_type = return_info.class_name; - imethod.return_type = "int"; + } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { // TODO redundant? + imethod.return_type = return_info.class_name; } else if (return_info.class_name != StringName()) { imethod.return_type = return_info.class_name; } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { imethod.return_type = return_info.hint_string; } else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { - imethod.return_type = "Variant"; + imethod.return_type = name_cache.type_Variant; } else if (return_info.type == Variant::NIL) { - imethod.return_type = "void"; + imethod.return_type = name_cache.type_void; } else { imethod.return_type = Variant::get_type_name(return_info.type); } - if (!itype.requires_collections && imethod.return_type == "Dictionary") + if (!itype.requires_collections && imethod.return_type == name_cache.type_Dictionary) itype.requires_collections = true; for (int i = 0; i < argc; i++) { @@ -1609,22 +1798,21 @@ void BindingsGenerator::_populate_object_type_interfaces() { ArgumentInterface iarg; iarg.name = arginfo.name; - if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { - //iarg.type = arginfo.class_name; - iarg.type = "int"; + if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { // TODO redundant? + iarg.type = arginfo.class_name; } else if (arginfo.class_name != StringName()) { iarg.type = arginfo.class_name; } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { iarg.type = arginfo.hint_string; } else if (arginfo.type == Variant::NIL) { - iarg.type = "Variant"; + iarg.type = name_cache.type_Variant; } else { iarg.type = Variant::get_type_name(arginfo.type); } iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name)); - if (!itype.requires_collections && iarg.type == "Dictionary") + if (!itype.requires_collections && iarg.type == name_cache.type_Dictionary) itype.requires_collections = true; if (m && m->has_default_argument(i)) { @@ -1636,7 +1824,7 @@ void BindingsGenerator::_populate_object_type_interfaces() { if (imethod.is_vararg) { ArgumentInterface ivararg; - ivararg.type = "VarArg"; + ivararg.type = name_cache.type_VarArg; ivararg.name = "@args"; imethod.add_argument(ivararg); } @@ -1679,7 +1867,128 @@ void BindingsGenerator::_populate_object_type_interfaces() { } } - obj_types.insert(itype.name, itype); + // Populate properties + + List<PropertyInfo> property_list; + ClassDB::get_property_list(type_cname, &property_list, true); + for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { + const PropertyInfo &property = E->get(); + + if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_CATEGORY) + continue; + + PropertyInterface iprop; + iprop.cname = property.name; + iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname)); + iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname); + iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname); + + bool valid = false; + iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid); + ERR_FAIL_COND(!valid); + + // Prevent property and enclosing type from sharing the same name + if (iprop.proxy_name == itype.proxy_name) { + if (verbose_output) { + WARN_PRINTS("Name of property `" + iprop.proxy_name + "` is ambiguous with the name of its class `" + + itype.proxy_name + "`. Renaming property to `" + iprop.proxy_name + "_`"); + } + + iprop.proxy_name += "_"; + } + + iprop.prop_doc = NULL; + + for (int i = 0; i < itype.class_doc->properties.size(); i++) { + const DocData::PropertyDoc &prop_doc = itype.class_doc->properties[i]; + + if (prop_doc.name == iprop.cname) { + iprop.prop_doc = &prop_doc; + break; + } + } + + itype.properties.push_back(iprop); + } + + // Populate enums and constants + + List<String> constant_list; + ClassDB::get_integer_constant_list(type_cname, &constant_list, true); + + const HashMap<StringName, List<StringName> > &enum_map = class_info->enum_map; + const StringName *k = NULL; + + while ((k = enum_map.next(k))) { + StringName enum_proxy_cname = *k; + String enum_proxy_name = enum_proxy_cname.operator String(); + if (itype.find_property_by_proxy_name(enum_proxy_cname)) { + // We have several conflicts between enums and PascalCase properties, + // so we append 'Enum' to the enum name in those cases. + enum_proxy_name += "Enum"; + enum_proxy_cname = StringName(enum_proxy_name); + } + EnumInterface ienum(enum_proxy_cname); + const List<StringName> &constants = enum_map.get(*k); + for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) { + int *value = class_info->constant_map.getptr(E->get()); + ERR_FAIL_NULL(value); + constant_list.erase(E->get().operator String()); + + ConstantInterface iconstant(snake_to_pascal_case(E->get(), true), *value); + + iconstant.const_doc = NULL; + for (int i = 0; i < itype.class_doc->constants.size(); i++) { + const DocData::ConstantDoc &const_doc = itype.class_doc->constants[i]; + + if (const_doc.name == iconstant.name) { + iconstant.const_doc = &const_doc; + break; + } + } + + ienum.constants.push_back(iconstant); + } + + ienum.prefix = _determine_enum_prefix(ienum); + + itype.enums.push_back(ienum); + + TypeInterface enum_itype; + enum_itype.name = itype.name + "." + String(*k); + enum_itype.cname = StringName(enum_itype.name); + enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name; + enum_itype.c_arg_in = "&%s"; + enum_itype.c_type = "int"; + enum_itype.c_type_in = "int"; + enum_itype.c_type_out = "int"; + enum_itype.cs_type = enum_itype.proxy_name; + enum_itype.im_type_in = enum_itype.proxy_name; + enum_itype.im_type_out = enum_itype.proxy_name; + enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[enum_itype.proxy_name]; + enum_types.insert(enum_itype.cname, enum_itype); + } + + for (const List<String>::Element *E = constant_list.front(); E; E = E->next()) { + int *value = class_info->constant_map.getptr(E->get()); + ERR_FAIL_NULL(value); + + ConstantInterface iconstant(snake_to_pascal_case(E->get(), true), *value); + + iconstant.const_doc = NULL; + for (int i = 0; i < itype.class_doc->constants.size(); i++) { + const DocData::ConstantDoc &const_doc = itype.class_doc->constants[i]; + + if (const_doc.name == iconstant.name) { + iconstant.const_doc = &const_doc; + break; + } + } + + itype.constants.push_back(iconstant); + } + + obj_types.insert(itype.cname, itype); class_list.pop_front(); } @@ -1704,7 +2013,10 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg r_iarg.default_argument = bool(p_val) ? "true" : "false"; break; case Variant::INT: - break; // Keep it + if (r_iarg.type != name_cache.type_int) { + r_iarg.default_argument = "(%s)" + r_iarg.default_argument; + } + break; case Variant::REAL: #ifndef REAL_T_IS_DOUBLE r_iarg.default_argument += "f"; @@ -1762,7 +2074,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg default: {} } - if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type == "Variant" && r_iarg.default_argument != "null") + if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type == name_cache.type_Variant && r_iarg.default_argument != "null") r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; } @@ -1774,7 +2086,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { #define INSERT_STRUCT_TYPE(m_type, m_type_in) \ { \ - itype = TypeInterface::create_value_type(#m_type); \ + itype = TypeInterface::create_value_type(String(#m_type)); \ itype.c_in = "\tMARSHALLED_IN(" #m_type ", %1, %1_in);\n"; \ itype.c_out = "\tMARSHALLED_OUT(" #m_type ", %1, ret_out)\n" \ "\treturn mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(%2), ret_out);\n"; \ @@ -1783,7 +2095,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cs_in = "ref %s"; \ itype.cs_out = "return (" #m_type ")%0;"; \ itype.im_type_out = "object"; \ - builtin_types.insert(#m_type, itype); \ + builtin_types.insert(itype.cname, itype); \ } INSERT_STRUCT_TYPE(Vector2, "real_t*") @@ -1799,22 +2111,22 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { #undef INSERT_STRUCT_TYPE -#define INSERT_PRIMITIVE_TYPE(m_type) \ - { \ - itype = TypeInterface::create_value_type(#m_type); \ - itype.c_arg_in = "&%s"; \ - itype.c_type_in = #m_type; \ - itype.c_type_out = #m_type; \ - itype.im_type_in = #m_type; \ - itype.im_type_out = #m_type; \ - builtin_types.insert(#m_type, itype); \ +#define INSERT_PRIMITIVE_TYPE(m_type) \ + { \ + itype = TypeInterface::create_value_type(String(#m_type)); \ + itype.c_arg_in = "&%s"; \ + itype.c_type_in = #m_type; \ + itype.c_type_out = #m_type; \ + itype.im_type_in = #m_type; \ + itype.im_type_out = #m_type; \ + builtin_types.insert(itype.cname, itype); \ } INSERT_PRIMITIVE_TYPE(bool) //INSERT_PRIMITIVE_TYPE(int) // int - itype = TypeInterface::create_value_type("int"); + itype = TypeInterface::create_value_type(String("int")); itype.c_arg_in = "&%s_in"; //* ptrcall only supports int64_t and uint64_t itype.c_in = "\t%0 %1_in = (%0)%1;\n"; @@ -1825,7 +2137,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.name; itype.im_type_in = itype.name; itype.im_type_out = itype.name; - builtin_types.insert(itype.name, itype); + builtin_types.insert(itype.cname, itype); #undef INSERT_PRIMITIVE_TYPE @@ -1836,6 +2148,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { #else itype.name = "float"; #endif + itype.cname = itype.name; itype.proxy_name = itype.name; itype.c_arg_in = "&%s_in"; //* ptrcall only supports double @@ -1848,11 +2161,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cs_type = itype.proxy_name; itype.im_type_in = itype.proxy_name; itype.im_type_out = itype.proxy_name; - builtin_types.insert(itype.name, itype); + builtin_types.insert(itype.cname, itype); // String itype = TypeInterface(); itype.name = "String"; + itype.cname = itype.name; itype.proxy_name = "string"; itype.c_in = "\t%0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n"; itype.c_out = "\treturn " C_METHOD_MONOSTR_FROM_GODOT "(%1);\n"; @@ -1863,11 +2177,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cs_type = itype.proxy_name; itype.im_type_in = itype.proxy_name; itype.im_type_out = itype.proxy_name; - builtin_types.insert(itype.name, itype); + builtin_types.insert(itype.cname, itype); // NodePath itype = TypeInterface(); itype.name = "NodePath"; + itype.cname = itype.name; itype.proxy_name = "NodePath"; itype.c_out = "\treturn memnew(NodePath(%1));\n"; itype.c_type = itype.name; @@ -1879,16 +2194,17 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; _populate_builtin_type(itype, Variant::NODE_PATH); - extra_members.insert(itype.name, MEMBER_BEGIN "public NodePath() : this(string.Empty) {}\n" MEMBER_BEGIN "public NodePath(string path)\n" OPEN_BLOCK_L2 - "this." BINDINGS_PTR_FIELD " = NativeCalls.godot_icall_NodePath_Ctor(path);\n" CLOSE_BLOCK_L2 - MEMBER_BEGIN "public static implicit operator NodePath(string from)\n" OPEN_BLOCK_L2 "return new NodePath(from);\n" CLOSE_BLOCK_L2 - MEMBER_BEGIN "public static implicit operator string(NodePath from)\n" OPEN_BLOCK_L2 - "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2); - builtin_types.insert(itype.name, itype); + extra_members.insert(itype.cname, MEMBER_BEGIN "public NodePath() : this(string.Empty) {}\n" MEMBER_BEGIN "public NodePath(string path)\n" OPEN_BLOCK_L2 + "this." BINDINGS_PTR_FIELD " = NativeCalls.godot_icall_NodePath_Ctor(path);\n" CLOSE_BLOCK_L2 + MEMBER_BEGIN "public static implicit operator NodePath(string from)\n" OPEN_BLOCK_L2 "return new NodePath(from);\n" CLOSE_BLOCK_L2 + MEMBER_BEGIN "public static implicit operator string(NodePath from)\n" OPEN_BLOCK_L2 + "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2); + builtin_types.insert(itype.cname, itype); // RID itype = TypeInterface(); itype.name = "RID"; + itype.cname = itype.name; itype.proxy_name = "RID"; itype.c_out = "\treturn memnew(RID(%1));\n"; itype.c_type = itype.name; @@ -1900,13 +2216,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; _populate_builtin_type(itype, Variant::_RID); - extra_members.insert(itype.name, MEMBER_BEGIN "internal RID()\n" OPEN_BLOCK_L2 - "this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L2); - builtin_types.insert(itype.name, itype); + extra_members.insert(itype.cname, MEMBER_BEGIN "internal RID()\n" OPEN_BLOCK_L2 + "this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L2); + builtin_types.insert(itype.cname, itype); // Variant itype = TypeInterface(); itype.name = "Variant"; + itype.cname = itype.name; itype.proxy_name = "object"; itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_VARIANT "(%1);\n"; itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_VARIANT "(%1);\n"; @@ -1917,11 +2234,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cs_type = itype.proxy_name; itype.im_type_in = "object"; itype.im_type_out = itype.proxy_name; - builtin_types.insert(itype.name, itype); + builtin_types.insert(itype.cname, itype); // VarArg (fictitious type to represent variable arguments) itype = TypeInterface(); itype.name = "VarArg"; + itype.cname = itype.name; itype.proxy_name = "object[]"; itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(Array) "(%1);\n"; itype.c_arg_in = "&%s_in"; @@ -1929,12 +2247,13 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_in = "MonoArray*"; itype.cs_type = "params object[]"; itype.im_type_in = "object[]"; - builtin_types.insert(itype.name, itype); + builtin_types.insert(itype.cname, itype); #define INSERT_ARRAY_FULL(m_name, m_type, m_proxy_t) \ { \ itype = TypeInterface(); \ itype.name = #m_name; \ + itype.cname = itype.name; \ itype.proxy_name = #m_proxy_t "[]"; \ itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \ itype.c_out = "\treturn " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \ @@ -1971,6 +2290,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { // Dictionary itype = TypeInterface(); itype.name = "Dictionary"; + itype.cname = itype.name; itype.proxy_name = "Dictionary<object, object>"; itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_DICT "(%1);\n"; itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_DICT "(%1);\n"; @@ -1981,11 +2301,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cs_type = itype.proxy_name; itype.im_type_in = itype.proxy_name; itype.im_type_out = itype.proxy_name; - builtin_types.insert(itype.name, itype); + builtin_types.insert(itype.cname, itype); // void (fictitious type to represent the return type of methods that do not return anything) itype = TypeInterface(); itype.name = "void"; + itype.cname = itype.name; itype.proxy_name = itype.name; itype.c_type = itype.name; itype.c_type_in = itype.c_type; @@ -1993,21 +2314,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cs_type = itype.proxy_name; itype.im_type_in = itype.proxy_name; itype.im_type_out = itype.proxy_name; - builtin_types.insert(itype.name, itype); - - // Error - itype = TypeInterface(); - itype.name = "Error"; - itype.proxy_name = "Error"; - itype.c_type = itype.name; - itype.c_type_in = itype.c_type; - itype.c_type_out = itype.c_type; - itype.cs_type = itype.proxy_name; - itype.cs_in = "(int)%0"; - itype.cs_out = "return (Error)%s;"; - itype.im_type_in = "int"; - itype.im_type_out = "int"; - builtin_types.insert(itype.name, itype); + builtin_types.insert(itype.cname, itype); } void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::Type vtype) { @@ -2024,6 +2331,7 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: MethodInterface imethod; imethod.name = mi.name; + imethod.cname = imethod.name; imethod.proxy_name = mi.name; for (int i = 0; i < mi.arguments.size(); i++) { @@ -2033,11 +2341,11 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: iarg.name = pi.name; if (pi.type == Variant::NIL) - iarg.type = "Variant"; + iarg.type = name_cache.type_Variant; else iarg.type = Variant::get_type_name(pi.type); - if (!r_itype.requires_collections && iarg.type == "Dictionary") + if (!r_itype.requires_collections && iarg.type == name_cache.type_Dictionary) r_itype.requires_collections = true; if ((mi.default_arguments.size() - mi.arguments.size() + i) >= 0) @@ -2048,12 +2356,12 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: if (mi.return_val.type == Variant::NIL) { if (mi.return_val.name != "") - imethod.return_type = "Variant"; + imethod.return_type = name_cache.type_Variant; } else { imethod.return_type = Variant::get_type_name(mi.return_val.type); } - if (!r_itype.requires_collections && imethod.return_type == "Dictionary") + if (!r_itype.requires_collections && imethod.return_type == name_cache.type_Dictionary) r_itype.requires_collections = true; if (r_itype.class_doc) { @@ -2069,15 +2377,113 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant:: } } -BindingsGenerator::BindingsGenerator() { +void BindingsGenerator::_populate_global_constants() { + + int global_constants_count = GlobalConstants::get_global_constant_count(); + + if (global_constants_count > 0) { + Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope"); + + ERR_EXPLAIN("Could not find `@GlobalScope` in DocData"); + CRASH_COND(!match); + + const DocData::ClassDoc &global_scope_doc = match->value(); + + for (int i = 0; i < global_constants_count; i++) { + + String constant_name = GlobalConstants::get_global_constant_name(i); + + const DocData::ConstantDoc *const_doc = NULL; + for (int i = 0; i < global_scope_doc.constants.size(); i++) { + const DocData::ConstantDoc &curr_const_doc = global_scope_doc.constants[i]; + + if (curr_const_doc.name == constant_name) { + const_doc = &curr_const_doc; + break; + } + } + + int constant_value = GlobalConstants::get_global_constant_value(i); + StringName enum_name = GlobalConstants::get_global_constant_enum(i); + + ConstantInterface iconstant(snake_to_pascal_case(constant_name, true), constant_value); + iconstant.const_doc = const_doc; + + if (enum_name != StringName()) { + EnumInterface ienum(enum_name); + List<EnumInterface>::Element *match = global_enums.find(ienum); + if (match) { + match->get().constants.push_back(iconstant); + } else { + ienum.constants.push_back(iconstant); + global_enums.push_back(ienum); + } + } else { + global_constants.push_back(iconstant); + } + } + + for (List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) { + EnumInterface &ienum = E->get(); + + TypeInterface enum_itype; + enum_itype = TypeInterface::create_value_type(ienum.cname); + enum_itype.c_arg_in = "&%s"; + enum_itype.c_type = "int"; + enum_itype.c_type_in = "int"; + enum_itype.c_type_out = "int"; + enum_itype.im_type_in = enum_itype.name; + enum_itype.im_type_out = enum_itype.name; + enum_types.insert(enum_itype.cname, enum_itype); + + ienum.prefix = _determine_enum_prefix(ienum); + + // HARDCODED + if (ienum.cname == name_cache.enum_Error) { + if (!ienum.prefix.empty()) { // Just in case it ever changes + ERR_PRINTS("Prefix for enum 'Error' is not empty"); + } + + ienum.prefix = "Err"; + } + } + } + + // HARDCODED + List<StringName> hardcoded_enums; + hardcoded_enums.push_back("Vector3.Axis"); + for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) { + // These enums are not generated and must be written manually (e.g.: Vector3.Axis) + // Here, we are assuming core types do not begin with underscore + TypeInterface enum_itype; + enum_itype = TypeInterface::create_value_type(E->get()); + enum_itype.c_arg_in = "&%s"; + enum_itype.c_type = "int"; + enum_itype.c_type_in = "int"; + enum_itype.c_type_out = "int"; + enum_itype.im_type_in = enum_itype.name; + enum_itype.im_type_out = enum_itype.name; + enum_types.insert(enum_itype.cname, enum_itype); + } +} + +BindingsGenerator::BindingsGenerator() : + name_cache(NameCache::get_singleton()) { EditorHelp::generate_doc(); + enum_types.clear(); + _populate_object_type_interfaces(); _populate_builtin_type_interfaces(); + + _populate_global_constants(); + + // Populate internal calls (after populating type interfaces and global constants) + _generate_header_icalls(); - for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) + for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) _generate_method_icalls(E->get()); _generate_method_icalls(builtin_types["NodePath"]); diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index dfa3aa9911..eac00690ff 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -39,6 +39,47 @@ #include "ustring.h" class BindingsGenerator { + + struct ConstantInterface { + String name; + int value; + const DocData::ConstantDoc *const_doc; + + ConstantInterface() {} + + ConstantInterface(const String &p_name, int p_value) { + name = p_name; + value = p_value; + } + }; + + struct EnumInterface { + StringName cname; + String prefix; + List<ConstantInterface> constants; + + _FORCE_INLINE_ bool operator==(const EnumInterface &p_ienum) const { + return p_ienum.cname == cname; + } + + EnumInterface() {} + + EnumInterface(const StringName &p_cname) { + cname = p_cname; + } + }; + + struct PropertyInterface { + StringName cname; + String proxy_name; + int index; + + StringName setter; + StringName getter; + + const DocData::PropertyDoc *prop_doc; + }; + struct ArgumentInterface { enum DefaultParamMode { CONSTANT, @@ -46,7 +87,7 @@ class BindingsGenerator { NULLABLE_REF }; - String type; + StringName type; String name; String default_argument; DefaultParamMode def_param_mode; @@ -58,6 +99,7 @@ class BindingsGenerator { struct MethodInterface { String name; + StringName cname; /** * Name of the C# method @@ -67,7 +109,7 @@ class BindingsGenerator { /** * [TypeInterface::name] of the return type */ - String return_type; + StringName return_type; /** * Determines if the method has a variable number of arguments (VarArg) @@ -103,7 +145,7 @@ class BindingsGenerator { } MethodInterface() { - return_type = "void"; + return_type = NameCache::get_singleton().type_void; is_vararg = false; is_virtual = false; requires_object_call = false; @@ -118,11 +160,12 @@ class BindingsGenerator { * Also used to format [c_out]. */ String name; + StringName cname; /** * Identifier name of the base class. */ - String base_name; + StringName base_name; /** * Name of the C# class @@ -256,23 +299,32 @@ class BindingsGenerator { const DocData::ClassDoc *class_doc; + List<ConstantInterface> constants; + List<EnumInterface> enums; + List<PropertyInterface> properties; List<MethodInterface> methods; - const MethodInterface *find_method_by_name(const String &p_name) const { - + const MethodInterface *find_method_by_name(const StringName &p_cname) const { for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name == p_name) + if (E->get().cname == p_cname) return &E->get(); } return NULL; } - static TypeInterface create_value_type(const String &p_name) { - TypeInterface itype; + const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const { + for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().proxy_name == p_proxy_name) + return &E->get(); + } - itype.name = p_name; - itype.proxy_name = p_name; + return NULL; + } + + private: + static void _init_value_type(TypeInterface &itype) { + itype.proxy_name = itype.name; itype.c_type = itype.name; itype.c_type_in = "void*"; @@ -281,15 +333,31 @@ class BindingsGenerator { itype.im_type_in = "ref " + itype.proxy_name; itype.im_type_out = itype.proxy_name; itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name]; + } + public: + static TypeInterface create_value_type(const String &p_name) { + TypeInterface itype; + itype.name = p_name; + itype.cname = StringName(p_name); + _init_value_type(itype); + return itype; + } + + static TypeInterface create_value_type(const StringName &p_name) { + TypeInterface itype; + itype.name = p_name.operator String(); + itype.cname = p_name; + _init_value_type(itype); return itype; } - static TypeInterface create_object_type(const String &p_name, ClassDB::APIType p_api_type) { + static TypeInterface create_object_type(const StringName &p_cname, ClassDB::APIType p_api_type) { TypeInterface itype; - itype.name = p_name; - itype.proxy_name = p_name.begins_with("_") ? p_name.substr(1, p_name.length()) : p_name; + itype.name = p_cname; + itype.cname = p_cname; + itype.proxy_name = itype.name.begins_with("_") ? itype.name.substr(1, itype.name.length()) : itype.name; itype.api_type = p_api_type; itype.is_object_type = true; itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name]; @@ -297,9 +365,10 @@ class BindingsGenerator { return itype; } - static void create_placeholder_type(TypeInterface &r_itype, const String &p_name) { - r_itype.name = p_name; - r_itype.proxy_name = p_name; + static void create_placeholder_type(TypeInterface &r_itype, const StringName &p_cname) { + r_itype.name = p_cname; + r_itype.cname = p_cname; + r_itype.proxy_name = r_itype.name; r_itype.c_type = r_itype.name; r_itype.c_type_in = "MonoObject*"; @@ -359,11 +428,15 @@ class BindingsGenerator { static bool verbose_output; - Map<String, TypeInterface> placeholder_types; - Map<String, TypeInterface> builtin_types; - Map<String, TypeInterface> obj_types; + Map<StringName, TypeInterface> placeholder_types; + Map<StringName, TypeInterface> builtin_types; + Map<StringName, TypeInterface> enum_types; + Map<StringName, TypeInterface> obj_types; - Map<String, String> extra_members; + List<EnumInterface> global_enums; + List<ConstantInterface> global_constants; + + Map<StringName, String> extra_members; List<InternalCall> method_icalls; Map<const MethodInterface *, const InternalCall *> method_icalls_map; @@ -373,8 +446,41 @@ class BindingsGenerator { List<InternalCall> core_custom_icalls; List<InternalCall> editor_custom_icalls; - const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) { + struct NameCache { + StringName type_void; + StringName type_int; + StringName type_Array; + StringName type_Dictionary; + StringName type_Variant; + StringName type_VarArg; + StringName type_Object; + StringName type_Reference; + StringName enum_Error; + + NameCache() { + type_void = StaticCString::create("void"); + type_int = StaticCString::create("int"); + type_Array = StaticCString::create("Array"); + type_Dictionary = StaticCString::create("Dictionary"); + type_Variant = StaticCString::create("Variant"); + type_VarArg = StaticCString::create("VarArg"); + type_Object = StaticCString::create("Object"); + type_Reference = StaticCString::create("Reference"); + enum_Error = StaticCString::create("Error"); + } + + static NameCache &get_singleton() { + static NameCache singleton; + return singleton; + } + + NameCache(const NameCache &); + NameCache &operator=(const NameCache &); + }; + + const NameCache &name_cache; + const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) { const List<InternalCall>::Element *it = p_list.front(); while (it) { if (it->get().name == p_name) return it; @@ -392,11 +498,13 @@ class BindingsGenerator { return p_type.name; } + String _determine_enum_prefix(const EnumInterface &p_ienum); + void _generate_header_icalls(); void _generate_method_icalls(const TypeInterface &p_itype); - const TypeInterface *_get_type_by_name_or_null(const String &p_name); - const TypeInterface *_get_type_by_name_or_placeholder(const String &p_name); + const TypeInterface *_get_type_by_name_or_null(const StringName &p_cname); + const TypeInterface *_get_type_by_name_or_placeholder(const StringName &p_cname); void _default_argument_from_variant(const Variant &p_var, ArgumentInterface &r_iarg); void _populate_builtin_type(TypeInterface &r_type, Variant::Type vtype); @@ -404,11 +512,15 @@ class BindingsGenerator { void _populate_object_type_interfaces(); void _populate_builtin_type_interfaces(); + void _populate_global_constants(); + Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file); - Error _generate_cs_property(const TypeInterface &p_itype, const DocData::PropertyDoc &p_prop_doc, List<String> &p_output); + Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_prop_doc, List<String> &p_output); Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output); + void _generate_global_constants(List<String> &p_output); + Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, List<String> &p_output); Error _save_file(const String &path, const List<String> &content); diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp index 9a1efb4423..d5819a4ca3 100644 --- a/modules/mono/editor/csharp_project.cpp +++ b/modules/mono/editor/csharp_project.cpp @@ -54,7 +54,7 @@ String generate_core_api_project(const String &p_dir, const Vector<String> &p_fi ERR_FAIL_V(String()); } - return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : ""; + return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String(); } String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files) { @@ -75,7 +75,7 @@ String generate_editor_api_project(const String &p_dir, const String &p_core_dll ERR_FAIL_V(String()); } - return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : ""; + return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String(); } String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files) { @@ -96,7 +96,7 @@ String generate_game_project(const String &p_dir, const String &p_name, const Ve ERR_FAIL_V(String()); } - return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : ""; + return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String(); } void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) { diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index b88d34fc33..3750a2b02a 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -313,7 +313,7 @@ GodotSharpBuilds *GodotSharpBuilds::singleton = NULL; void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) { BuildProcess *match = builds.getptr(p_build_info); - ERR_FAIL_COND(!match); + ERR_FAIL_NULL(match); BuildProcess &bp = *match; bp.on_exit(p_exit_code); diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 1bc1e8a515..1e61646769 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -50,9 +50,9 @@ GodotSharpEditor *GodotSharpEditor::singleton = NULL; bool GodotSharpEditor::_create_project_solution() { - EditorProgress pr("create_csharp_solution", "Generating solution...", 2); + EditorProgress pr("create_csharp_solution", TTR("Generating solution..."), 2); - pr.step("Generating C# project..."); + pr.step(TTR("Generating C# project...")); String path = OS::get_singleton()->get_resource_dir(); String name = ProjectSettings::get_singleton()->get("application/config/name"); @@ -67,7 +67,7 @@ bool GodotSharpEditor::_create_project_solution() { NETSolution solution(name); if (!solution.set_path(path)) { - show_error_dialog("Failed to create solution."); + show_error_dialog(TTR("Failed to create solution.")); return false; } @@ -79,7 +79,7 @@ bool GodotSharpEditor::_create_project_solution() { Error sln_error = solution.save(); if (sln_error != OK) { - show_error_dialog("Failed to save solution."); + show_error_dialog(TTR("Failed to save solution.")); return false; } @@ -89,13 +89,13 @@ bool GodotSharpEditor::_create_project_solution() { if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR)) return false; - pr.step("Done"); + pr.step(TTR("Done")); // Here, after all calls to progress_task_step call_deferred("_remove_create_sln_menu_option"); } else { - show_error_dialog("Failed to create C# project."); + show_error_dialog(TTR("Failed to create C# project.")); } return true; @@ -194,14 +194,14 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { error_dialog = memnew(AcceptDialog); editor->get_gui_base()->add_child(error_dialog); - bottom_panel_btn = editor->add_bottom_panel_item("Mono", memnew(MonoBottomPanel(editor))); + bottom_panel_btn = editor->add_bottom_panel_item(TTR("Mono"), memnew(MonoBottomPanel(editor))); godotsharp_builds = memnew(GodotSharpBuilds); editor->add_child(memnew(MonoReloadNode)); menu_button = memnew(MenuButton); - menu_button->set_text("Mono"); + menu_button->set_text(TTR("Mono")); menu_popup = menu_button->get_popup(); String sln_path = GodotSharpDirs::get_project_sln_path(); @@ -209,7 +209,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) { bottom_panel_btn->hide(); - menu_popup->add_item("Create C# solution", MENU_CREATE_SLN); + menu_popup->add_item(TTR("Create C# solution"), MENU_CREATE_SLN); } menu_popup->connect("id_pressed", this, "_menu_option_pressed"); diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp index 31dc09856a..be714026ad 100644 --- a/modules/mono/editor/mono_bottom_panel.cpp +++ b/modules/mono/editor/mono_bottom_panel.cpp @@ -197,7 +197,7 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) { panel_builds_tab->add_child(toolbar_hbc); ToolButton *build_project_btn = memnew(ToolButton); - build_project_btn->set_text("Build Project"); + build_project_btn->set_text(TTR("Build Project")); build_project_btn->set_focus_mode(FOCUS_NONE); build_project_btn->connect("pressed", this, "_build_project_pressed"); toolbar_hbc->add_child(build_project_btn); @@ -205,7 +205,7 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) { toolbar_hbc->add_spacer(); warnings_btn = memnew(ToolButton); - warnings_btn->set_text("Warnings"); + warnings_btn->set_text(TTR("Warnings")); warnings_btn->set_toggle_mode(true); warnings_btn->set_pressed(true); warnings_btn->set_visible(false); @@ -214,7 +214,7 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) { toolbar_hbc->add_child(warnings_btn); errors_btn = memnew(ToolButton); - errors_btn->set_text("Errors"); + errors_btn->set_text(TTR("Errors")); errors_btn->set_toggle_mode(true); errors_btn->set_pressed(true); errors_btn->set_visible(false); diff --git a/modules/mono/glue/cs_files/Error.cs b/modules/mono/glue/cs_files/Error.cs deleted file mode 100644 index dee4b88f74..0000000000 --- a/modules/mono/glue/cs_files/Error.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace Godot -{ - public enum Error : int - { - OK = 0, - FAILED = 1, - ERR_UNAVAILABLE = 2, - ERR_UNCONFIGURED = 3, - ERR_UNAUTHORIZED = 4, - ERR_PARAMETER_RANGE_ERROR = 5, - ERR_OUT_OF_MEMORY = 6, - ERR_FILE_NOT_FOUND = 7, - ERR_FILE_BAD_DRIVE = 8, - ERR_FILE_BAD_PATH = 9, - ERR_FILE_NO_PERMISSION = 10, - ERR_FILE_ALREADY_IN_USE = 11, - ERR_FILE_CANT_OPEN = 12, - ERR_FILE_CANT_WRITE = 13, - ERR_FILE_CANT_READ = 14, - ERR_FILE_UNRECOGNIZED = 15, - ERR_FILE_CORRUPT = 16, - ERR_FILE_MISSING_DEPENDENCIES = 17, - ERR_FILE_EOF = 18, - ERR_CANT_OPEN = 19, - ERR_CANT_CREATE = 20, - ERR_PARSE_ERROR = 43, - ERROR_QUERY_FAILED = 21, - ERR_ALREADY_IN_USE = 22, - ERR_LOCKED = 23, - ERR_TIMEOUT = 24, - ERR_CANT_AQUIRE_RESOURCE = 28, - ERR_INVALID_DATA = 30, - ERR_INVALID_PARAMETER = 31, - ERR_ALREADY_EXISTS = 32, - ERR_DOES_NOT_EXIST = 33, - ERR_DATABASE_CANT_READ = 34, - ERR_DATABASE_CANT_WRITE = 35, - ERR_COMPILATION_FAILED = 36, - ERR_METHOD_NOT_FOUND = 37, - ERR_LINK_FAILED = 38, - ERR_SCRIPT_FAILED = 39, - ERR_CYCLIC_LINK = 40, - ERR_BUSY = 44, - ERR_HELP = 46, - ERR_BUG = 47 - } -} diff --git a/modules/mono/glue/cs_files/ExportAttribute.cs b/modules/mono/glue/cs_files/ExportAttribute.cs index dce9cc59a0..e6f569e1bb 100644 --- a/modules/mono/glue/cs_files/ExportAttribute.cs +++ b/modules/mono/glue/cs_files/ExportAttribute.cs @@ -5,13 +5,13 @@ namespace Godot [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class ExportAttribute : Attribute { - private int hint; - private string hint_string; + private PropertyHint hint; + private string hintString; - public ExportAttribute(int hint = GD.PROPERTY_HINT_NONE, string hint_string = "") + public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "") { this.hint = hint; - this.hint_string = hint_string; + this.hintString = hintString; } } } diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs index 99fc289161..b335ef55e4 100644 --- a/modules/mono/glue/cs_files/GD.cs +++ b/modules/mono/glue/cs_files/GD.cs @@ -2,10 +2,8 @@ using System; namespace Godot { - public static class GD + public static partial class GD { - /*{GodotGlobalConstants}*/ - public static object Bytes2Var(byte[] bytes) { return NativeCalls.godot_icall_Godot_bytes2var(bytes); diff --git a/modules/mono/glue/cs_files/Rect2.cs b/modules/mono/glue/cs_files/Rect2.cs index f2718d7b7a..e1fbb65da5 100644 --- a/modules/mono/glue/cs_files/Rect2.cs +++ b/modules/mono/glue/cs_files/Rect2.cs @@ -109,14 +109,14 @@ namespace Godot return g; } - public Rect2 GrowMargin(int margin, float by) + public Rect2 GrowMargin(Margin margin, float by) { Rect2 g = this; - g.GrowIndividual((GD.MARGIN_LEFT == margin) ? by : 0, - (GD.MARGIN_TOP == margin) ? by : 0, - (GD.MARGIN_RIGHT == margin) ? by : 0, - (GD.MARGIN_BOTTOM == margin) ? by : 0); + g.GrowIndividual((Margin.Left == margin) ? by : 0, + (Margin.Top == margin) ? by : 0, + (Margin.Right == margin) ? by : 0, + (Margin.Bottom == margin) ? by : 0); return g; } @@ -230,4 +230,4 @@ namespace Godot }); } } -}
\ No newline at end of file +} diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index eb34f9dd3f..63b24f3ee6 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -290,7 +290,7 @@ int GDMonoField::get_int_value(MonoObject *p_object) { String GDMonoField::get_string_value(MonoObject *p_object) { MonoObject *val = get_value(p_object); - return val ? GDMonoMarshal::mono_string_to_godot((MonoString *)val) : String(); + return GDMonoMarshal::mono_string_to_godot((MonoString *)val); } bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) { diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 8bc2bb5096..d744d24f24 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -490,8 +490,9 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) { return unbox<double>(p_obj); case MONO_TYPE_STRING: { - String str = mono_string_to_godot((MonoString *)p_obj); - return str; + if (p_obj == NULL) + return Variant(); // NIL + return mono_string_to_godot_not_null((MonoString *)p_obj); } break; case MONO_TYPE_VALUETYPE: { diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 443e947fb5..1be4be1a1c 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -62,13 +62,20 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type); String mono_to_utf8_string(MonoString *p_mono_string); String mono_to_utf16_string(MonoString *p_mono_string); -_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) { +_FORCE_INLINE_ String mono_string_to_godot_not_null(MonoString *p_mono_string) { if (sizeof(CharType) == 2) return mono_to_utf16_string(p_mono_string); return mono_to_utf8_string(p_mono_string); } +_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) { + if (p_mono_string == NULL) + return String(); + + return mono_string_to_godot_not_null(p_mono_string); +} + _FORCE_INLINE_ MonoString *mono_from_utf8_string(const String &p_string) { return mono_string_new(mono_domain_get(), p_string.utf8().get_data()); } diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 1cccd0ad9d..638636e985 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -95,7 +95,7 @@ void MonoCache::clear_members() { class_ExportAttribute = NULL; field_ExportAttribute_hint = NULL; - field_ExportAttribute_hint_string = NULL; + field_ExportAttribute_hintString = NULL; class_ToolAttribute = NULL; class_RemoteAttribute = NULL; class_SyncAttribute = NULL; @@ -163,7 +163,7 @@ void update_godot_api_cache() { // Attributes CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); - CACHE_FIELD_AND_CHECK(ExportAttribute, hint_string, CACHED_CLASS(ExportAttribute)->get_field("hint_string")); + CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString")); CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute)); CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute)); CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute)); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index c38f8c5af5..4308b357ba 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -97,7 +97,7 @@ struct MonoCache { GDMonoClass *class_ExportAttribute; GDMonoField *field_ExportAttribute_hint; - GDMonoField *field_ExportAttribute_hint_string; + GDMonoField *field_ExportAttribute_hintString; GDMonoClass *class_ToolAttribute; GDMonoClass *class_RemoteAttribute; GDMonoClass *class_SyncAttribute; diff --git a/modules/opus/register_types.cpp b/modules/opus/register_types.cpp index a69c8bf9f3..6d7a3575ed 100644 --- a/modules/opus/register_types.cpp +++ b/modules/opus/register_types.cpp @@ -34,13 +34,18 @@ static ResourceFormatLoaderAudioStreamOpus *opus_stream_loader = NULL; void register_opus_types() { - - opus_stream_loader = memnew(ResourceFormatLoaderAudioStreamOpus); - ResourceLoader::add_resource_format_loader(opus_stream_loader); - ClassDB::register_class<AudioStreamOpus>(); + // Sorry guys, do not enable this unless you can figure out a way + // to get Opus to not do any memory allocation or system calls + // in the audio thread. + // Currently the implementation even reads files from the audio thread, + // and this is not how audio programming works. + + //opus_stream_loader = memnew(ResourceFormatLoaderAudioStreamOpus); + //ResourceLoader::add_resource_format_loader(opus_stream_loader); + //ClassDB::register_class<AudioStreamOpus>(); } void unregister_opus_types() { - memdelete(opus_stream_loader); + //memdelete(opus_stream_loader); } diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 5b04ab8826..2e686fbee4 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -82,9 +82,6 @@ def configure(env): env['RANLIB'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib" env['AS'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as" env.Append(CCFLAGS=['-D__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define - if env['tools'] and env['openmp']: - env.Append(CPPFLAGS=['-fopenmp']) - env.Append(LINKFLAGS=['-fopenmp']) else: # osxcross build root = os.environ.get("OSXCROSS_ROOT", 0) diff --git a/platform/windows/detect.py b/platform/windows/detect.py index e216868bd8..3b8de2caf4 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -191,8 +191,6 @@ def configure(env): if (env["use_lto"]): env.Append(CCFLAGS=['/GL']) env.Append(LINKFLAGS=['/LTCG']) - if env['tools'] and env['openmp']: - env.Append(CPPFLAGS=['/openmp']) env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")]) env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) @@ -270,9 +268,6 @@ def configure(env): env.Append(CCFLAGS=['-flto']) env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))]) - if env['tools'] and env['openmp']: - env.Append(CPPFLAGS=['-fopenmp']) - env.Append(LINKFLAGS=['-fopenmp']) ## Compile flags diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 98ae9a8658..cb45fed1be 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -265,9 +265,5 @@ def configure(env): env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu']) - if env['tools'] and env['openmp']: - env.Append(CPPFLAGS=['-fopenmp']) - env.Append(LINKFLAGS=['-fopenmp']) - if env['use_static_cpp']: env.Append(LINKFLAGS=['-static-libstdc++']) diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 6616e47317..f3f4b1f217 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -1050,6 +1050,10 @@ void OS_X11::set_window_maximized(bool p_enabled) { XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + while (p_enabled && !is_window_maximized()) { + // Wait for effective resizing (so the GLX context is too). + } + maximized = p_enabled; } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 7b30ddaa56..a83c1c1cad 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1527,7 +1527,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("_recreate_quadrants"), &TileMap::_recreate_quadrants); ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants); - ClassDB::bind_method(D_METHOD("update_bitmask_area"), &TileMap::update_bitmask_area); + ClassDB::bind_method(D_METHOD("update_bitmask_area", "position"), &TileMap::update_bitmask_area); ClassDB::bind_method(D_METHOD("update_bitmask_region", "start", "end"), &TileMap::update_bitmask_region, DEFVAL(Vector2()), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("_set_tile_data"), &TileMap::_set_tile_data); diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 9a77626296..8c282a31b8 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -772,8 +772,8 @@ void BakedLightmap::_bind_methods() { BakedLightmap::BakedLightmap() { extents = Vector3(10, 10, 10); - bake_cell_size = 0.1; - capture_cell_size = 0.25; + bake_cell_size = 0.25; + capture_cell_size = 0.5; bake_quality = BAKE_QUALITY_MEDIUM; bake_mode = BAKE_MODE_CONE_TRACE; diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index c74abb7e2d..7143310036 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -70,6 +70,9 @@ void Camera::_validate_property(PropertyInfo &p_property) const { void Camera::_update_camera() { + if (!is_inside_tree()) + return; + Transform tr = get_camera_transform(); tr.origin += tr.basis.get_axis(1) * v_offset; tr.origin += tr.basis.get_axis(0) * h_offset; @@ -81,7 +84,7 @@ void Camera::_update_camera() { get_viewport()->_camera_transform_changed_notify(); */ - if (!is_inside_tree() || get_tree()->is_node_being_edited(this) || !is_current()) + if (get_tree()->is_node_being_edited(this) || !is_current()) return; get_viewport()->_camera_transform_changed_notify(); diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index d9f88ac693..e890533ab7 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -558,27 +558,27 @@ bool Spatial::is_visible() const { void Spatial::rotate(const Vector3 &p_normal, float p_radians) { Transform t = get_transform(); - t.basis.rotate(p_normal, p_radians); + t.basis.rotate_local(p_normal, p_radians); //use local rotation here, as it makes more sense here in tree hierarchy set_transform(t); } void Spatial::rotate_x(float p_radians) { Transform t = get_transform(); - t.basis.rotate(Vector3(1, 0, 0), p_radians); + t.basis.rotate_local(Vector3(1, 0, 0), p_radians); set_transform(t); } void Spatial::rotate_y(float p_radians) { Transform t = get_transform(); - t.basis.rotate(Vector3(0, 1, 0), p_radians); + t.basis.rotate_local(Vector3(0, 1, 0), p_radians); set_transform(t); } void Spatial::rotate_z(float p_radians) { Transform t = get_transform(); - t.basis.rotate(Vector3(0, 0, 1), p_radians); + t.basis.rotate_local(Vector3(0, 0, 1), p_radians); set_transform(t); } diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index bf0f801e32..bd7e52d947 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -30,11 +30,9 @@ #include "voxel_light_baker.h" #include "os/os.h" +#include "os/threaded_array_processor.h" #include <stdlib.h> -#ifdef _OPENMP -#include <omp.h> -#endif #define FINDMINMAX(x0, x1, x2, min, max) \ min = max = x0; \ @@ -1689,7 +1687,7 @@ _ALWAYS_INLINE_ uint32_t xorshift32(uint32_t *state) { return x; } -Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal, uint32_t *rng_state) { +Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) { int samples_per_quality[3] = { 48, 128, 512 }; @@ -1711,8 +1709,7 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V const Light *light = bake_light.ptr(); const Cell *cells = bake_cells.ptr(); - // Prevent false sharing when running on OpenMP - uint32_t local_rng_state = *rng_state; + uint32_t local_rng_state = rand(); //needs to be fixed again for (int i = 0; i < samples; i++) { @@ -1796,10 +1793,28 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V } // Make sure we don't reset this thread's RNG state - *rng_state = local_rng_state; + return accum / samples; } +void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) { + + LightMap *pixel = &p_line[p_x]; + if (pixel->pos == Vector3()) + return; + //print_line("pos: " + pixel->pos + " normal " + pixel->normal); + switch (bake_mode) { + case BAKE_MODE_CONE_TRACE: { + pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy; + } break; + case BAKE_MODE_RAY_TRACE: { + pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy; + } break; + // pixel->light = Vector3(1, 1, 1); + //} + } +} + Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) { //transfer light information to a lightmap @@ -1862,53 +1877,10 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh volatile int lines = 0; // make sure our OS-level rng is seeded - srand(OS::get_singleton()->get_ticks_usec()); - - // setup an RNG state for each OpenMP thread - uint32_t threadcount = 1; - uint32_t threadnum = 0; -#ifdef _OPENMP - threadcount = omp_get_max_threads(); -#endif - Vector<uint32_t> rng_states; - rng_states.resize(threadcount); - for (uint32_t i = 0; i < threadcount; i++) { - do { - rng_states[i] = rand(); - } while (rng_states[i] == 0); - } - uint32_t *rng_states_p = rng_states.ptrw(); for (int i = 0; i < height; i++) { - //print_line("bake line " + itos(i) + " / " + itos(height)); -#ifdef _OPENMP -#pragma omp parallel for schedule(dynamic, 1) private(threadnum) -#endif - for (int j = 0; j < width; j++) { - -#ifdef _OPENMP - threadnum = omp_get_thread_num(); -#endif - - //if (i == 125 && j == 280) { - - LightMap *pixel = &lightmap_ptr[i * width + j]; - if (pixel->pos == Vector3()) - continue; //unused, skipe - - //print_line("pos: " + pixel->pos + " normal " + pixel->normal); - switch (bake_mode) { - case BAKE_MODE_CONE_TRACE: { - pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy; - } break; - case BAKE_MODE_RAY_TRACE: { - pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal, &rng_states_p[threadnum]) * energy; - } break; - // pixel->light = Vector3(1, 1, 1); - //} - } - } + thread_process_array(width, this, &VoxelLightBaker::_lightmap_bake_point, &lightmap_ptr[i * width]); lines = MAX(lines, i); //for multithread if (p_bake_time_func) { diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h index 7db31f8a67..68e11c356b 100644 --- a/scene/3d/voxel_light_baker.h +++ b/scene/3d/voxel_light_baker.h @@ -148,9 +148,12 @@ private: _FORCE_INLINE_ void _sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha); _FORCE_INLINE_ Vector3 _voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture); _FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); - _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal, uint32_t *rng_state); + _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); + + void _lightmap_bake_point(uint32_t p_x, LightMap *p_line); public: + void begin_bake(int p_subdiv, const AABB &p_bounds); void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material); void begin_bake_light(BakeQuality p_quality = BAKE_QUALITY_MEDIUM, BakeMode p_bake_mode = BAKE_MODE_CONE_TRACE, float p_propagation = 0.85, float p_energy = 1); diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 32f82fe6b8..a50047e426 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -386,8 +386,6 @@ bool AnimationTreePlayer::_get(const StringName &p_name, Variant &r_ret) const { void AnimationTreePlayer::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::NODE_PATH, "base_path")); - p_list->push_back(PropertyInfo(Variant::NODE_PATH, "master_player")); p_list->push_back(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK)); } @@ -1140,6 +1138,9 @@ void AnimationTreePlayer::transition_node_set_input_count(const StringName &p_no n->inputs.resize(p_inputs); n->input_data.resize(p_inputs); + + _clear_cycle_test(); + last_error = _cycle_test(out_name); } void AnimationTreePlayer::transition_node_set_input_auto_advance(const StringName &p_node, int p_input, bool p_auto_advance) { @@ -1360,6 +1361,8 @@ void AnimationTreePlayer::remove_node(const StringName &p_node) { node_map.erase(p_node); + _clear_cycle_test(); + // compute last error again, just in case last_error = _cycle_test(out_name); dirty_caches = true; @@ -1387,6 +1390,14 @@ AnimationTreePlayer::ConnectError AnimationTreePlayer::_cycle_test(const StringN return CONNECT_OK; } +// Use this function to not alter next complete _cycle_test(). +void AnimationTreePlayer::_clear_cycle_test() { + for (Map<StringName, NodeBase *>::Element *E = node_map.front(); E; E = E->next()) { + NodeBase *nb = E->get(); + nb->cycletest = false; + } +} + Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const StringName &p_dst_node, int p_dst_input) { ERR_FAIL_COND_V(!node_map.has(p_src_node), ERR_INVALID_PARAMETER); @@ -1411,11 +1422,7 @@ Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const Str dst->inputs[p_dst_input].node = p_src_node; - for (Map<StringName, NodeBase *>::Element *E = node_map.front(); E; E = E->next()) { - - NodeBase *nb = E->get(); - nb->cycletest = false; - } + _clear_cycle_test(); last_error = _cycle_test(out_name); if (last_error) { diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h index c49b0c4d1b..7213441d6e 100644 --- a/scene/animation/animation_tree_player.h +++ b/scene/animation/animation_tree_player.h @@ -317,6 +317,7 @@ private: bool reset_request; ConnectError _cycle_test(const StringName &p_at_node); + void _clear_cycle_test(); Track *_find_track(const NodePath &p_path); void _recompute_caches(); diff --git a/scene/gui/button.h b/scene/gui/button.h index 35488582de..5c5a73bae3 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -56,7 +56,6 @@ private: float _internal_margin[4]; protected: - virtual Size2 get_minimum_size() const; void _set_internal_margin(Margin p_margin, float p_value); void _notification(int p_what); static void _bind_methods(); @@ -64,6 +63,8 @@ protected: public: // + virtual Size2 get_minimum_size() const; + void set_text(const String &p_text); String get_text() const; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index cb6283507e..446676e80d 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -39,33 +39,32 @@ void ColorPicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - //sample->set_texture(get_icon("color_sample")); + btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); bt_add_preset->set_icon(get_icon("add_preset")); _update_controls(); } break; - case NOTIFICATION_ENTER_TREE: { + btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); bt_add_preset->set_icon(get_icon("add_preset")); _update_color(); } break; - case NOTIFICATION_PARENTED: { + for (int i = 0; i < 4; i++) set_margin((Margin)i, get_constant("margin")); } break; - case NOTIFICATION_VISIBILITY_CHANGED: { Popup *p = Object::cast_to<Popup>(get_parent()); if (p) p->set_size(Size2(get_combined_minimum_size().width + get_constant("margin") * 2, get_combined_minimum_size().height + get_constant("margin") * 2)); } break; - case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { + if (screen != NULL) { if (screen->is_visible()) { screen->hide(); @@ -523,7 +522,6 @@ ColorPicker::ColorPicker() : add_child(hb_edit); w_edit = memnew(Control); - //w_edit->set_ignore_mouse(false); w_edit->set_custom_minimum_size(Size2(get_constant("h_width"), 0)); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); @@ -589,7 +587,6 @@ ColorPicker::ColorPicker() : c_text->set_h_size_flags(SIZE_EXPAND_FILL); _update_controls(); - //_update_color(); updating = false; set_pick_color(Color(1, 1, 1)); @@ -599,7 +596,6 @@ ColorPicker::ColorPicker() : preset = memnew(TextureRect); bbc->add_child(preset); - //preset->set_ignore_mouse(false); preset->connect("gui_input", this, "_preset_input"); preset->connect("draw", this, "_update_presets"); @@ -660,11 +656,13 @@ bool ColorPickerButton::is_editing_alpha() const { return picker->is_editing_alpha(); } -ColorPicker *ColorPickerButton::get_picker() { +ColorPicker *ColorPickerButton::get_picker() const { + return picker; } -PopupPanel *ColorPickerButton::get_popup() { +PopupPanel *ColorPickerButton::get_popup() const { + return popup; } diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index c02cdc8608..2bae279ed5 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -129,8 +129,8 @@ public: void set_edit_alpha(bool p_show); bool is_editing_alpha() const; - ColorPicker *get_picker(); - PopupPanel *get_popup(); + ColorPicker *get_picker() const; + PopupPanel *get_popup() const; ColorPickerButton(); }; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index d850553957..c235797bef 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -33,6 +33,9 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) { + if (disable_shortcuts) + return; + if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event))) { if (!get_parent() || !is_visible_in_tree() || is_disabled()) @@ -60,25 +63,10 @@ void MenuButton::pressed() { void MenuButton::_gui_input(Ref<InputEvent> p_event) { - /*if (p_event.type==InputEvent::MOUSE_BUTTON && p_event->get_button_index()==BUTTON_LEFT) { - clicked=p_event->is_pressed(); - } - if (clicked && p_event.type==InputEvent::MOUSE_MOTION && popup->is_visible_in_tree()) { - - Point2 gt = Point2(p_event.mouse_motion.x,p_event.mouse_motion.y); - gt = get_global_transform().xform(gt); - Point2 lt = popup->get_transform().affine_inverse().xform(gt); - if (popup->has_point(lt)) { - //print_line("HAS POINT!!!"); - popup->call_deferred("grab_click_focus"); - } - - }*/ - BaseButton::_gui_input(p_event); } -PopupMenu *MenuButton::get_popup() { +PopupMenu *MenuButton::get_popup() const { return popup; } @@ -98,14 +86,22 @@ void MenuButton::_bind_methods() { ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &MenuButton::_unhandled_key_input); ClassDB::bind_method(D_METHOD("_set_items"), &MenuButton::_set_items); ClassDB::bind_method(D_METHOD("_get_items"), &MenuButton::_get_items); + ClassDB::bind_method(D_METHOD("set_disable_shortcuts", "disabled"), &MenuButton::set_disable_shortcuts); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items"); ADD_SIGNAL(MethodInfo("about_to_show")); } + +void MenuButton::set_disable_shortcuts(bool p_disabled) { + + disable_shortcuts = p_disabled; +} + MenuButton::MenuButton() { set_flat(true); + set_disable_shortcuts(false); set_enabled_focus_mode(FOCUS_NONE); popup = memnew(PopupMenu); popup->hide(); diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index c7f1d976ff..1bd9b155b2 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -40,6 +40,7 @@ class MenuButton : public Button { GDCLASS(MenuButton, Button); bool clicked; + bool disable_shortcuts; PopupMenu *popup; virtual void pressed(); @@ -53,7 +54,9 @@ protected: static void _bind_methods(); public: - PopupMenu *get_popup(); + PopupMenu *get_popup() const; + void set_disable_shortcuts(bool p_disabled); + MenuButton(); ~MenuButton(); }; diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 70f3d9ca83..6f784b56de 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -42,38 +42,35 @@ Size2 OptionButton::get_minimum_size() const { void OptionButton::_notification(int p_what) { - switch (p_what) { - - case NOTIFICATION_DRAW: { - - if (!has_icon("arrow")) - return; - - RID ci = get_canvas_item(); - Ref<Texture> arrow = Control::get_icon("arrow"); - Ref<StyleBox> normal = get_stylebox("normal"); - Color clr = Color(1, 1, 1); - if (get_constant("modulate_arrow")) - switch (get_draw_mode()) { - case DRAW_PRESSED: - clr = get_color("font_color_pressed"); - break; - case DRAW_HOVER: - clr = get_color("font_color_hover"); - break; - case DRAW_DISABLED: - clr = get_color("font_color_disabled"); - break; - default: - clr = get_color("font_color"); - } - - Size2 size = get_size(); - - Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); - arrow->draw(ci, ofs, clr); - - } break; + if (p_what == NOTIFICATION_DRAW) { + + if (!has_icon("arrow")) + return; + + RID ci = get_canvas_item(); + Ref<Texture> arrow = Control::get_icon("arrow"); + Ref<StyleBox> normal = get_stylebox("normal"); + Color clr = Color(1, 1, 1); + if (get_constant("modulate_arrow")) { + switch (get_draw_mode()) { + case DRAW_PRESSED: + clr = get_color("font_color_pressed"); + break; + case DRAW_HOVER: + clr = get_color("font_color_hover"); + break; + case DRAW_DISABLED: + clr = get_color("font_color_disabled"); + break; + default: + clr = get_color("font_color"); + } + } + + Size2 size = get_size(); + + Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); + arrow->draw(ci, ofs, clr); } } @@ -244,6 +241,11 @@ void OptionButton::remove_item(int p_idx) { popup->remove_item(p_idx); } +PopupMenu *OptionButton::get_popup() const { + + return popup; +} + Array OptionButton::_get_items() const { Array items; @@ -310,6 +312,8 @@ void OptionButton::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_item", "idx"), &OptionButton::remove_item); ClassDB::bind_method(D_METHOD("_select_int"), &OptionButton::_select_int); + ClassDB::bind_method(D_METHOD("get_popup"), &OptionButton::get_popup); + ClassDB::bind_method(D_METHOD("_set_items"), &OptionButton::_set_items); ClassDB::bind_method(D_METHOD("_get_items"), &OptionButton::_get_items); @@ -320,15 +324,16 @@ void OptionButton::_bind_methods() { OptionButton::OptionButton() { + current = -1; + set_text_align(ALIGN_LEFT); + set_action_mode(ACTION_MODE_BUTTON_PRESS); + popup = memnew(PopupMenu); popup->hide(); + add_child(popup); popup->set_as_toplevel(true); popup->set_pass_on_modal_close_click(false); - add_child(popup); popup->connect("id_pressed", this, "_selected"); - - current = -1; - set_text_align(ALIGN_LEFT); } OptionButton::~OptionButton() { diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index a06c540678..b09942b072 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -85,6 +85,8 @@ public: void remove_item(int p_idx); + PopupMenu *get_popup() const; + virtual void get_translatable_strings(List<String> *p_strings) const; OptionButton(); diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 4420a936d2..1c15953517 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -61,7 +61,7 @@ Control *SplitContainer::_getch(int p_idx) const { void SplitContainer::_resort() { - /** First pass, determine minimum size AND amount of stretchable elements */ + /* First pass, determine minimum size AND amount of stretchable elements */ int axis = vertical ? 1 : 0; @@ -114,10 +114,8 @@ void SplitContainer::_resort() { Size2 ms_second = second->get_combined_minimum_size(); if (vertical) { - minimum = ms_first.height + ms_second.height; } else { - minimum = ms_first.width + ms_second.width; } @@ -141,12 +139,10 @@ void SplitContainer::_resort() { } else if (expand_first_mode) { middle_sep = get_size()[axis] - ms_second[axis] - sep; - } else { middle_sep = ms_first[axis]; } - } else if (ratiomode) { int first_ratio = first->get_stretch_ratio(); @@ -160,23 +156,19 @@ void SplitContainer::_resort() { expand_ofs = (available * (1.0 - ratio)); middle_sep = ms_first[axis] + available * ratio + expand_ofs; - } else if (expand_first_mode) { if (expand_ofs > 0) expand_ofs = 0; - - if (expand_ofs < -available) + else if (expand_ofs < -available) expand_ofs = -available; middle_sep = get_size()[axis] - ms_second[axis] - sep + expand_ofs; - } else { if (expand_ofs < 0) expand_ofs = 0; - - if (expand_ofs > available) + else if (expand_ofs > available) expand_ofs = available; middle_sep = ms_first[axis] + expand_ofs; @@ -187,7 +179,6 @@ void SplitContainer::_resort() { fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep))); int sofs = middle_sep + sep; fit_child_in_rect(second, Rect2(Point2(0, sofs), Size2(get_size().width, get_size().height - sofs))); - } else { fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(middle_sep, get_size().height))); @@ -246,10 +237,12 @@ void SplitContainer::_notification(int p_what) { _resort(); } break; case NOTIFICATION_MOUSE_ENTER: { + mouse_inside = true; update(); } break; case NOTIFICATION_MOUSE_EXIT: { + mouse_inside = false; update(); } break; @@ -260,22 +253,17 @@ void SplitContainer::_notification(int p_what) { if (collapsed || (!mouse_inside && get_constant("autohide"))) return; + int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_constant("separation") : 0; Ref<Texture> tex = get_icon("grabber"); Size2 size = get_size(); - if (vertical) { + if (dragger_visibility == DRAGGER_VISIBLE) { - //draw_style_box( get_stylebox("bg"), Rect2(0,middle_sep,get_size().width,sep)); - if (dragger_visibility == DRAGGER_VISIBLE) + if (vertical) draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2)); - - } else { - - //draw_style_box( get_stylebox("bg"), Rect2(middle_sep,0,sep,get_size().height)); - if (dragger_visibility == DRAGGER_VISIBLE) + else draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2)); } - } break; } } @@ -292,11 +280,13 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { if (mb->get_button_index() == BUTTON_LEFT) { if (mb->is_pressed()) { + int sep = get_constant("separation"); if (vertical) { if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + sep) { + dragging = true; drag_from = mb->get_position().y; drag_ofs = expand_ofs; @@ -304,6 +294,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { } else { if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + sep) { + dragging = true; drag_from = mb->get_position().x; drag_ofs = expand_ofs; @@ -318,36 +309,31 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm = p_event; - if (mm.is_valid()) { - - if (dragging) { + if (mm.is_valid() && dragging) { - expand_ofs = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from); - queue_sort(); - emit_signal("dragged", get_split_offset()); - } + expand_ofs = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from); + queue_sort(); + emit_signal("dragged", get_split_offset()); } } Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const { - if (collapsed) - return Control::get_cursor_shape(p_pos); - if (dragging) return (vertical ? CURSOR_VSIZE : CURSOR_HSIZE); - int sep = get_constant("separation"); + if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) { - if (vertical) { + int sep = get_constant("separation"); - if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) { - return CURSOR_VSIZE; - } - } else { + if (vertical) { - if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) { - return CURSOR_HSIZE; + if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) + return CURSOR_VSIZE; + } else { + + if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) + return CURSOR_HSIZE; } } @@ -358,6 +344,7 @@ void SplitContainer::set_split_offset(int p_offset) { if (expand_ofs == p_offset) return; + expand_ofs = p_offset; queue_sort(); } @@ -371,6 +358,7 @@ void SplitContainer::set_collapsed(bool p_collapsed) { if (collapsed == p_collapsed) return; + collapsed = p_collapsed; queue_sort(); } diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index c7a484c4c5..40a58d4b32 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -88,7 +88,7 @@ class HSplitContainer : public SplitContainer { public: HSplitContainer() : - SplitContainer(false) { set_default_cursor_shape(CURSOR_HSPLIT); } + SplitContainer(false) {} }; class VSplitContainer : public SplitContainer { @@ -97,7 +97,7 @@ class VSplitContainer : public SplitContainer { public: VSplitContainer() : - SplitContainer(true) { set_default_cursor_shape(CURSOR_VSPLIT); } + SplitContainer(true) {} }; #endif // SPLIT_CONTAINER_H diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 07f1bdf8e5..0fba4a6f94 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1695,10 +1695,9 @@ void TextEdit::indent_right() { // fix selection and cursor being off by one on the last line if (is_selection_active()) { - selection.to_column++; - selection.from_column++; + select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1); } - cursor.column++; + cursor_set_column(cursor.column + 1, false); end_complex_operation(); update(); } @@ -1737,14 +1736,9 @@ void TextEdit::indent_left() { // fix selection and cursor being off by one on the last line if (is_selection_active() && last_line_text != get_line(end_line)) { - if (selection.to_column > 0) - selection.to_column--; - if (selection.from_column > 0) - selection.from_column--; - } - if (cursor.column > 0) { - cursor.column--; + select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1); } + cursor_set_column(cursor.column - 1, false); end_complex_operation(); update(); } @@ -1973,6 +1967,31 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { + _reset_caret_blink_timer(); + + int row, col; + update_line_scroll_pos(); + _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); + + if (is_right_click_moving_caret()) { + if (is_selection_active()) { + + int from_line = get_selection_from_line(); + int to_line = get_selection_to_line(); + int from_column = get_selection_from_column(); + int to_column = get_selection_to_column(); + + if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { + // Right click is outside the seleted text + deselect(); + } + } + if (!is_selection_active()) { + cursor_set_line(row, true, false); + cursor_set_column(col); + } + } + menu->set_position(get_global_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); menu->popup(); @@ -3708,6 +3727,14 @@ bool TextEdit::cursor_is_block_mode() const { return block_caret; } +void TextEdit::set_right_click_moves_caret(bool p_enable) { + right_click_moves_caret = p_enable; +} + +bool TextEdit::is_right_click_moving_caret() const { + return right_click_moves_caret; +} + void TextEdit::_v_scroll_input() { scrolling = false; } @@ -4168,11 +4195,15 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t p_from_line = text.size() - 1; if (p_from_column >= text[p_from_line].length()) p_from_column = text[p_from_line].length(); + if (p_from_column < 0) + p_from_column = 0; if (p_to_line >= text.size()) p_to_line = text.size() - 1; if (p_to_column >= text[p_to_line].length()) p_to_column = text[p_to_line].length(); + if (p_to_column < 0) + p_to_column = 0; selection.from_line = p_from_line; selection.from_column = p_from_column; @@ -5457,6 +5488,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("cursor_set_block_mode", "enable"), &TextEdit::cursor_set_block_mode); ClassDB::bind_method(D_METHOD("cursor_is_block_mode"), &TextEdit::cursor_is_block_mode); + ClassDB::bind_method(D_METHOD("set_right_click_moves_caret", "enable"), &TextEdit::set_right_click_moves_caret); + ClassDB::bind_method(D_METHOD("is_right_click_moving_caret"), &TextEdit::is_right_click_moving_caret); + ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly); ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly); @@ -5492,7 +5526,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled); ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden); - ClassDB::bind_method(D_METHOD("is_line_hidden"), &TextEdit::is_line_hidden); + ClassDB::bind_method(D_METHOD("is_line_hidden", "line"), &TextEdit::is_line_hidden); ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines); ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines); ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line); @@ -5540,6 +5574,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled"); ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "cursor_set_blink_speed", "cursor_get_blink_speed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_moving_by_right_click"), "set_right_click_moves_caret", "is_right_click_moving_caret"); ADD_SIGNAL(MethodInfo("cursor_changed")); ADD_SIGNAL(MethodInfo("text_changed")); @@ -5617,6 +5652,7 @@ TextEdit::TextEdit() { caret_blink_timer->set_wait_time(0.65); caret_blink_timer->connect("timeout", this, "_toggle_draw_caret"); cursor_set_blink_enabled(false); + right_click_moves_caret = true; idle_detect = memnew(Timer); add_child(idle_detect); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 836d5c7388..f18eaa85cb 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -246,6 +246,7 @@ class TextEdit : public Control { bool draw_caret; bool window_has_focus; bool block_caret; + bool right_click_moves_caret; bool setting_row; bool wrap; @@ -481,6 +482,9 @@ public: void cursor_set_block_mode(const bool p_enable); bool cursor_is_block_mode() const; + void set_right_click_moves_caret(bool p_enable); + bool is_right_click_moving_caret() const; + void set_readonly(bool p_readonly); bool is_readonly() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index b5b42e8f29..51ad22e271 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1775,7 +1775,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool case TreeItem::CELL_MODE_STRING: { //nothing in particular - if (select_mode == SELECT_MULTI && (get_tree()->get_last_event_id() == focus_in_id || !already_cursor)) { + if (select_mode == SELECT_MULTI && (get_tree()->get_event_count() == focus_in_id || !already_cursor)) { bring_up_editor = false; } @@ -1863,7 +1863,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool } else { editor_text = String::num(p_item->cells[col].val, Math::step_decimals(p_item->cells[col].step)); - if (select_mode == SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id) + if (select_mode == SELECT_MULTI && get_tree()->get_event_count() == focus_in_id) bring_up_editor = false; } } @@ -2786,7 +2786,7 @@ void Tree::_notification(int p_what) { if (p_what == NOTIFICATION_FOCUS_ENTER) { - focus_in_id = get_tree()->get_last_event_id(); + focus_in_id = get_tree()->get_event_count(); } if (p_what == NOTIFICATION_MOUSE_EXIT) { @@ -2950,43 +2950,51 @@ Size2 Tree::get_minimum_size() const { return Size2(1, 1); } -TreeItem *Tree::create_item(TreeItem *p_parent) { +TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) { ERR_FAIL_COND_V(blocked > 0, NULL); - TreeItem *ti = memnew(TreeItem(this)); - - ERR_FAIL_COND_V(!ti, NULL); - ti->cells.resize(columns.size()); + TreeItem *ti = NULL; if (p_parent) { - /* Always append at the end */ + // Append or insert a new item to the given parent. + ti = memnew(TreeItem(this)); + ERR_FAIL_COND_V(!ti, NULL); + ti->cells.resize(columns.size()); - TreeItem *last = 0; + TreeItem *prev = NULL; TreeItem *c = p_parent->childs; + int idx = 0; while (c) { - - last = c; + if (idx++ == p_idx) { + ti->next = c; + break; + } + prev = c; c = c->next; } - if (last) { - - last->next = ti; - } else { - + if (prev) + prev->next = ti; + else p_parent->childs = ti; - } ti->parent = p_parent; } else { - if (root) - ti->childs = root; + if (!root) { + // No root exists, make the given item the new root. + ti = memnew(TreeItem(this)); + ERR_FAIL_COND_V(!ti, NULL); + ti->cells.resize(columns.size()); - root = ti; + root = ti; + } else { + // Root exists, append or insert to root. + ti = create_item(root, p_idx); + } } return ti; @@ -3723,7 +3731,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("_scroll_moved"), &Tree::_scroll_moved); ClassDB::bind_method(D_METHOD("clear"), &Tree::clear); - ClassDB::bind_method(D_METHOD("create_item", "parent"), &Tree::_create_item, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::_create_item, DEFVAL(Variant()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root); ClassDB::bind_method(D_METHOD("set_column_min_width", "column", "min_width"), &Tree::set_column_min_width); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 112de3165f..b8d94bcffb 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -359,7 +359,7 @@ private: LineEdit *text_editor; HSlider *value_editor; bool updating_value_editor; - uint32_t focus_in_id; + int64_t focus_in_id; PopupMenu *popup_menu; Vector<ColumnInfo> columns; @@ -511,8 +511,8 @@ protected: static void _bind_methods(); //bind helpers - Object *_create_item(Object *p_parent) { - return create_item(Object::cast_to<TreeItem>(p_parent)); + Object *_create_item(Object *p_parent, int p_idx = -1) { + return create_item(Object::cast_to<TreeItem>(p_parent), p_idx); } TreeItem *_get_next_selected(Object *p_item) { @@ -532,7 +532,7 @@ public: void clear(); - TreeItem *create_item(TreeItem *p_parent = 0); + TreeItem *create_item(TreeItem *p_parent = 0, int p_idx = -1); TreeItem *get_root(); TreeItem *get_last_item(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index de1ab9959a..942a6d5428 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -340,7 +340,8 @@ void Node::move_child(Node *p_child, int p_pos) { data.children[i]->notification(NOTIFICATION_MOVED_IN_PARENT); } for (const Map<StringName, GroupData>::Element *E = p_child->data.grouped.front(); E; E = E->next()) { - E->get().group->changed = true; + if (E->get().group) + E->get().group->changed = true; } data.blocked--; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 7c31b72bb5..db39b37bd5 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -391,13 +391,12 @@ void SceneTree::input_event(const Ref<InputEvent> &p_event) { if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_event))) return; //avoid joy input on editor + current_event++; root_lock++; - //last_id=p_event.ID; input_handled = false; Ref<InputEvent> ev = p_event; - ev->set_id(++last_id); //this should work better MainLoop::input_event(ev); @@ -941,11 +940,6 @@ void SceneMainLoop::_update_listener_2d() { } */ -uint32_t SceneTree::get_last_event_id() const { - - return last_id; -} - Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { r_error.error = Variant::CallError::CALL_OK; @@ -994,6 +988,10 @@ int64_t SceneTree::get_frame() const { return current_frame; } +int64_t SceneTree::get_event_count() const { + + return current_event; +} Array SceneTree::_get_nodes_in_group(const StringName &p_group) { @@ -2287,9 +2285,10 @@ SceneTree::SceneTree() { tree_version = 1; physics_process_time = 1; idle_process_time = 1; - last_id = 1; + root = NULL; current_frame = 0; + current_event = 0; tree_changed_name = "tree_changed"; node_added_name = "node_added"; node_removed_name = "node_removed"; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 9c5b0f69cb..3e2e74b553 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -109,7 +109,6 @@ private: float idle_process_time; bool accept_quit; bool quit_on_go_back; - uint32_t last_id; #ifdef DEBUG_ENABLED bool debug_collisions_hint; @@ -130,6 +129,7 @@ private: bool use_font_oversampling; int64_t current_frame; + int64_t current_event; int node_count; #ifdef TOOLS_ENABLED @@ -325,7 +325,7 @@ public: NOTIFICATION_TRANSFORM_CHANGED = 29 }; - enum CallGroupFlags { + enum GroupCallFlags { GROUP_CALL_DEFAULT = 0, GROUP_CALL_REVERSE = 1, GROUP_CALL_REALTIME = 2, @@ -335,8 +335,6 @@ public: _FORCE_INLINE_ Viewport *get_root() const { return root; } - uint32_t get_last_event_id() const; - void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification); void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value); @@ -412,6 +410,7 @@ public: int get_collision_debug_contact_count() { return collision_debug_contacts; } int64_t get_frame() const; + int64_t get_event_count() const; int get_node_count() const; @@ -467,6 +466,6 @@ public: VARIANT_ENUM_CAST(SceneTree::StretchMode); VARIANT_ENUM_CAST(SceneTree::StretchAspect); -VARIANT_ENUM_CAST(SceneTree::CallGroupFlags); +VARIANT_ENUM_CAST(SceneTree::GroupCallFlags); #endif diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 8f431389d8..fa6a7832f5 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -184,7 +184,6 @@ Viewport::GUI::GUI() { key_focus = NULL; mouse_over = NULL; - cancelled_input_ID = 0; tooltip = NULL; tooltip_popup = NULL; tooltip_label = NULL; @@ -1620,9 +1619,6 @@ bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_che void Viewport::_gui_input_event(Ref<InputEvent> p_event) { - if (p_event->get_id() == gui.cancelled_input_ID) { - return; - } //? /* if (!is_visible()) { @@ -1640,7 +1636,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (mb->is_pressed()) { Size2 pos = mpos; - if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button) { + if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button && mb->get_button_index() == BUTTON_LEFT) { //do not steal mouse focus and stuff @@ -1752,7 +1748,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { _gui_call_input(gui.mouse_focus, mb); } - get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "windows", "_cancel_input_ID", mb->get_id()); get_tree()->set_input_as_handled(); if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) { @@ -1825,7 +1820,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.drag_data=Variant(); //always clear }*/ - get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "windows", "_cancel_input_ID", mb->get_id()); get_tree()->set_input_as_handled(); } } @@ -2904,7 +2898,7 @@ Viewport::Viewport() { gui.canvas_sort_index = 0; msaa = MSAA_DISABLED; - hdr = false; + hdr = true; usage = USAGE_3D; debug_draw = DEBUG_DRAW_DISABLED; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 0835e3f69a..c084e348b5 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -269,7 +269,6 @@ private: float tooltip_timer; float tooltip_delay; List<Control *> modal_stack; - unsigned int cancelled_input_ID; Transform2D focus_inv_xform; bool subwindow_order_dirty; List<Control *> subwindows; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 39e6698725..0c8837ee1a 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -200,6 +200,9 @@ static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL; static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL; +static ResourceFormatSaverShader *resource_saver_shader = NULL; +static ResourceFormatLoaderShader *resource_loader_shader = NULL; + void register_scene_types() { SceneStringNames::create(); @@ -607,6 +610,12 @@ void register_scene_types() { resource_loader_text = memnew(ResourceFormatLoaderText); ResourceLoader::add_resource_format_loader(resource_loader_text, true); + resource_saver_shader = memnew(ResourceFormatSaverShader); + ResourceSaver::add_resource_format_saver(resource_saver_shader, true); + + resource_loader_shader = memnew(ResourceFormatLoaderShader); + ResourceLoader::add_resource_format_loader(resource_loader_shader, true); + for (int i = 0; i < 20; i++) { GLOBAL_DEF("layer_names/2d_render/layer_" + itos(i + 1), ""); GLOBAL_DEF("layer_names/2d_physics/layer_" + itos(i + 1), ""); @@ -632,6 +641,13 @@ void unregister_scene_types() { memdelete(resource_loader_text); } + if (resource_saver_shader) { + memdelete(resource_saver_shader); + } + if (resource_loader_shader) { + memdelete(resource_loader_shader); + } + SpatialMaterial::finish_shaders(); ParticlesMaterial::finish_shaders(); CanvasItemMaterial::finish_shaders(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 326320c60f..cc9fde58e2 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -753,7 +753,7 @@ void SpatialMaterial::_update_shader() { if (features[FEATURE_REFRACTION] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //refraction not supported with triplanar if (features[FEATURE_NORMAL_MAPPING]) { - code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) ) * SIDE;\n"; + code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) );\n"; } else { code += "\tvec3 ref_normal = NORMAL;\n"; } diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 66df7dfda8..207c50f673 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -151,3 +151,80 @@ Shader::~Shader() { VisualServer::get_singleton()->free(shader); } +//////////// + +RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error) { + + if (r_error) + *r_error = ERR_FILE_CANT_OPEN; + + Ref<Shader> shader; + shader.instance(); + + Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path); + + String str; + str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + + shader->set_code(str); + + if (r_error) + *r_error = OK; + + return shader; +} + +void ResourceFormatLoaderShader::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("shader"); +} + +bool ResourceFormatLoaderShader::handles_type(const String &p_type) const { + + return (p_type == "Shader"); +} + +String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const { + + String el = p_path.get_extension().to_lower(); + if (el == "shader") + return "Shader"; + return ""; +} + +Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + + Ref<Shader> shader = p_resource; + ERR_FAIL_COND_V(shader.is_null(), ERR_INVALID_PARAMETER); + + String source = shader->get_code(); + + Error err; + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + + if (err) { + + ERR_FAIL_COND_V(err, err); + } + + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; + } + file->close(); + memdelete(file); + + return OK; +} + +void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { + + if (Object::cast_to<Shader>(*p_resource)) { + p_extensions->push_back("shader"); + } +} +bool ResourceFormatSaverShader::recognize(const RES &p_resource) const { + + return Object::cast_to<Shader>(*p_resource) != NULL; +} diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 5cc70629c7..78d73a33e2 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -31,6 +31,7 @@ #define SHADER_H #include "io/resource_loader.h" +#include "io/resource_saver.h" #include "resource.h" #include "scene/resources/texture.h" @@ -38,7 +39,6 @@ class Shader : public Resource { GDCLASS(Shader, Resource); OBJ_SAVE_TYPE(Shader); - RES_BASE_EXTENSION("shd"); public: enum Mode { @@ -95,4 +95,19 @@ public: VARIANT_ENUM_CAST(Shader::Mode); +class ResourceFormatLoaderShader : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +class ResourceFormatSaverShader : public ResourceFormatSaver { +public: + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; + virtual bool recognize(const RES &p_resource) const; +}; + #endif // SHADER_H diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 987d6c5f6a..35d0d55d85 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -707,6 +707,8 @@ Ref<Image> StreamTexture::get_data() const { } void StreamTexture::set_flags(uint32_t p_flags) { + flags = p_flags; + VS::get_singleton()->texture_set_flags(texture, flags); } void StreamTexture::reload_from_file() { diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index bd6b917d4e..144c208c07 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -893,8 +893,8 @@ void TileSet::clear() { void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("create_tile", "id"), &TileSet::create_tile); - ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "mode"), &TileSet::autotile_set_bitmask_mode); - ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode"), &TileSet::autotile_get_bitmask_mode); + ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "id", "mode"), &TileSet::autotile_set_bitmask_mode); + ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode", "id"), &TileSet::autotile_get_bitmask_mode); ClassDB::bind_method(D_METHOD("tile_set_name", "id", "name"), &TileSet::tile_set_name); ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name); ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture"), &TileSet::tile_set_texture); diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index dc58cd36dd..dad4711c07 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -654,6 +654,10 @@ void Physics2DServer::_bind_methods() { BIND_ENUM_CONSTANT(JOINT_GROOVE); BIND_ENUM_CONSTANT(JOINT_DAMPED_SPRING); + BIND_ENUM_CONSTANT(JOINT_PARAM_BIAS); + BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_BIAS); + BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_FORCE); + BIND_ENUM_CONSTANT(DAMPED_STRING_REST_LENGTH); BIND_ENUM_CONSTANT(DAMPED_STRING_STIFFNESS); BIND_ENUM_CONSTANT(DAMPED_STRING_DAMPING); diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index a25c5ca65e..96f981ab5e 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -109,7 +109,6 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SIDE"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); |