diff options
224 files changed, 2457 insertions, 1085 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 9503bd2575..58b2bc0492 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -613,27 +613,6 @@ void OS::_bind_methods() { BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN); BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3); - BIND_ENUM_CONSTANT(DAY_SUNDAY); - BIND_ENUM_CONSTANT(DAY_MONDAY); - BIND_ENUM_CONSTANT(DAY_TUESDAY); - BIND_ENUM_CONSTANT(DAY_WEDNESDAY); - BIND_ENUM_CONSTANT(DAY_THURSDAY); - BIND_ENUM_CONSTANT(DAY_FRIDAY); - BIND_ENUM_CONSTANT(DAY_SATURDAY); - - BIND_ENUM_CONSTANT(MONTH_JANUARY); - BIND_ENUM_CONSTANT(MONTH_FEBRUARY); - BIND_ENUM_CONSTANT(MONTH_MARCH); - BIND_ENUM_CONSTANT(MONTH_APRIL); - BIND_ENUM_CONSTANT(MONTH_MAY); - BIND_ENUM_CONSTANT(MONTH_JUNE); - BIND_ENUM_CONSTANT(MONTH_JULY); - BIND_ENUM_CONSTANT(MONTH_AUGUST); - BIND_ENUM_CONSTANT(MONTH_SEPTEMBER); - BIND_ENUM_CONSTANT(MONTH_OCTOBER); - BIND_ENUM_CONSTANT(MONTH_NOVEMBER); - BIND_ENUM_CONSTANT(MONTH_DECEMBER); - BIND_ENUM_CONSTANT(SYSTEM_DIR_DESKTOP); BIND_ENUM_CONSTANT(SYSTEM_DIR_DCIM); BIND_ENUM_CONSTANT(SYSTEM_DIR_DOCUMENTS); diff --git a/core/core_bind.h b/core/core_bind.h index c863a8094c..e556b1878f 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -129,33 +129,6 @@ public: RENDERING_DRIVER_OPENGL3, }; - enum Weekday { - DAY_SUNDAY, - DAY_MONDAY, - DAY_TUESDAY, - DAY_WEDNESDAY, - DAY_THURSDAY, - DAY_FRIDAY, - DAY_SATURDAY - }; - - enum Month { - // Start at 1 to follow Windows SYSTEMTIME structure - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx - MONTH_JANUARY = 1, - MONTH_FEBRUARY, - MONTH_MARCH, - MONTH_APRIL, - MONTH_MAY, - MONTH_JUNE, - MONTH_JULY, - MONTH_AUGUST, - MONTH_SEPTEMBER, - MONTH_OCTOBER, - MONTH_NOVEMBER, - MONTH_DECEMBER - }; - virtual PackedStringArray get_connected_midi_inputs(); virtual void open_midi_inputs(); virtual void close_midi_inputs(); @@ -583,8 +556,6 @@ VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode); VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags); VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver); -VARIANT_ENUM_CAST(core_bind::OS::Weekday); -VARIANT_ENUM_CAST(core_bind::OS::Month); VARIANT_ENUM_CAST(core_bind::OS::SystemDir); VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation); diff --git a/core/input/input.cpp b/core/input/input.cpp index cb65d2569c..554f8fad00 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -540,6 +540,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em drag_event->set_position(position); drag_event->set_relative(relative); + drag_event->set_tilt(mm->get_tilt()); + drag_event->set_pen_inverted(mm->get_pen_inverted()); + drag_event->set_pressure(mm->get_pressure()); drag_event->set_velocity(get_last_mouse_velocity()); event_dispatch_function(drag_event); @@ -605,6 +608,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em motion_event.instantiate(); motion_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); + motion_event->set_tilt(sd->get_tilt()); + motion_event->set_pen_inverted(sd->get_pen_inverted()); + motion_event->set_pressure(sd->get_pressure()); motion_event->set_position(sd->get_position()); motion_event->set_global_position(sd->get_position()); motion_event->set_relative(sd->get_relative()); diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 0a32b4bf68..4859490230 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -1223,6 +1223,30 @@ int InputEventScreenDrag::get_index() const { return index; } +void InputEventScreenDrag::set_tilt(const Vector2 &p_tilt) { + tilt = p_tilt; +} + +Vector2 InputEventScreenDrag::get_tilt() const { + return tilt; +} + +void InputEventScreenDrag::set_pressure(float p_pressure) { + pressure = p_pressure; +} + +float InputEventScreenDrag::get_pressure() const { + return pressure; +} + +void InputEventScreenDrag::set_pen_inverted(bool p_inverted) { + pen_inverted = p_inverted; +} + +bool InputEventScreenDrag::get_pen_inverted() const { + return pen_inverted; +} + void InputEventScreenDrag::set_position(const Vector2 &p_pos) { pos = p_pos; } @@ -1256,6 +1280,9 @@ Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, con sd->set_window_id(get_window_id()); sd->set_index(index); + sd->set_pressure(get_pressure()); + sd->set_pen_inverted(get_pen_inverted()); + sd->set_tilt(get_tilt()); sd->set_position(p_xform.xform(pos + p_local_ofs)); sd->set_relative(p_xform.basis_xform(relative)); sd->set_velocity(p_xform.basis_xform(velocity)); @@ -1268,7 +1295,7 @@ String InputEventScreenDrag::as_text() const { } String InputEventScreenDrag::to_string() { - return vformat("InputEventScreenDrag: index=%d, position=(%s), relative=(%s), velocity=(%s)", index, String(get_position()), String(get_relative()), String(get_velocity())); + return vformat("InputEventScreenDrag: index=%d, position=(%s), relative=(%s), velocity=(%s), pressure=%.2f, tilt=(%s), pen_inverted=(%s)", index, String(get_position()), String(get_relative()), String(get_velocity()), get_pressure(), String(get_tilt()), get_pen_inverted()); } bool InputEventScreenDrag::accumulate(const Ref<InputEvent> &p_event) { @@ -1292,6 +1319,15 @@ void InputEventScreenDrag::_bind_methods() { ClassDB::bind_method(D_METHOD("set_index", "index"), &InputEventScreenDrag::set_index); ClassDB::bind_method(D_METHOD("get_index"), &InputEventScreenDrag::get_index); + ClassDB::bind_method(D_METHOD("set_tilt", "tilt"), &InputEventScreenDrag::set_tilt); + ClassDB::bind_method(D_METHOD("get_tilt"), &InputEventScreenDrag::get_tilt); + + ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventScreenDrag::set_pressure); + ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventScreenDrag::get_pressure); + + ClassDB::bind_method(D_METHOD("set_pen_inverted", "pen_inverted"), &InputEventScreenDrag::set_pen_inverted); + ClassDB::bind_method(D_METHOD("get_pen_inverted"), &InputEventScreenDrag::get_pen_inverted); + ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventScreenDrag::set_position); ClassDB::bind_method(D_METHOD("get_position"), &InputEventScreenDrag::get_position); @@ -1302,6 +1338,9 @@ void InputEventScreenDrag::_bind_methods() { ClassDB::bind_method(D_METHOD("get_velocity"), &InputEventScreenDrag::get_velocity); ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "tilt"), "set_tilt", "get_tilt"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure"), "set_pressure", "get_pressure"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pen_inverted"), "set_pen_inverted", "get_pen_inverted"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative", PROPERTY_HINT_NONE, "suffix:px"), "set_relative", "get_relative"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_velocity", "get_velocity"); diff --git a/core/input/input_event.h b/core/input/input_event.h index adbcb7cf68..06c3118abc 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -384,6 +384,9 @@ class InputEventScreenDrag : public InputEventFromWindow { Vector2 pos; Vector2 relative; Vector2 velocity; + Vector2 tilt; + float pressure = 0; + bool pen_inverted = false; protected: static void _bind_methods(); @@ -392,6 +395,15 @@ public: void set_index(int p_index); int get_index() const; + void set_tilt(const Vector2 &p_tilt); + Vector2 get_tilt() const; + + void set_pressure(float p_pressure); + float get_pressure() const; + + void set_pen_inverted(bool p_inverted); + bool get_pen_inverted() const; + void set_position(const Vector2 &p_pos); Vector2 get_position() const; diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 9ba653e1a9..9f89f5d8c9 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -1813,3 +1813,24 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo return OK; } + +Vector<float> vector3_to_float32_array(const Vector3 *vecs, size_t count) { + // We always allocate a new array, and we don't memcpy. + // We also don't consider returning a pointer to the passed vectors when sizeof(real_t) == 4. + // One reason is that we could decide to put a 4th component in Vector3 for SIMD/mobile performance, + // which would cause trouble with these optimizations. + Vector<float> floats; + if (count == 0) { + return floats; + } + floats.resize(count * 3); + float *floats_w = floats.ptrw(); + for (size_t i = 0; i < count; ++i) { + const Vector3 v = vecs[i]; + floats_w[0] = v.x; + floats_w[1] = v.y; + floats_w[2] = v.z; + floats_w += 3; + } + return floats; +} diff --git a/core/io/marshalls.h b/core/io/marshalls.h index fef3a1c2c1..66e2571066 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -215,4 +215,6 @@ public: Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = nullptr, bool p_allow_objects = false, int p_depth = 0); Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false, int p_depth = 0); +Vector<float> vector3_to_float32_array(const Vector3 *vecs, size_t count); + #endif // MARSHALLS_H diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 8dff8e6e7e..a998dece2a 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -453,7 +453,10 @@ public: } static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { double range = max - min; - double result = is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + if (is_zero_approx(range)) { + return min; + } + double result = value - (range * Math::floor((value - min) / range)); if (is_equal_approx(result, max)) { return min; } @@ -461,7 +464,10 @@ public: } static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) { float range = max - min; - float result = is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + if (is_zero_approx(range)) { + return min; + } + float result = value - (range * Math::floor((value - min) / range)); if (is_equal_approx(result, max)) { return min; } diff --git a/core/os/os.h b/core/os/os.h index 07e9020a51..a5885b1aaa 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -34,6 +34,7 @@ #include "core/config/engine.h" #include "core/io/image.h" #include "core/io/logger.h" +#include "core/os/time_enums.h" #include "core/string/ustring.h" #include "core/templates/list.h" #include "core/templates/vector.h" @@ -185,33 +186,6 @@ public: virtual void yield(); - enum Weekday : uint8_t { - WEEKDAY_SUNDAY, - WEEKDAY_MONDAY, - WEEKDAY_TUESDAY, - WEEKDAY_WEDNESDAY, - WEEKDAY_THURSDAY, - WEEKDAY_FRIDAY, - WEEKDAY_SATURDAY, - }; - - enum Month : uint8_t { - /// Start at 1 to follow Windows SYSTEMTIME structure - /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx - MONTH_JANUARY = 1, - MONTH_FEBRUARY, - MONTH_MARCH, - MONTH_APRIL, - MONTH_MAY, - MONTH_JUNE, - MONTH_JULY, - MONTH_AUGUST, - MONTH_SEPTEMBER, - MONTH_OCTOBER, - MONTH_NOVEMBER, - MONTH_DECEMBER, - }; - struct DateTime { int64_t year; Month month; diff --git a/core/os/time.cpp b/core/os/time.cpp index a3c2c99b4c..3fc831d124 100644 --- a/core/os/time.cpp +++ b/core/os/time.cpp @@ -52,8 +52,8 @@ static const uint8_t MONTH_DAYS_TABLE[2][12] = { { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; -VARIANT_ENUM_CAST(Time::Month); -VARIANT_ENUM_CAST(Time::Weekday); +VARIANT_ENUM_CAST(Month); +VARIANT_ENUM_CAST(Weekday); #define UNIX_TIME_TO_HMS \ uint8_t hour, minute, second; \ diff --git a/core/os/time.h b/core/os/time.h index 4b4ce3526a..379a224f34 100644 --- a/core/os/time.h +++ b/core/os/time.h @@ -32,6 +32,7 @@ #define TIME_H #include "core/object/class_db.h" +#include "time_enums.h" // This Time class conforms with as many of the ISO 8601 standards as possible. // * As per ISO 8601:2004 4.3.2.1, all dates follow the Proleptic Gregorian @@ -51,33 +52,6 @@ class Time : public Object { public: static Time *get_singleton(); - enum Month { - /// Start at 1 to follow Windows SYSTEMTIME structure - /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx - MONTH_JANUARY = 1, - MONTH_FEBRUARY, - MONTH_MARCH, - MONTH_APRIL, - MONTH_MAY, - MONTH_JUNE, - MONTH_JULY, - MONTH_AUGUST, - MONTH_SEPTEMBER, - MONTH_OCTOBER, - MONTH_NOVEMBER, - MONTH_DECEMBER, - }; - - enum Weekday : uint8_t { - WEEKDAY_SUNDAY, - WEEKDAY_MONDAY, - WEEKDAY_TUESDAY, - WEEKDAY_WEDNESDAY, - WEEKDAY_THURSDAY, - WEEKDAY_FRIDAY, - WEEKDAY_SATURDAY, - }; - // Methods that convert times. Dictionary get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const; Dictionary get_date_dict_from_unix_time(int64_t p_unix_time_val) const; diff --git a/core/os/time_enums.h b/core/os/time_enums.h new file mode 100644 index 0000000000..aa2d97a308 --- /dev/null +++ b/core/os/time_enums.h @@ -0,0 +1,63 @@ +/*************************************************************************/ +/* time_enums.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TIME_ENUMS_H +#define TIME_ENUMS_H + +#include <cstdint> + +enum Month { + /// Start at 1 to follow Windows SYSTEMTIME structure + /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx + MONTH_JANUARY = 1, + MONTH_FEBRUARY, + MONTH_MARCH, + MONTH_APRIL, + MONTH_MAY, + MONTH_JUNE, + MONTH_JULY, + MONTH_AUGUST, + MONTH_SEPTEMBER, + MONTH_OCTOBER, + MONTH_NOVEMBER, + MONTH_DECEMBER, +}; + +enum Weekday : uint8_t { + WEEKDAY_SUNDAY, + WEEKDAY_MONDAY, + WEEKDAY_TUESDAY, + WEEKDAY_WEDNESDAY, + WEEKDAY_THURSDAY, + WEEKDAY_FRIDAY, + WEEKDAY_SATURDAY, +}; + +#endif // TIME_ENUMS_H diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index ac569941bf..57d62dac91 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -65,11 +65,13 @@ static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...) const, Variant *b template <class T, class... P> static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + VariantInternal::clear(&r_ret); call_with_variant_args_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals); } template <class T, class... P> static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { + VariantInternal::clear(&r_ret); call_with_variant_argsc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals); } diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 8a5048de6b..60225275f3 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -529,13 +529,13 @@ The material will use the texture's alpha values for transparency. </constant> <constant name="TRANSPARENCY_ALPHA_SCISSOR" value="2" enum="Transparency"> - The material will cut off all values below a threshold, the rest will remain opaque. The opaque portions will be rendering in the depth prepass. + The material will cut off all values below a threshold, the rest will remain opaque. The opaque portions will be rendered in the depth prepass. </constant> <constant name="TRANSPARENCY_ALPHA_HASH" value="3" enum="Transparency"> The material will cut off all values below a spatially-deterministic threshold, the rest will remain opaque. </constant> <constant name="TRANSPARENCY_ALPHA_DEPTH_PRE_PASS" value="4" enum="Transparency"> - The material will use the texture's alpha value for transparency, but will still be rendered in the depth prepass. + The material will use the texture's alpha value for transparency, but will discard fragments with an alpha of less than 0.99 during the depth prepass and fragments with an alpha less than 0.1 during the shadow pass. </constant> <constant name="TRANSPARENCY_MAX" value="5" enum="Transparency"> Represents the size of the [enum Transparency] enum. diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml index 309e2231a4..821117122c 100644 --- a/doc/classes/CharacterBody3D.xml +++ b/doc/classes/CharacterBody3D.xml @@ -41,10 +41,16 @@ Returns a [KinematicCollision3D], which contains information about the latest collision that occurred during the last call to [method move_and_slide]. </description> </method> + <method name="get_platform_angular_velocity" qualifiers="const"> + <return type="Vector3" /> + <description> + Returns the angular velocity of the platform at the last collision point. Only valid after calling [method move_and_slide]. + </description> + </method> <method name="get_platform_velocity" qualifiers="const"> <return type="Vector3" /> <description> - Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code]. + Returns the linear velocity of the platform at the last collision point. Only valid after calling [method move_and_slide]. </description> </method> <method name="get_position_delta" qualifiers="const"> diff --git a/doc/classes/InputEventScreenDrag.xml b/doc/classes/InputEventScreenDrag.xml index e5cc522b21..c1d126ca4a 100644 --- a/doc/classes/InputEventScreenDrag.xml +++ b/doc/classes/InputEventScreenDrag.xml @@ -13,12 +13,21 @@ <member name="index" type="int" setter="set_index" getter="get_index" default="0"> The drag event index in the case of a multi-drag event. </member> + <member name="pen_inverted" type="bool" setter="set_pen_inverted" getter="get_pen_inverted" default="false"> + Returns [code]true[/code] when using the eraser end of a stylus pen. + </member> <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> The drag position. </member> + <member name="pressure" type="float" setter="set_pressure" getter="get_pressure" default="0.0"> + Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code]. + </member> <member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2(0, 0)"> The drag position relative to the previous position (position at the last frame). </member> + <member name="tilt" type="Vector2" setter="set_tilt" getter="get_tilt" default="Vector2(0, 0)"> + Represents the angles of tilt of the pen. Positive X-coordinate value indicates a tilt to the right. Positive Y-coordinate value indicates a tilt toward the user. Ranges from [code]-1.0[/code] to [code]1.0[/code] for both axes. + </member> <member name="velocity" type="Vector2" setter="set_velocity" getter="get_velocity" default="Vector2(0, 0)"> The drag velocity. </member> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 0efc6ab399..ff4982e2fb 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -654,63 +654,6 @@ <constant name="RENDERING_DRIVER_OPENGL3" value="1" enum="RenderingDriver"> The OpenGL 3 rendering driver. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on Web. </constant> - <constant name="DAY_SUNDAY" value="0" enum="Weekday"> - Sunday. - </constant> - <constant name="DAY_MONDAY" value="1" enum="Weekday"> - Monday. - </constant> - <constant name="DAY_TUESDAY" value="2" enum="Weekday"> - Tuesday. - </constant> - <constant name="DAY_WEDNESDAY" value="3" enum="Weekday"> - Wednesday. - </constant> - <constant name="DAY_THURSDAY" value="4" enum="Weekday"> - Thursday. - </constant> - <constant name="DAY_FRIDAY" value="5" enum="Weekday"> - Friday. - </constant> - <constant name="DAY_SATURDAY" value="6" enum="Weekday"> - Saturday. - </constant> - <constant name="MONTH_JANUARY" value="1" enum="Month"> - January. - </constant> - <constant name="MONTH_FEBRUARY" value="2" enum="Month"> - February. - </constant> - <constant name="MONTH_MARCH" value="3" enum="Month"> - March. - </constant> - <constant name="MONTH_APRIL" value="4" enum="Month"> - April. - </constant> - <constant name="MONTH_MAY" value="5" enum="Month"> - May. - </constant> - <constant name="MONTH_JUNE" value="6" enum="Month"> - June. - </constant> - <constant name="MONTH_JULY" value="7" enum="Month"> - July. - </constant> - <constant name="MONTH_AUGUST" value="8" enum="Month"> - August. - </constant> - <constant name="MONTH_SEPTEMBER" value="9" enum="Month"> - September. - </constant> - <constant name="MONTH_OCTOBER" value="10" enum="Month"> - October. - </constant> - <constant name="MONTH_NOVEMBER" value="11" enum="Month"> - November. - </constant> - <constant name="MONTH_DECEMBER" value="12" enum="Month"> - December. - </constant> <constant name="SYSTEM_DIR_DESKTOP" value="0" enum="SystemDir"> Desktop directory path. </constant> diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index 2d25965180..f1316fa991 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -805,6 +805,23 @@ Sets a joint parameter. See [enum JointParam] for a list of available parameters. </description> </method> + <method name="pin_joint_get_param" qualifiers="const"> + <return type="float" /> + <param index="0" name="joint" type="RID" /> + <param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" /> + <description> + Returns the value of a pin joint parameter. See [enum PinJointParam] for a list of available parameters. + </description> + </method> + <method name="pin_joint_set_param"> + <return type="void" /> + <param index="0" name="joint" type="RID" /> + <param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" /> + <param index="2" name="value" type="float" /> + <description> + Sets a pin joint parameter. See [enum PinJointParam] for a list of available parameters. + </description> + </method> <method name="rectangle_shape_create"> <return type="RID" /> <description> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 67b692a7a0..d4c42e36eb 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -464,9 +464,6 @@ <member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1"> When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable is unused. </member> - <member name="debug/gdscript/warnings/void_assignment" type="int" setter="" getter="" default="1"> - When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when assigning the result of a function that returns [code]void[/code] to a variable. - </member> <member name="debug/settings/crash_handler/message" type="String" setter="" getter="" default=""Please include this when reporting the bug to the project developer.""> Message to be displayed before the backtrace when the engine crashes. By default, this message is only used in exported projects due to the editor-only override applied to this setting. </member> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 1faecfd4d0..f0c60f6ed9 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -191,7 +191,7 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) { //material is only meant for alpha pass flags |= GeometryInstanceSurface::FLAG_PASS_ALPHA; - if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED)) { + if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED)) { flags |= GeometryInstanceSurface::FLAG_PASS_DEPTH; flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW; } @@ -203,7 +203,7 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry GLES3::SceneMaterialData *material_shadow = nullptr; void *surface_shadow = nullptr; - if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip) { + if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip) { flags |= GeometryInstanceSurface::FLAG_USES_SHARED_SHADOW_MATERIAL; material_shadow = static_cast<GLES3::SceneMaterialData *>(GLES3::MaterialStorage::get_singleton()->material_get_data(scene_globals.default_material, RS::SHADER_SPATIAL)); diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index ebafdc88d8..53ab3d2367 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -3237,7 +3237,7 @@ void SceneShaderData::set_code(const String &p_code) { uses_alpha = false; uses_alpha_clip = false; uses_blend_alpha = false; - uses_depth_pre_pass = false; + uses_depth_prepass_alpha = false; uses_discard = false; uses_roughness = false; uses_normal = false; @@ -3288,7 +3288,7 @@ void SceneShaderData::set_code(const String &p_code) { // Use alpha clip pipeline for alpha hash/dither. // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows. actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip; - actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; + actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_prepass_alpha; actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; @@ -3398,7 +3398,7 @@ bool SceneShaderData::casts_shadows() const { bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha; bool has_alpha = has_base_alpha || uses_blend_alpha; - return !has_alpha || (uses_depth_pre_pass && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED)); + return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED)); } RS::ShaderNativeSourceCode SceneShaderData::get_native_source_code() const { diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 9965d23070..32463d291b 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -286,7 +286,7 @@ struct SceneShaderData : public ShaderData { bool uses_alpha; bool uses_blend_alpha; bool uses_alpha_clip; - bool uses_depth_pre_pass; + bool uses_depth_prepass_alpha; bool uses_discard; bool uses_roughness; bool uses_normal; diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index 8b31781c5e..05f7dc9725 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -118,6 +118,7 @@ void EditorDebuggerTree::_scene_tree_rmb_selected(const Vector2 &p_position, Mou item_menu->add_icon_item(get_theme_icon(SNAME("CreateNewSceneFrom"), SNAME("EditorIcons")), TTR("Save Branch as Scene"), ITEM_MENU_SAVE_REMOTE_NODE); item_menu->add_icon_item(get_theme_icon(SNAME("CopyNodePath"), SNAME("EditorIcons")), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH); item_menu->set_position(get_screen_position() + get_local_mouse_position()); + item_menu->reset_size(); item_menu->popup(); } @@ -157,7 +158,11 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int const SceneDebuggerTree::RemoteNode &node = p_tree->nodes[i]; TreeItem *item = create_item(parent); item->set_text(0, node.name); - item->set_tooltip_text(0, TTR("Type:") + " " + node.type_name); + if (node.scene_file_path.is_empty()) { + item->set_tooltip_text(0, node.name + "\n" + TTR("Type:") + " " + node.type_name); + } else { + item->set_tooltip_text(0, node.name + "\n" + TTR("Instance:") + " " + node.scene_file_path + "\n" + TTR("Type:") + " " + node.type_name); + } Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(node.type_name, ""); if (icon.is_valid()) { item->set_icon(0, icon); @@ -323,6 +328,8 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) { file_dialog->add_filter("*." + extensions[i], extensions[i].to_upper()); } + String filename = get_selected_path().get_file() + "." + extensions.front()->get().to_lower(); + file_dialog->set_current_path(filename); file_dialog->popup_file_dialog(); } break; case ITEM_MENU_COPY_NODE_PATH: { diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 55c512f77d..a9c46d4d94 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -1500,7 +1500,7 @@ void EditorFileDialog::_go_back() { } void EditorFileDialog::_go_forward() { - if (local_history_pos == local_history.size() - 1) { + if (local_history_pos >= local_history.size() - 1) { return; } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 88a1bbb4a9..9037851127 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2586,7 +2586,7 @@ bool EditorInspector::_is_property_disabled_by_feature_profile(const StringName return false; } -void EditorInspector::_update_tree() { +void EditorInspector::update_tree() { //to update properly if all is refreshed StringName current_selected = property_selected; int current_focusable = -1; @@ -3305,10 +3305,6 @@ void EditorInspector::_update_tree() { } } -void EditorInspector::update_tree() { - update_tree_pending = true; -} - void EditorInspector::update_property(const String &p_prop) { if (!editor_property_map.has(p_prop)) { return; @@ -3903,9 +3899,10 @@ void EditorInspector::_notification(int p_what) { changing++; if (update_tree_pending) { + update_tree(); update_tree_pending = false; pending.clear(); - _update_tree(); + } else { while (pending.size()) { StringName prop = *pending.begin(); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 53490f0880..df8493308a 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -542,8 +542,6 @@ class EditorInspector : public ScrollContainer { void _show_add_meta_dialog(); void _check_meta_name(const String &p_name); - void _update_tree(); - protected: static void _bind_methods(); void _notification(int p_what); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index aab64587ce..30322a94f1 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -135,7 +135,7 @@ public: label->set_h_size_flags(Control::SIZE_EXPAND_FILL); grid_step_x = memnew(SpinBox); - grid_step_x->set_min(0.01); + grid_step_x->set_min(1); grid_step_x->set_max(SPIN_BOX_GRID_RANGE); grid_step_x->set_allow_greater(true); grid_step_x->set_suffix("px"); @@ -144,7 +144,7 @@ public: child_container->add_child(grid_step_x); grid_step_y = memnew(SpinBox); - grid_step_y->set_min(0.01); + grid_step_y->set_min(1); grid_step_y->set_max(SPIN_BOX_GRID_RANGE); grid_step_y->set_allow_greater(true); grid_step_y->set_suffix("px"); @@ -4977,7 +4977,7 @@ CanvasItemEditor::CanvasItemEditor() { SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created)); SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position)); - EditorNode::get_singleton()->call_deferred(SNAME("connect"), callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true)); + EditorNode::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true)); EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false)); // A fluid container for all toolbars. diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 5f9446c3b1..cbe30f7e0f 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -436,6 +436,7 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { } EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(sphere); RS::get_singleton()->free(sphere_instance); RS::get_singleton()->free(viewport); @@ -767,6 +768,7 @@ EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() { } EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); //RS::get_singleton()->free(sphere); RS::get_singleton()->free(mesh_instance); RS::get_singleton()->free(viewport); @@ -867,6 +869,7 @@ EditorFontPreviewPlugin::EditorFontPreviewPlugin() { } EditorFontPreviewPlugin::~EditorFontPreviewPlugin() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(canvas_item); RS::get_singleton()->free(canvas); RS::get_singleton()->free(viewport); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 91c7fbc06a..0df53bddd1 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -100,6 +100,7 @@ bool EditorNode3DGizmo::is_editable() const { } void EditorNode3DGizmo::clear() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); for (int i = 0; i < instances.size(); i++) { if (instances[i].instance.is_valid()) { RS::get_singleton()->free(instances[i].instance); @@ -809,6 +810,7 @@ void EditorNode3DGizmo::transform() { } void EditorNode3DGizmo::free() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); ERR_FAIL_COND(!spatial_node); ERR_FAIL_COND(!valid); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 4976c8c750..8e2b9b4bce 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -3557,6 +3557,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) { } void Node3DEditorViewport::_finish_gizmo_instances() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); for (int i = 0; i < 3; i++) { RS::get_singleton()->free(move_gizmo_instance[i]); RS::get_singleton()->free(move_plane_gizmo_instance[i]); @@ -5536,6 +5537,7 @@ Node3DEditorViewportContainer::Node3DEditorViewportContainer() { Node3DEditor *Node3DEditor::singleton = nullptr; Node3DEditorSelectedItem::~Node3DEditorSelectedItem() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (sbox_instance.is_valid()) { RenderingServer::get_singleton()->free(sbox_instance); } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index bb5491fcb5..562eddbc64 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3003,6 +3003,7 @@ void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) { _go_to_tab(script_list->get_item_metadata(next_tab)); _update_script_names(); } + accept_event(); } if (ED_IS_SHORTCUT("script_editor/prev_script", p_event)) { if (script_list->get_item_count() > 1) { @@ -3011,12 +3012,15 @@ void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) { _go_to_tab(script_list->get_item_metadata(next_tab)); _update_script_names(); } + accept_event(); } if (ED_IS_SHORTCUT("script_editor/window_move_up", p_event)) { _menu_option(WINDOW_MOVE_UP); + accept_event(); } if (ED_IS_SHORTCUT("script_editor/window_move_down", p_event)) { _menu_option(WINDOW_MOVE_DOWN); + accept_event(); } } diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 5a1f214933..7c3c3e571e 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -1488,13 +1488,15 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() { } // Selection if needed. - for (RBSet<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) { + for (RBSet<TileMapCell>::Element *E = tile_set_selection.front(); E;) { + RBSet<TileMapCell>::Element *N = E->next(); const TileMapCell *selected = &(E->get()); if (!tile_set->has_source(selected->source_id) || !tile_set->get_source(selected->source_id)->has_tile(selected->get_atlas_coords()) || !tile_set->get_source(selected->source_id)->has_alternative_tile(selected->get_atlas_coords(), selected->alternative_tile)) { tile_set_selection.erase(E); } + E = N; } if (!tile_map_selection.is_empty()) { @@ -2266,7 +2268,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { patterns_item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); patterns_item_list->connect("gui_input", callable_mp(this, &TileMapEditorTilesPlugin::_patterns_item_list_gui_input)); patterns_item_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection).unbind(1)); - patterns_item_list->connect("item_activated", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection)); + patterns_item_list->connect("item_activated", callable_mp(this, &TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection).unbind(1)); patterns_item_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::patterns_item_list_empty_clicked)); patterns_bottom_panel->add_child(patterns_item_list); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index c93b0019dc..3d0c1acff8 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -5383,6 +5383,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Binormal", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Color", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Custom0", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom0", "CUSTOM0"), { "custom0" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Custom1", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom1", "CUSTOM1"), { "custom1" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Custom2", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom2", "CUSTOM2"), { "custom2" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Custom3", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom3", "CUSTOM3"), { "custom3" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("InstanceId", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id", "INSTANCE_ID"), { "instance_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("InstanceCustom", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom", "INSTANCE_CUSTOM"), { "instance_custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ModelViewMatrix", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview_matrix", "MODELVIEW_MATRIX"), { "modelview_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 40683e2938..5243916bd2 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -338,7 +338,7 @@ void RenameDialog::_bind_methods() { } void RenameDialog::_update_substitute() { - LineEdit *focus_owner_line_edit = Object::cast_to<LineEdit>(scene_tree_editor->get_viewport()->gui_get_focus_owner()); + LineEdit *focus_owner_line_edit = Object::cast_to<LineEdit>(get_viewport()->gui_get_focus_owner()); bool is_main_field = _is_main_field(focus_owner_line_edit); but_insert_name->set_disabled(!is_main_field); @@ -636,7 +636,7 @@ bool RenameDialog::_is_main_field(LineEdit *line_edit) { } void RenameDialog::_insert_text(String text) { - LineEdit *focus_owner = Object::cast_to<LineEdit>(scene_tree_editor->get_viewport()->gui_get_focus_owner()); + LineEdit *focus_owner = Object::cast_to<LineEdit>(get_viewport()->gui_get_focus_owner()); if (_is_main_field(focus_owner)) { focus_owner->selection_delete(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index f91b571118..4b04fd1589 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -134,6 +134,8 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) { _tool_selected(TOOL_MOVE_DOWN); } else if (ED_IS_SHORTCUT("scene_tree/reparent", p_event)) { _tool_selected(TOOL_REPARENT); + } else if (ED_IS_SHORTCUT("scene_tree/reparent_to_new_node", p_event)) { + _tool_selected(TOOL_REPARENT_TO_NEW_NODE); } else if (ED_IS_SHORTCUT("scene_tree/save_branch_as_scene", p_event)) { _tool_selected(TOOL_NEW_SCENE_FROM); } else if (ED_IS_SHORTCUT("scene_tree/delete_no_confirm", p_event)) { @@ -3217,6 +3219,7 @@ List<Node *> SceneTreeDock::paste_nodes() { if (!paste_parent) { paste_parent = dup; owner = dup; + dup->set_scene_file_path(String()); // Make sure the scene path is empty, to avoid accidental references. ur->add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup); } else { ur->add_do_method(paste_parent, "add_child", dup, true); diff --git a/misc/scripts/install_vulkan_sdk_macos.sh b/misc/scripts/install_vulkan_sdk_macos.sh index d78659fa9f..17d567f208 100755 --- a/misc/scripts/install_vulkan_sdk_macos.sh +++ b/misc/scripts/install_vulkan_sdk_macos.sh @@ -8,7 +8,15 @@ curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.dmg" -o /tmp/ hdiutil attach /tmp/vulkan-sdk.dmg -mountpoint /Volumes/vulkan-sdk /Volumes/vulkan-sdk/InstallVulkan.app/Contents/MacOS/InstallVulkan \ --accept-licenses --default-answer --confirm-command install -hdiutil detach /Volumes/vulkan-sdk + +cnt=5 +until hdiutil detach -force /Volumes/vulkan-sdk +do + [[ cnt -eq "0" ]] && break + sleep 1 + ((cnt--)) +done + rm -f /tmp/vulkan-sdk.dmg echo 'Vulkan SDK installed successfully! You can now build Godot by running "scons".' diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 0ebdbf090d..9457583d09 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -115,10 +115,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } if (from != line_length) { - /* check if we are in entering a region */ + // Check if we are in entering a region. if (in_region == -1) { for (int c = 0; c < color_regions.size(); c++) { - /* check there is enough room */ + // Check there is enough room. int chars_left = line_length - from; int start_key_length = color_regions[c].start_key.length(); int end_key_length = color_regions[c].end_key.length(); @@ -126,7 +126,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l continue; } - /* search the line */ + // Search the line. bool match = true; const char32_t *start_key = color_regions[c].start_key.get_data(); for (int k = 0; k < start_key_length; k++) { @@ -141,7 +141,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_region = c; from += start_key_length; - /* check if it's the whole line */ + // Check if it's the whole line. if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) { if (from + end_key_length > line_length) { // If it's key length and there is a '\', dont skip to highlight esc chars. @@ -166,7 +166,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - /* if we are in one find the end key */ + // If we are in one, find the end key. if (in_region != -1) { Color region_color = color_regions[in_region].color; if (in_node_path && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) { @@ -183,7 +183,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l highlighter_info["color"] = region_color; color_map[j] = highlighter_info; - /* search the line */ + // Search the line. int region_end_index = -1; int end_key_length = color_regions[in_region].end_key.length(); const char32_t *end_key = color_regions[in_region].end_key.get_data(); @@ -267,14 +267,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_keyword = false; } - // allow ABCDEF in hex notation + // Allow ABCDEF in hex notation. if (is_hex_notation && (is_hex_digit(str[j]) || is_a_digit)) { is_a_digit = true; } else { is_hex_notation = false; } - // disallow anything not a 0 or 1 in binary notation + // Disallow anything not a 0 or 1 in binary notation. if (is_bin_notation && !is_binary_digit(str[j])) { is_a_digit = false; is_bin_notation = false; @@ -284,7 +284,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_number = true; } - // Special cases for numbers + // Special cases for numbers. if (in_number && !is_a_digit) { if (str[j] == 'b' && str[j - 1] == '0') { is_bin_notation = true; @@ -349,7 +349,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l if (col != Color()) { for (int k = j - 1; k >= 0; k--) { if (str[k] == '.') { - col = Color(); // keyword, member & global func indexing not allowed + col = Color(); // Keyword, member & global func indexing not allowed. break; } else if (str[k] > 32) { break; @@ -372,7 +372,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l k++; } - // check for space between name and bracket + // Check for space between name and bracket. while (k < line_length && is_whitespace(str[k])) { k++; } @@ -445,7 +445,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_member_variable = false; } - // Keep symbol color for binary '&&'. In the case of '&&&' use StringName color for the last ampersand + // Keep symbol color for binary '&&'. In the case of '&&&' use StringName color for the last ampersand. if (!in_string_name && in_region == -1 && str[j] == '&' && !is_binary_op) { if (j >= 2 && str[j - 1] == '&' && str[j - 2] != '&' && prev_is_binary_op) { is_binary_op = true; @@ -456,7 +456,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_string_name = false; } - // '^^' has no special meaning, so unlike StringName, when binary, use NodePath color for the last caret + // '^^' has no special meaning, so unlike StringName, when binary, use NodePath color for the last caret. if (!in_node_path && in_region == -1 && str[j] == '^' && !is_binary_op && (j == 0 || (j > 0 && str[j - 1] != '^') || prev_is_binary_op)) { in_node_path = true; } else if (in_region != -1 || is_a_symbol) { @@ -465,7 +465,8 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l if (!in_node_ref && in_region == -1 && (str[j] == '$' || (str[j] == '%' && !is_binary_op))) { in_node_ref = true; - } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) { + } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%') || (is_a_digit && j > 0 && (str[j - 1] == '$' || str[j - 1] == '/' || str[j - 1] == '%'))) { + // NodeRefs can't start with digits, so point out wrong syntax immediately. in_node_ref = false; } @@ -525,7 +526,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l prev_type = current_type; current_type = next_type; - // no need to store regions... + // No need to store regions... if (prev_type == REGION) { prev_text = ""; prev_column = j; @@ -533,7 +534,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l String text = str.substr(prev_column, j - prev_column).strip_edges(); prev_column = j; - // ignore if just whitespace + // Ignore if just whitespace. if (!text.is_empty()) { prev_text = text; } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 1fe1561559..40bc2beb23 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -629,6 +629,10 @@ void GDScript::_update_doc() { } } + for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) { + E.value->_update_doc(); + } + _add_doc(doc); } #endif diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 1556957074..ad20672e2d 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1751,12 +1751,6 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable type = p_variable->initializer->get_datatype(); -#ifdef DEBUG_ENABLED - if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { - parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name); - } -#endif - if (p_variable->infer_datatype) { type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; @@ -1846,12 +1840,6 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant } type = p_constant->initializer->get_datatype(); - -#ifdef DEBUG_ENABLED - if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { - parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name); - } -#endif } if (p_constant->datatype_specifier != nullptr) { @@ -2047,6 +2035,9 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) { update_array_literal_element_type(expected_type, static_cast<GDScriptParser::ArrayNode *>(p_return->return_value)); } } + if (has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL) { + push_error("A void function cannot return a value.", p_return); + } result = p_return->return_value->get_datatype(); } else { // Return type is null by default. @@ -2332,9 +2323,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig } #ifdef DEBUG_ENABLED - if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.is_hard_type() && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) { - parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name); - } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) { + if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION); } #endif @@ -2649,6 +2638,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } else if (GDScriptUtilityFunctions::function_exists(function_name)) { MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name); + if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) { + push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call); + } + if (all_is_constant && GDScriptUtilityFunctions::is_function_constant(function_name)) { // Can call on compilation. Vector<const Variant *> args; @@ -2692,6 +2685,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } else if (Variant::has_utility_function(function_name)) { MethodInfo function_info = info_from_utility_func(function_name); + if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) { + push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call); + } + if (all_is_constant && Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH) { // Can call on compilation. Vector<const Variant *> args; @@ -2834,6 +2831,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a mark_lambda_use_self(); } + if (!p_is_root && return_type.is_hard_type() && return_type.kind == GDScriptParser::DataType::BUILTIN && return_type.builtin_type == Variant::NIL) { + push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", p_call->function_name), p_call); + } + #ifdef DEBUG_ENABLED if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL) { parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name); @@ -3997,10 +3998,8 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va scr = obj->get_script(); } if (scr.is_valid()) { - result.script_path = scr->get_path(); Ref<GDScript> gds = scr; if (gds.is_valid()) { - result.kind = GDScriptParser::DataType::CLASS; // This might be an inner class, so we want to get the parser for the root. // But still get the inner class from that tree. String script_path = gds->get_script_path(); @@ -4026,11 +4025,14 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va return error_type; } + result.kind = GDScriptParser::DataType::CLASS; + result.native_type = found->get_datatype().native_type; result.class_type = found; result.script_path = ref->get_parser()->script_path; } else { result.kind = GDScriptParser::DataType::SCRIPT; result.native_type = scr->get_instance_base_type(); + result.script_path = scr->get_path(); } result.script_type = scr; } else { diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 6faf2dde73..ca0f77bc0a 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -298,13 +298,7 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro singleton->full_gdscript_cache[p_path] = script; singleton->shallow_gdscript_cache.erase(p_path); - r_error = script->reload(true); - if (r_error) { - singleton->shallow_gdscript_cache[p_path] = script; - singleton->full_gdscript_cache.erase(p_path); - return script; - } - + script->reload(true); return script; } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 6c7b5d534e..3c9387a837 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -538,20 +538,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Construct a built-in type. Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name); - gen->write_construct(result, vtype, arguments); + gen->write_construct(return_addr, vtype, arguments); } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) { // Variant utility function. - gen->write_call_utility(result, call->function_name, arguments); + gen->write_call_utility(return_addr, call->function_name, arguments); } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) { // GDScript utility function. - gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments); + gen->write_call_gdscript_utility(return_addr, GDScriptUtilityFunctions::get_function(call->function_name), arguments); } else { // Regular function. const GDScriptParser::ExpressionNode *callee = call->callee; if (call->is_super) { // Super call. - gen->write_super_call(result, call->function_name, arguments); + gen->write_super_call(return_addr, call->function_name, arguments); } else { if (callee->type == GDScriptParser::Node::IDENTIFIER) { // Self function call. @@ -563,22 +563,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (_have_exact_arguments(method, arguments)) { // Exact arguments, use ptrcall. - gen->write_call_ptrcall(result, self, method, arguments); + gen->write_call_ptrcall(return_addr, self, method, arguments); } else { // Not exact arguments, but still can use method bind call. - gen->write_call_method_bind(result, self, method, arguments); + gen->write_call_method_bind(return_addr, self, method, arguments); } } else if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") { GDScriptCodeGenerator::Address self; self.mode = GDScriptCodeGenerator::Address::CLASS; if (within_await) { - gen->write_call_async(result, self, call->function_name, arguments); + gen->write_call_async(return_addr, self, call->function_name, arguments); } else { gen->write_call(return_addr, self, call->function_name, arguments); } } else { if (within_await) { - gen->write_call_self_async(result, call->function_name, arguments); + gen->write_call_self_async(return_addr, call->function_name, arguments); } else { gen->write_call_self(return_addr, call->function_name, arguments); } @@ -589,18 +589,18 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (subscript->is_attribute) { // May be static built-in method call. if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) { - gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments); + gen->write_call_builtin_type_static(return_addr, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments); } else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") && ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) { // It's a static native method call. - gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments); + gen->write_call_native_static(return_addr, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments); } else { GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); if (r_error) { return GDScriptCodeGenerator::Address(); } if (within_await) { - gen->write_call_async(result, base, call->function_name, arguments); + gen->write_call_async(return_addr, base, call->function_name, arguments); } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) { // Native method, use faster path. StringName class_name; @@ -613,16 +613,16 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code MethodBind *method = ClassDB::get_method(class_name, call->function_name); if (_have_exact_arguments(method, arguments)) { // Exact arguments, use ptrcall. - gen->write_call_ptrcall(result, base, method, arguments); + gen->write_call_ptrcall(return_addr, base, method, arguments); } else { // Not exact arguments, but still can use method bind call. - gen->write_call_method_bind(result, base, method, arguments); + gen->write_call_method_bind(return_addr, base, method, arguments); } } else { gen->write_call(return_addr, base, call->function_name, arguments); } } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { - gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); + gen->write_call_builtin_type(return_addr, base, base.type.builtin_type, call->function_name, arguments); } else { gen->write_call(return_addr, base, call->function_name, arguments); } @@ -2636,10 +2636,6 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser: } } -#ifdef TOOLS_ENABLED - p_script->_update_doc(); -#endif - p_script->_init_rpc_methods_properties(); p_script->valid = true; @@ -2724,6 +2720,10 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri return err; } +#ifdef TOOLS_ENABLED + p_script->_update_doc(); +#endif + return GDScriptCache::finish_compiling(main_script->get_path()); } diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index c8dcb531fa..447a93a68d 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -1541,8 +1541,28 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Callable::CallError err; if (call_ret) { GET_INSTRUCTION_ARG(ret, argc + 1); +#ifdef DEBUG_ENABLED + Variant::Type base_type = base->get_type(); + Object *base_obj = base->get_validated_object(); + StringName base_class = base_obj ? base_obj->get_class_name() : StringName(); +#endif base->callp(*methodname, (const Variant **)argptrs, argc, *ret, err); #ifdef DEBUG_ENABLED + if (ret->get_type() == Variant::NIL) { + if (base_type == Variant::OBJECT) { + if (base_obj) { + MethodBind *method = ClassDB::get_method(base_class, *methodname); + if (*methodname == CoreStringNames::get_singleton()->_free || (method && !method->has_return())) { + err_text = R"(Trying to get a return value of a method that returns "void")"; + OPCODE_BREAK; + } + } + } else if (Variant::has_builtin_method(base_type, *methodname) && !Variant::has_builtin_method_return_value(base_type, *methodname)) { + err_text = R"(Trying to get a return value of a method that returns "void")"; + OPCODE_BREAK; + } + } + if (!call_async && ret->get_type() == Variant::OBJECT) { // Check if getting a function state without await. bool was_freed = false; diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index 36bc051643..9ae4bdae56 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -80,10 +80,6 @@ String GDScriptWarning::get_message() const { case STANDALONE_EXPRESSION: { return "Standalone expression (the line has no effect)."; } break; - case VOID_ASSIGNMENT: { - CHECK_SYMBOLS(1); - return "Assignment operation, but the function '" + symbols[0] + "()' returns void."; - } break; case NARROWING_CONVERSION: { return "Narrowing conversion (float is converted to int and loses precision)."; } break; @@ -202,7 +198,6 @@ String GDScriptWarning::get_name_from_code(Code p_code) { "UNREACHABLE_CODE", "UNREACHABLE_PATTERN", "STANDALONE_EXPRESSION", - "VOID_ASSIGNMENT", "NARROWING_CONVERSION", "INCOMPATIBLE_TERNARY", "UNUSED_SIGNAL", diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index 7e4e975510..df6ee71425 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -57,7 +57,6 @@ public: UNREACHABLE_CODE, // Code after a return statement. UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind). STANDALONE_EXPRESSION, // Expression not assigned to a variable. - VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable. NARROWING_CONVERSION, // Float value into an integer slot, precision is lost. INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible. UNUSED_SIGNAL, // Signal is defined but never emitted. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd new file mode 100644 index 0000000000..63587942f7 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd @@ -0,0 +1,2 @@ +func test() -> void: + return null diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out new file mode 100644 index 0000000000..3c09f44ba9 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +A void function cannot return a value. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd new file mode 100644 index 0000000000..0ee4e7ea36 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd @@ -0,0 +1,4 @@ +func test() -> void: + var a + a = 1 + return a diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out new file mode 100644 index 0000000000..3c09f44ba9 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +A void function cannot return a value. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd new file mode 100644 index 0000000000..a3450966cc --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd @@ -0,0 +1,3 @@ +func test(): + var builtin := [] + print(builtin.reverse()) # Built-in type method. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out new file mode 100644 index 0000000000..225c85e9c7 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot get return value of call to "reverse()" because it returns "void". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd new file mode 100644 index 0000000000..2162a181ac --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd @@ -0,0 +1,5 @@ +func foo() -> void: + pass + +func test(): + print(foo()) # Custom method. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out new file mode 100644 index 0000000000..2b1a607883 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot get return value of call to "foo()" because it returns "void". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd new file mode 100644 index 0000000000..f3443d985e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd @@ -0,0 +1,2 @@ +func test(): + print(print_debug()) # GDScript utility function. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out new file mode 100644 index 0000000000..502c18ab9d --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot get return value of call to "print_debug()" because it returns "void". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd new file mode 100644 index 0000000000..b8e81b160a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd @@ -0,0 +1,3 @@ +func test(): + var obj := Node.new() + print(obj.free()) # Native type method. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out new file mode 100644 index 0000000000..88be39345b --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot get return value of call to "free()" because it returns "void". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd new file mode 100644 index 0000000000..8eabed4271 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd @@ -0,0 +1,2 @@ +func test(): + print(print()) # Built-in utility function. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out new file mode 100644 index 0000000000..ebf43186be --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot get return value of call to "print()" because it returns "void". diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.gd new file mode 100644 index 0000000000..25381035b2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.gd @@ -0,0 +1,15 @@ +const Preloaded := preload( 'preload_script_native_type.notest.gd' ) + +func test() -> void: + var inferred := Preloaded.new() + var inferred_owner := inferred.owner + + var typed: Preloaded + typed = Preloaded.new() + var typed_owner := typed.owner + + print(typed_owner == inferred_owner) + + inferred.free() + typed.free() + print('ok') diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.notest.gd new file mode 100644 index 0000000000..61510e14cd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.notest.gd @@ -0,0 +1 @@ +extends Node diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.out b/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.out new file mode 100644 index 0000000000..3e24a1e2af --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_script_native_type.out @@ -0,0 +1,3 @@ +GDTEST_OK +true +ok diff --git a/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd new file mode 100644 index 0000000000..c9caef7d7c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd @@ -0,0 +1,5 @@ +func variant() -> Variant: + return 'variant' + +func test(): + print(variant()) diff --git a/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out new file mode 100644 index 0000000000..57fe608cc5 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out @@ -0,0 +1,2 @@ +GDTEST_OK +variant diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd deleted file mode 100644 index b4a42b3e3d..0000000000 --- a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd +++ /dev/null @@ -1,6 +0,0 @@ -func i_return_void() -> void: - return - - -func test(): - var __ = i_return_void() diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out deleted file mode 100644 index 84c9598f9a..0000000000 --- a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out +++ /dev/null @@ -1,5 +0,0 @@ -GDTEST_OK ->> WARNING ->> Line: 6 ->> VOID_ASSIGNMENT ->> Assignment operation, but the function 'i_return_void()' returns void. diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd new file mode 100644 index 0000000000..a3daf70627 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd @@ -0,0 +1,4 @@ +func test(): + var obj + obj = Node.new() + print(obj.free()) diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out new file mode 100644 index 0000000000..5edaf19442 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/use_return_value_of_free_call.gd +>> 4 +>> Trying to get a return value of a method that returns "void" diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd new file mode 100644 index 0000000000..49fb76ad1f --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd @@ -0,0 +1,4 @@ +func test(): + var value + value = [] + print(value.reverse()) diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out new file mode 100644 index 0000000000..128356ff8a --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/use_return_value_of_void_builtin_method_call.gd +>> 4 +>> Trying to get a return value of a method that returns "void" diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd new file mode 100644 index 0000000000..44f9aa467a --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd @@ -0,0 +1,4 @@ +func test(): + var obj + obj = RefCounted.new() + print(obj.notify_property_list_changed()) diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out new file mode 100644 index 0000000000..e02c206778 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/use_return_value_of_void_native_method_call.gd +>> 4 +>> Trying to get a return value of a method that returns "void" diff --git a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd index 5303fb04e2..9b64084fa6 100644 --- a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd +++ b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd @@ -15,10 +15,10 @@ func test(): var string_array: Array[String] = [] var stringname_array: Array[StringName] = [] - assert(!string_array.push_back(&"abc")) + string_array.push_back(&"abc") print("Array[String] insert converted: ", typeof(string_array[0]) == TYPE_STRING) - assert(!stringname_array.push_back("abc")) + stringname_array.push_back("abc") print("Array[StringName] insert converted: ", typeof(stringname_array[0]) == TYPE_STRING_NAME) print("StringName in Array[String]: ", &"abc" in string_array) @@ -28,8 +28,8 @@ func test(): assert(!packed_string_array.push_back("abc")) print("StringName in PackedStringArray: ", &"abc" in packed_string_array) - assert(!string_array.push_back("abc")) + string_array.push_back("abc") print("StringName finds String in Array: ", string_array.find(&"abc")) - assert(!stringname_array.push_back(&"abc")) + stringname_array.push_back(&"abc") print("String finds StringName in Array: ", stringname_array.find("abc")) diff --git a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp index cfa498af65..4b71511582 100644 --- a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp +++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp @@ -59,6 +59,7 @@ Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFState> p_sta mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path()); node->replace_by(mesh_instance_node_3d); delete_queue.push_back(node); + node = mesh_instance_node_3d; } else { memdelete(mesh_instance_node_3d); } diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 89ef9ddd90..186e6a504f 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -1405,6 +1405,7 @@ GridMapEditor::GridMapEditor() { } GridMapEditor::~GridMapEditor() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); _clear_clipboard_data(); for (int i = 0; i < 3; i++) { diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index e396d77d86..d23d68ffba 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -796,6 +796,10 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) { } void GridMap::_octant_exit_world(const OctantKey &p_key) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); + ERR_FAIL_NULL(NavigationServer3D::get_singleton()); + ERR_FAIL_COND(!octant_map.has(p_key)); Octant &g = *octant_map[p_key]; PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); @@ -834,6 +838,10 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) { } void GridMap::_octant_clean_up(const OctantKey &p_key) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); + ERR_FAIL_NULL(NavigationServer3D::get_singleton()); + ERR_FAIL_COND(!octant_map.has(p_key)); Octant &g = *octant_map[p_key]; @@ -1186,6 +1194,7 @@ Vector3 GridMap::_get_offset() const { } void GridMap::clear_baked_meshes() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); for (int i = 0; i < baked_meshes.size(); i++) { RS::get_singleton()->free(baked_meshes[i].instance); } diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp index 8c785d7591..1b6f1d7897 100644 --- a/modules/noise/noise_texture_2d.cpp +++ b/modules/noise/noise_texture_2d.cpp @@ -40,6 +40,7 @@ NoiseTexture2D::NoiseTexture2D() { } NoiseTexture2D::~NoiseTexture2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (texture.is_valid()) { RS::get_singleton()->free(texture); } diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 84542be3b9..fefee9bb24 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -95,10 +95,13 @@ if env["opengl3"]: env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_depth_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_htc_controller_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_huawei_controller_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_rate_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_wmr_controller_extension.cpp") env.modules_sources += module_obj diff --git a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp b/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp index db4062b196..4dacfcca9f 100644 --- a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp @@ -29,8 +29,7 @@ /*************************************************************************/ #include "openxr_interaction_profile_meta_data.h" - -#include <openxr/openxr.h> +#include "../openxr_api.h" OpenXRInteractionProfileMetaData *OpenXRInteractionProfileMetaData::singleton = nullptr; @@ -38,6 +37,7 @@ OpenXRInteractionProfileMetaData::OpenXRInteractionProfileMetaData() { singleton = this; _register_core_metadata(); + OpenXRAPI::register_extension_metadata(); } OpenXRInteractionProfileMetaData::~OpenXRInteractionProfileMetaData() { @@ -394,320 +394,4 @@ void OpenXRInteractionProfileMetaData::_register_core_metadata() { register_io_path("/interaction_profiles/valve/index_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); register_io_path("/interaction_profiles/valve/index_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // HP MR controller (newer G2 controllers) - // TODO move this into an extension once this is supported. - register_interaction_profile("HPMR controller", "/interaction_profiles/hp/mixed_reality_controller", XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Samsung Odyssey controller - // TODO move this into an extension once this is supported. - register_interaction_profile("Samsung Odyssey controller", "/interaction_profiles/samsung/odyssey_controller", XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // HTC Vive Cosmos controller - // TODO move this into an extension once this is supported. - register_interaction_profile("Vive Cosmos controller", "/interaction_profiles/htc/vive_cosmos_controller", XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/left", "/user/hand/left/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/right", "/user/hand/right/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // HTC Vive Focus 3 controller - // TODO move this into an extension once this is supported. - register_interaction_profile("Vive Focus 3 controller", "/interaction_profiles/htc/vive_focus3_controller", XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch ", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/left", "/user/hand/left/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/right", "/user/hand/right/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // Huawei controller - // TODO move this into an extension once this is supported. - register_interaction_profile("Huawei controller", "/interaction_profiles/huawei/controller", XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME); - register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - - register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/left", "/user/hand/left/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/right", "/user/hand/right/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/left", "/user/hand/left/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/right", "/user/hand/right/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/left", "/user/hand/left/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/right", "/user/hand/right/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/left", "/user/hand/left/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/right", "/user/hand/right/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - - // HTC Vive tracker - // Interestingly enough trackers don't have buttons or inputs, yet these are defined in the spec. - // I think this can be supported through attachments on the trackers. - // TODO move this into an extension once this is supported. - register_interaction_profile("HTC Vive tracker", "/interaction_profiles/htc/vive_tracker_htcx", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); - - // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); - register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); } diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp index 402a2ee707..8a08016d9f 100644 --- a/modules/openxr/extensions/openxr_android_extension.cpp +++ b/modules/openxr/extensions/openxr_android_extension.cpp @@ -44,11 +44,17 @@ OpenXRAndroidExtension *OpenXRAndroidExtension::get_singleton() { return singleton; } -OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) : - OpenXRExtensionWrapper(p_openxr_api) { +OpenXRAndroidExtension::OpenXRAndroidExtension() { singleton = this; +} + +HashMap<String, bool *> OpenXRAndroidExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + request_extensions[XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME] = &loader_init_extension_available; request_extensions[XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME] = &create_instance_extension_available; + + return request_extensions; } void OpenXRAndroidExtension::on_before_instance_created() { diff --git a/modules/openxr/extensions/openxr_android_extension.h b/modules/openxr/extensions/openxr_android_extension.h index 087b634756..03b7233b7f 100644 --- a/modules/openxr/extensions/openxr_android_extension.h +++ b/modules/openxr/extensions/openxr_android_extension.h @@ -38,8 +38,9 @@ class OpenXRAndroidExtension : public OpenXRExtensionWrapper { public: static OpenXRAndroidExtension *get_singleton(); - OpenXRAndroidExtension(OpenXRAPI *p_openxr_api); + OpenXRAndroidExtension(); + virtual HashMap<String, bool *> get_requested_extensions() override; virtual void on_before_instance_created() override; virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) override; diff --git a/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp index 0f6aaf8afb..0eed0f6cd9 100644 --- a/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp +++ b/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp @@ -36,17 +36,22 @@ OpenXRCompositionLayerDepthExtension *OpenXRCompositionLayerDepthExtension::get_ return singleton; } -OpenXRCompositionLayerDepthExtension::OpenXRCompositionLayerDepthExtension(OpenXRAPI *p_openxr_api) : - OpenXRExtensionWrapper(p_openxr_api) { +OpenXRCompositionLayerDepthExtension::OpenXRCompositionLayerDepthExtension() { singleton = this; - - request_extensions[XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME] = &available; } OpenXRCompositionLayerDepthExtension::~OpenXRCompositionLayerDepthExtension() { singleton = nullptr; } +HashMap<String, bool *> OpenXRCompositionLayerDepthExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME] = &available; + + return request_extensions; +} + bool OpenXRCompositionLayerDepthExtension::is_available() { return available; } diff --git a/modules/openxr/extensions/openxr_composition_layer_depth_extension.h b/modules/openxr/extensions/openxr_composition_layer_depth_extension.h index 9533783d83..c4d4bbfa5a 100644 --- a/modules/openxr/extensions/openxr_composition_layer_depth_extension.h +++ b/modules/openxr/extensions/openxr_composition_layer_depth_extension.h @@ -38,9 +38,10 @@ class OpenXRCompositionLayerDepthExtension : public OpenXRExtensionWrapper, publ public: static OpenXRCompositionLayerDepthExtension *get_singleton(); - OpenXRCompositionLayerDepthExtension(OpenXRAPI *p_openxr_api); + OpenXRCompositionLayerDepthExtension(); virtual ~OpenXRCompositionLayerDepthExtension() override; + virtual HashMap<String, bool *> get_requested_extensions() override; bool is_available(); virtual XrCompositionLayerBaseHeader *get_composition_layer() override; diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index eed969d628..25383c12d6 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -42,19 +42,14 @@ class OpenXRAPI; class OpenXRActionMap; +// `OpenXRExtensionWrapper` allows us to implement OpenXR extensions. class OpenXRExtensionWrapper { -protected: - OpenXRAPI *openxr_api = nullptr; - - // Store extension we require. - // If bool pointer is a nullptr this means this extension is mandatory and initialisation will fail if it is not available - // If bool pointer is set, value will be set to true or false depending on whether extension is available - HashMap<String, bool *> request_extensions; - public: - virtual HashMap<String, bool *> get_request_extensions() { - return request_extensions; - } + // `get_requested_extensions` should return a list of OpenXR extensions related to this extension. + // If the bool * is a nullptr this extension is mandatory + // If the bool * points to a boolean, the boolean will be updated + // to true if the extension is enabled. + virtual HashMap<String, bool *> get_requested_extensions() = 0; // These functions allow an extension to add entries to a struct chain. // `p_next_pointer` points to the last struct that was created for this chain @@ -62,49 +57,60 @@ public: // You should return the pointer to the last struct you define as your result. // If you are not adding any structs, just return `p_next_pointer`. // See existing extensions for examples of this implementation. - virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } - virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } - virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } - virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when we interogate OpenXRS system abilities. + virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when we create our OpenXR instance. + virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when we create our OpenXR session. + virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when creating OpenXR swap chains. - virtual void on_before_instance_created() {} - virtual void on_instance_created(const XrInstance p_instance) {} - virtual void on_instance_destroyed() {} - virtual void on_session_created(const XrSession p_instance) {} + // `on_register_metadata` allows extensions to register additional controller metadata. + // This function is called even when OpenXRApi is not constructured as the metadata + // needs to be available to the editor. + // Also extensions should provide metadata regardless of whether they are supported + // on the host system as the controller data is used to setup action maps for users + // who may have access to the relevant hardware. + virtual void on_register_metadata() {} + + virtual void on_before_instance_created() {} // `on_before_instance_created` is called before we create our OpenXR instance. + virtual void on_instance_created(const XrInstance p_instance) {} // `on_instance_created` is called right after we've successfully created our OpenXR instance. + virtual void on_instance_destroyed() {} // `on_instance_destroyed` is called right before we destroy our OpenXR instance. + virtual void on_session_created(const XrSession p_instance) {} // `on_session_created` is called right after we've successsfully created our OpenXR session. + virtual void on_session_destroyed() {} // `on_session_destroyed` is called right before we destroy our OpenXR session. + + // `on_process` is called as part of our OpenXR process handling, + // this happens right before physics process and normal processing is run. + // This is when controller data is queried and made available to game logic. virtual void on_process() {} - virtual void on_pre_render() {} - virtual void on_session_destroyed() {} + virtual void on_pre_render() {} // `on_pre_render` is called right before we start rendering our XR viewport. - virtual void on_state_idle() {} - virtual void on_state_ready() {} - virtual void on_state_synchronized() {} - virtual void on_state_visible() {} - virtual void on_state_focused() {} - virtual void on_state_stopping() {} - virtual void on_state_loss_pending() {} - virtual void on_state_exiting() {} + virtual void on_state_idle() {} // `on_state_idle` is called when the OpenXR session state is changed to idle. + virtual void on_state_ready() {} // `on_state_ready` is called when the OpenXR session state is changed to ready, this means OpenXR is ready to setup our session. + virtual void on_state_synchronized() {} // `on_state_synchronized` is called when the OpenXR session state is changed to synchronized, note that OpenXR also returns to this state when our application looses focus. + virtual void on_state_visible() {} // `on_state_visible` is called when the OpenXR session state is changed to visible, OpenXR is now ready to receive frames. + virtual void on_state_focused() {} // `on_state_focused` is called when the OpenXR session state is changed to focused, this state is the active state when our game runs. + virtual void on_state_stopping() {} // `on_state_stopping` is called when the OpenXR session state is changed to stopping. + virtual void on_state_loss_pending() {} // `on_state_loss_pending` is called when the OpenXR session state is changed to loss pending. + virtual void on_state_exiting() {} // `on_state_exiting` is called when the OpenXR session state is changed to exiting. - // Returns true if the event was handled, false otherwise. + // `on_event_polled` is called when there is an OpenXR event to process. + // Should return true if the event was handled, false otherwise. virtual bool on_event_polled(const XrEventDataBuffer &event) { return false; } - OpenXRExtensionWrapper(OpenXRAPI *p_openxr_api) { openxr_api = p_openxr_api; }; + OpenXRExtensionWrapper() = default; virtual ~OpenXRExtensionWrapper() = default; }; +// `OpenXRGraphicsExtensionWrapper` implements specific logic for each supported graphics API. class OpenXRGraphicsExtensionWrapper : public OpenXRExtensionWrapper { public: - virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) = 0; - virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) = 0; - virtual String get_swapchain_format_name(int64_t p_swapchain_format) const = 0; - virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) = 0; - virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0; - virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) = 0; - virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) = 0; - - OpenXRGraphicsExtensionWrapper(OpenXRAPI *p_openxr_api) : - OpenXRExtensionWrapper(p_openxr_api){}; + virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) = 0; // `get_usable_swapchain_formats` should return a list of usable color formats. + virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) = 0; // `get_usable_depth_formats` should return a list of usable depth formats. + virtual String get_swapchain_format_name(int64_t p_swapchain_format) const = 0; // `get_swapchain_format_name` should return the constant name of a given format. + virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) = 0; // `get_swapchain_image_data` extracts image IDs for the swapchain images and stores there in an implementation dependent data structure. + virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0; // `cleanup_swapchain_graphics_data` cleans up the data held in our implementation dependent data structure and should free up its memory. + virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) = 0; // `create_projection_fov` creates a proper projection matrix based on asymmetric FOV data provided by OpenXR. + virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) = 0; // `get_texture` returns a Godot texture RID for the current active texture in our swapchain. }; #endif // OPENXR_EXTENSION_WRAPPER_H diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp index c0bbaea5b4..09c5f0b06d 100644 --- a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp +++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp @@ -36,18 +36,22 @@ OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::get_single return singleton; } -OpenXRDisplayRefreshRateExtension::OpenXRDisplayRefreshRateExtension(OpenXRAPI *p_openxr_api) : - OpenXRExtensionWrapper(p_openxr_api) { +OpenXRDisplayRefreshRateExtension::OpenXRDisplayRefreshRateExtension() { singleton = this; - - // Extensions we use for our hand tracking. - request_extensions[XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME] = &display_refresh_rate_ext; } OpenXRDisplayRefreshRateExtension::~OpenXRDisplayRefreshRateExtension() { display_refresh_rate_ext = false; } +HashMap<String, bool *> OpenXRDisplayRefreshRateExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME] = &display_refresh_rate_ext; + + return request_extensions; +} + void OpenXRDisplayRefreshRateExtension::on_instance_created(const XrInstance p_instance) { if (display_refresh_rate_ext) { EXT_INIT_XR_FUNC(xrEnumerateDisplayRefreshRatesFB); @@ -65,9 +69,9 @@ float OpenXRDisplayRefreshRateExtension::get_refresh_rate() const { if (display_refresh_rate_ext) { float rate; - XrResult result = xrGetDisplayRefreshRateFB(openxr_api->get_session(), &rate); + XrResult result = xrGetDisplayRefreshRateFB(OpenXRAPI::get_singleton()->get_session(), &rate); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to obtain refresh rate [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to obtain refresh rate [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); } else { refresh_rate = rate; } @@ -78,9 +82,9 @@ float OpenXRDisplayRefreshRateExtension::get_refresh_rate() const { void OpenXRDisplayRefreshRateExtension::set_refresh_rate(float p_refresh_rate) { if (display_refresh_rate_ext) { - XrResult result = xrRequestDisplayRefreshRateFB(openxr_api->get_session(), p_refresh_rate); + XrResult result = xrRequestDisplayRefreshRateFB(OpenXRAPI::get_singleton()->get_session(), p_refresh_rate); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to set refresh rate [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to set refresh rate [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); } } } @@ -91,21 +95,21 @@ Array OpenXRDisplayRefreshRateExtension::get_available_refresh_rates() const { if (display_refresh_rate_ext) { uint32_t display_refresh_rate_count = 0; - result = xrEnumerateDisplayRefreshRatesFB(openxr_api->get_session(), 0, &display_refresh_rate_count, nullptr); + result = xrEnumerateDisplayRefreshRatesFB(OpenXRAPI::get_singleton()->get_session(), 0, &display_refresh_rate_count, nullptr); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to obtain refresh rates count [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to obtain refresh rates count [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); } if (display_refresh_rate_count > 0) { float *display_refresh_rates = (float *)memalloc(sizeof(float) * display_refresh_rate_count); if (display_refresh_rates == nullptr) { - print_line("OpenXR: Failed to obtain refresh rates memory buffer [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to obtain refresh rates memory buffer [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); return arr; } - result = xrEnumerateDisplayRefreshRatesFB(openxr_api->get_session(), display_refresh_rate_count, &display_refresh_rate_count, display_refresh_rates); + result = xrEnumerateDisplayRefreshRatesFB(OpenXRAPI::get_singleton()->get_session(), display_refresh_rate_count, &display_refresh_rate_count, display_refresh_rates); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to obtain refresh rates count [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to obtain refresh rates count [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); memfree(display_refresh_rates); return arr; } diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h index dcd52fe4d1..a86cf7d196 100644 --- a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h +++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h @@ -45,9 +45,11 @@ class OpenXRDisplayRefreshRateExtension : public OpenXRExtensionWrapper { public: static OpenXRDisplayRefreshRateExtension *get_singleton(); - OpenXRDisplayRefreshRateExtension(OpenXRAPI *p_openxr_api); + OpenXRDisplayRefreshRateExtension(); virtual ~OpenXRDisplayRefreshRateExtension() override; + virtual HashMap<String, bool *> get_requested_extensions() override; + virtual void on_instance_created(const XrInstance p_instance) override; virtual void on_instance_destroyed() override; diff --git a/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.cpp b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.cpp index 259b1236a3..9172cb9dae 100644 --- a/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.cpp +++ b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.cpp @@ -42,10 +42,7 @@ OpenXRFbPassthroughExtensionWrapper *OpenXRFbPassthroughExtensionWrapper::get_si return singleton; } -OpenXRFbPassthroughExtensionWrapper::OpenXRFbPassthroughExtensionWrapper(OpenXRAPI *p_openxr_api) : - OpenXRExtensionWrapper(p_openxr_api) { - request_extensions[XR_FB_PASSTHROUGH_EXTENSION_NAME] = &fb_passthrough_ext; - request_extensions[XR_FB_TRIANGLE_MESH_EXTENSION_NAME] = &fb_triangle_mesh_ext; +OpenXRFbPassthroughExtensionWrapper::OpenXRFbPassthroughExtensionWrapper() { singleton = this; } @@ -53,6 +50,15 @@ OpenXRFbPassthroughExtensionWrapper::~OpenXRFbPassthroughExtensionWrapper() { cleanup(); } +HashMap<String, bool *> OpenXRFbPassthroughExtensionWrapper::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_FB_PASSTHROUGH_EXTENSION_NAME] = &fb_passthrough_ext; + request_extensions[XR_FB_TRIANGLE_MESH_EXTENSION_NAME] = &fb_triangle_mesh_ext; + + return request_extensions; +} + void OpenXRFbPassthroughExtensionWrapper::cleanup() { fb_passthrough_ext = false; fb_triangle_mesh_ext = false; @@ -93,7 +99,7 @@ void OpenXRFbPassthroughExtensionWrapper::on_instance_created(const XrInstance i } if (fb_passthrough_ext) { - openxr_api->register_composition_layer_provider(this); + OpenXRAPI::get_singleton()->register_composition_layer_provider(this); } } @@ -122,7 +128,7 @@ bool OpenXRFbPassthroughExtensionWrapper::start_passthrough() { } // Create the passthrough layer - result = xrCreatePassthroughLayerFB(openxr_api->get_session(), &passthrough_layer_config, &passthrough_layer); + result = xrCreatePassthroughLayerFB(OpenXRAPI::get_singleton()->get_session(), &passthrough_layer_config, &passthrough_layer); if (!is_valid_passthrough_result(result, "Failed to create the passthrough layer")) { stop_passthrough(); return false; @@ -142,8 +148,8 @@ bool OpenXRFbPassthroughExtensionWrapper::start_passthrough() { void OpenXRFbPassthroughExtensionWrapper::on_session_created(const XrSession session) { if (fb_passthrough_ext) { // Create the passthrough feature and start it. - XrResult result = xrCreatePassthroughFB(openxr_api->get_session(), &passthrough_create_info, &passthrough_handle); - if (!openxr_api->xr_result(result, "Failed to create passthrough")) { + XrResult result = xrCreatePassthroughFB(OpenXRAPI::get_singleton()->get_session(), &passthrough_create_info, &passthrough_handle); + if (!OpenXRAPI::get_singleton()->xr_result(result, "Failed to create passthrough")) { passthrough_handle = XR_NULL_HANDLE; return; } @@ -169,13 +175,13 @@ void OpenXRFbPassthroughExtensionWrapper::stop_passthrough() { if (passthrough_layer != XR_NULL_HANDLE) { // Destroy the layer result = xrDestroyPassthroughLayerFB(passthrough_layer); - openxr_api->xr_result(result, "Unable to destroy passthrough layer"); + OpenXRAPI::get_singleton()->xr_result(result, "Unable to destroy passthrough layer"); passthrough_layer = XR_NULL_HANDLE; } if (passthrough_handle != XR_NULL_HANDLE) { result = xrPassthroughPauseFB(passthrough_handle); - openxr_api->xr_result(result, "Unable to stop passthrough feature"); + OpenXRAPI::get_singleton()->xr_result(result, "Unable to stop passthrough feature"); } } @@ -186,7 +192,7 @@ void OpenXRFbPassthroughExtensionWrapper::on_session_destroyed() { XrResult result; if (passthrough_handle != XR_NULL_HANDLE) { result = xrDestroyPassthroughFB(passthrough_handle); - openxr_api->xr_result(result, "Unable to destroy passthrough feature"); + OpenXRAPI::get_singleton()->xr_result(result, "Unable to destroy passthrough feature"); passthrough_handle = XR_NULL_HANDLE; } } @@ -194,13 +200,13 @@ void OpenXRFbPassthroughExtensionWrapper::on_session_destroyed() { void OpenXRFbPassthroughExtensionWrapper::on_instance_destroyed() { if (fb_passthrough_ext) { - openxr_api->unregister_composition_layer_provider(this); + OpenXRAPI::get_singleton()->unregister_composition_layer_provider(this); } cleanup(); } bool OpenXRFbPassthroughExtensionWrapper::initialize_fb_passthrough_extension(const XrInstance p_instance) { - ERR_FAIL_NULL_V(openxr_api, false); + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false); EXT_INIT_XR_FUNC_V(xrCreatePassthroughFB); EXT_INIT_XR_FUNC_V(xrDestroyPassthroughFB); @@ -219,7 +225,7 @@ bool OpenXRFbPassthroughExtensionWrapper::initialize_fb_passthrough_extension(co } bool OpenXRFbPassthroughExtensionWrapper::initialize_fb_triangle_mesh_extension(const XrInstance p_instance) { - ERR_FAIL_NULL_V(openxr_api, false); + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false); EXT_INIT_XR_FUNC_V(xrCreateTriangleMeshFB); EXT_INIT_XR_FUNC_V(xrDestroyTriangleMeshFB); diff --git a/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h index 1959f3fdc4..7df59c765e 100644 --- a/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_fb_passthrough_extension_wrapper.h @@ -43,9 +43,12 @@ class Viewport; // Wrapper for the set of Facebook XR passthrough extensions. class OpenXRFbPassthroughExtensionWrapper : public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider { - friend class OpenXRAPI; - public: + OpenXRFbPassthroughExtensionWrapper(); + ~OpenXRFbPassthroughExtensionWrapper(); + + virtual HashMap<String, bool *> get_requested_extensions() override; + void on_instance_created(const XrInstance instance) override; void on_session_created(const XrSession session) override; @@ -68,10 +71,6 @@ public: static OpenXRFbPassthroughExtensionWrapper *get_singleton(); -protected: - OpenXRFbPassthroughExtensionWrapper(OpenXRAPI *p_openxr_api); - ~OpenXRFbPassthroughExtensionWrapper(); - private: // Create a passthrough feature EXT_PROTO_XRRESULT_FUNC3(xrCreatePassthroughFB, @@ -208,7 +207,7 @@ private: // returned even when the operation is valid on Meta Quest devices. // The issue should be addressed on that platform in OS release v37. inline bool is_valid_passthrough_result(XrResult result, const char *format) { - return openxr_api->xr_result(result, format) || result == XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB; + return OpenXRAPI::get_singleton()->xr_result(result, format) || result == XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB; } Viewport *get_main_viewport(); @@ -234,12 +233,6 @@ private: XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB, XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB, }; - XrPassthroughStyleFB passthrough_layer_style = { - XR_TYPE_PASSTHROUGH_STYLE_FB, - nullptr, - 1, - { 0, 0, 0, 0 }, - }; XrPassthroughLayerFB passthrough_layer = XR_NULL_HANDLE; XrCompositionLayerPassthroughFB composition_passthrough_layer = { diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp index 85e2ee4903..989f431698 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -41,15 +41,9 @@ OpenXRHandTrackingExtension *OpenXRHandTrackingExtension::get_singleton() { return singleton; } -OpenXRHandTrackingExtension::OpenXRHandTrackingExtension(OpenXRAPI *p_openxr_api) : - OpenXRExtensionWrapper(p_openxr_api) { +OpenXRHandTrackingExtension::OpenXRHandTrackingExtension() { singleton = this; - // Extensions we use for our hand tracking. - request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext; - request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext; - request_extensions[XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME] = &hand_tracking_aim_state_ext; - // Make sure this is cleared until we actually request it handTrackingSystemProperties.supportsHandTracking = false; } @@ -58,6 +52,16 @@ OpenXRHandTrackingExtension::~OpenXRHandTrackingExtension() { singleton = nullptr; } +HashMap<String, bool *> OpenXRHandTrackingExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext; + request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext; + request_extensions[XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME] = &hand_tracking_aim_state_ext; + + return request_extensions; +} + void OpenXRHandTrackingExtension::on_instance_created(const XrInstance p_instance) { if (hand_tracking_ext) { EXT_INIT_XR_FUNC(xrCreateHandTrackerEXT); @@ -127,7 +131,7 @@ void OpenXRHandTrackingExtension::on_process() { } // process our hands - const XrTime time = openxr_api->get_next_frame_time(); // This data will be used for the next frame we render + const XrTime time = OpenXRAPI::get_singleton()->get_next_frame_time(); // This data will be used for the next frame we render XrResult result; @@ -140,10 +144,10 @@ void OpenXRHandTrackingExtension::on_process() { XR_HAND_JOINT_SET_DEFAULT_EXT, // handJointSet }; - result = xrCreateHandTrackerEXT(openxr_api->get_session(), &createInfo, &hand_trackers[i].hand_tracker); + result = xrCreateHandTrackerEXT(OpenXRAPI::get_singleton()->get_session(), &createInfo, &hand_trackers[i].hand_tracker); if (XR_FAILED(result)) { // not successful? then we do nothing. - print_line("OpenXR: Failed to obtain hand tracking information [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to obtain hand tracking information [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); hand_trackers[i].is_initialized = false; } else { void *next_pointer = nullptr; @@ -192,14 +196,14 @@ void OpenXRHandTrackingExtension::on_process() { XrHandJointsLocateInfoEXT locateInfo = { XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, // type next_pointer, // next - openxr_api->get_play_space(), // baseSpace + OpenXRAPI::get_singleton()->get_play_space(), // baseSpace time, // time }; result = xrLocateHandJointsEXT(hand_trackers[i].hand_tracker, &locateInfo, &hand_trackers[i].locations); if (XR_FAILED(result)) { // not successful? then we do nothing. - print_line("OpenXR: Failed to get tracking for hand", i, "[", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to get tracking for hand", i, "[", OpenXRAPI::get_singleton()->get_error_string(result), "]"); continue; } diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h index 0eca80bcfb..8aef0a6d0e 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.h +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h @@ -54,9 +54,11 @@ public: static OpenXRHandTrackingExtension *get_singleton(); - OpenXRHandTrackingExtension(OpenXRAPI *p_openxr_api); + OpenXRHandTrackingExtension(); virtual ~OpenXRHandTrackingExtension() override; + virtual HashMap<String, bool *> get_requested_extensions() override; + virtual void on_instance_created(const XrInstance p_instance) override; virtual void on_instance_destroyed() override; virtual void on_session_destroyed() override; diff --git a/modules/openxr/extensions/openxr_htc_controller_extension.cpp b/modules/openxr/extensions/openxr_htc_controller_extension.cpp new file mode 100644 index 0000000000..321a27ad61 --- /dev/null +++ b/modules/openxr/extensions/openxr_htc_controller_extension.cpp @@ -0,0 +1,129 @@ +/*************************************************************************/ +/* openxr_htc_controller_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_htc_controller_extension.h" +#include "../action_map/openxr_interaction_profile_meta_data.h" + +HashMap<String, bool *> OpenXRHTCControllerExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available[HTC_VIVE_COSMOS]; + request_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available[HTC_VIVE_FOCUS3]; + + return request_extensions; +} + +bool OpenXRHTCControllerExtension::is_available(HTCControllers p_type) { + return available[p_type]; +} + +void OpenXRHTCControllerExtension::on_register_metadata() { + OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + ERR_FAIL_NULL(metadata); + + // HTC Vive Cosmos controller + metadata->register_interaction_profile("Vive Cosmos controller", "/interaction_profiles/htc/vive_cosmos_controller", XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/left", "/user/hand/left/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/right", "/user/hand/right/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + + // HTC Vive Focus 3 controller + metadata->register_interaction_profile("Vive Focus 3 controller", "/interaction_profiles/htc/vive_focus3_controller", XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch ", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/left", "/user/hand/left/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/right", "/user/hand/right/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); +} diff --git a/modules/openxr/extensions/openxr_htc_controller_extension.h b/modules/openxr/extensions/openxr_htc_controller_extension.h new file mode 100644 index 0000000000..fe346bd3a7 --- /dev/null +++ b/modules/openxr/extensions/openxr_htc_controller_extension.h @@ -0,0 +1,55 @@ +/*************************************************************************/ +/* openxr_htc_controller_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_HTC_CONTROLLER_EXTENSION_H +#define OPENXR_HTC_CONTROLLER_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +class OpenXRHTCControllerExtension : public OpenXRExtensionWrapper { +public: + enum HTCControllers { + // Note, HTC Vive Wand controllers are part of the core spec and not part of our extension. + HTC_VIVE_COSMOS, + HTC_VIVE_FOCUS3, + HTC_MAX_CONTROLLERS + }; + + virtual HashMap<String, bool *> get_requested_extensions() override; + + bool is_available(HTCControllers p_type); + + virtual void on_register_metadata() override; + +private: + bool available[HTC_MAX_CONTROLLERS] = { false, false }; +}; + +#endif // OPENXR_HTC_CONTROLLER_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp index 302acf4e30..e6316144c7 100644 --- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp @@ -29,29 +29,155 @@ /*************************************************************************/ #include "openxr_htc_vive_tracker_extension.h" +#include "../action_map/openxr_interaction_profile_meta_data.h" #include "core/string/print_string.h" -OpenXRHTCViveTrackerExtension *OpenXRHTCViveTrackerExtension::singleton = nullptr; - -OpenXRHTCViveTrackerExtension *OpenXRHTCViveTrackerExtension::get_singleton() { - return singleton; -} - -OpenXRHTCViveTrackerExtension::OpenXRHTCViveTrackerExtension(OpenXRAPI *p_openxr_api) : - OpenXRExtensionWrapper(p_openxr_api) { - singleton = this; +HashMap<String, bool *> OpenXRHTCViveTrackerExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; request_extensions[XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME] = &available; -} -OpenXRHTCViveTrackerExtension::~OpenXRHTCViveTrackerExtension() { - singleton = nullptr; + return request_extensions; } bool OpenXRHTCViveTrackerExtension::is_available() { return available; } +void OpenXRHTCViveTrackerExtension::on_register_metadata() { + OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + ERR_FAIL_NULL(metadata); + + // HTC Vive tracker + // Interestingly enough trackers don't have buttons or inputs, yet these are defined in the spec. + // I think this can be supported through attachments on the trackers. + metadata->register_interaction_profile("HTC Vive tracker", "/interaction_profiles/htc/vive_tracker_htcx", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + + // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + + // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); +} + bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &event) { switch (event.type) { case XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX: { diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h index 376af35e37..cba5ada96b 100644 --- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h +++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.h @@ -35,18 +35,14 @@ class OpenXRHTCViveTrackerExtension : public OpenXRExtensionWrapper { public: - static OpenXRHTCViveTrackerExtension *get_singleton(); - - OpenXRHTCViveTrackerExtension(OpenXRAPI *p_openxr_api); - virtual ~OpenXRHTCViveTrackerExtension() override; + virtual HashMap<String, bool *> get_requested_extensions() override; bool is_available(); + virtual void on_register_metadata() override; virtual bool on_event_polled(const XrEventDataBuffer &event) override; private: - static OpenXRHTCViveTrackerExtension *singleton; - bool available = false; }; diff --git a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp new file mode 100644 index 0000000000..4f1b2280ff --- /dev/null +++ b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp @@ -0,0 +1,83 @@ +/*************************************************************************/ +/* openxr_huawei_controller_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_huawei_controller_extension.h" +#include "../action_map/openxr_interaction_profile_meta_data.h" + +HashMap<String, bool *> OpenXRHuaweiControllerExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available; + + return request_extensions; +} + +bool OpenXRHuaweiControllerExtension::is_available() { + return available; +} + +void OpenXRHuaweiControllerExtension::on_register_metadata() { + OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + ERR_FAIL_NULL(metadata); + + // Huawei controller + metadata->register_interaction_profile("Huawei controller", "/interaction_profiles/huawei/controller", XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/left", "/user/hand/left/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/right", "/user/hand/right/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/left", "/user/hand/left/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/right", "/user/hand/right/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/left", "/user/hand/left/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/right", "/user/hand/right/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/left", "/user/hand/left/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/right", "/user/hand/right/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); +} diff --git a/modules/openxr/extensions/openxr_huawei_controller_extension.h b/modules/openxr/extensions/openxr_huawei_controller_extension.h new file mode 100644 index 0000000000..959bac0ef8 --- /dev/null +++ b/modules/openxr/extensions/openxr_huawei_controller_extension.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* openxr_huawei_controller_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_HUAWEI_CONTROLLER_EXTENSION_H +#define OPENXR_HUAWEI_CONTROLLER_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +class OpenXRHuaweiControllerExtension : public OpenXRExtensionWrapper { +public: + virtual HashMap<String, bool *> get_requested_extensions() override; + + bool is_available(); + + virtual void on_register_metadata() override; + +private: + bool available = false; +}; + +#endif // OPENXR_HUAWEI_CONTROLLER_EXTENSION_H diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp index 3b7c130149..efecf732e7 100644 --- a/modules/openxr/extensions/openxr_opengl_extension.cpp +++ b/modules/openxr/extensions/openxr_opengl_extension.cpp @@ -37,24 +37,21 @@ #include "servers/rendering/rendering_server_globals.h" #include "servers/rendering_server.h" -OpenXROpenGLExtension::OpenXROpenGLExtension(OpenXRAPI *p_openxr_api) : - OpenXRGraphicsExtensionWrapper(p_openxr_api) { +HashMap<String, bool *> OpenXROpenGLExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + #ifdef ANDROID_ENABLED request_extensions[XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME] = nullptr; #else request_extensions[XR_KHR_OPENGL_ENABLE_EXTENSION_NAME] = nullptr; #endif - ERR_FAIL_NULL(openxr_api); -} - -OpenXROpenGLExtension::~OpenXROpenGLExtension() { + return request_extensions; } void OpenXROpenGLExtension::on_instance_created(const XrInstance p_instance) { - ERR_FAIL_NULL(openxr_api); - // Obtain pointers to functions we're accessing here. + ERR_FAIL_NULL(OpenXRAPI::get_singleton()); #ifdef ANDROID_ENABLED EXT_INIT_XR_FUNC(xrGetOpenGLESGraphicsRequirementsKHR); @@ -65,10 +62,10 @@ void OpenXROpenGLExtension::on_instance_created(const XrInstance p_instance) { } bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_version) { - ERR_FAIL_NULL_V(openxr_api, false); + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false); - XrSystemId system_id = openxr_api->get_system_id(); - XrInstance instance = openxr_api->get_instance(); + XrSystemId system_id = OpenXRAPI::get_singleton()->get_system_id(); + XrInstance instance = OpenXRAPI::get_singleton()->get_instance(); #ifdef ANDROID_ENABLED XrGraphicsRequirementsOpenGLESKHR opengl_requirements; @@ -76,7 +73,7 @@ bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_versi opengl_requirements.next = nullptr; XrResult result = xrGetOpenGLESGraphicsRequirementsKHR(instance, system_id, &opengl_requirements); - if (!openxr_api->xr_result(result, "Failed to get OpenGL graphics requirements!")) { + if (!OpenXRAPI::get_singleton()->xr_result(result, "Failed to get OpenGL graphics requirements!")) { return false; } #else @@ -85,7 +82,7 @@ bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_versi opengl_requirements.next = nullptr; XrResult result = xrGetOpenGLGraphicsRequirementsKHR(instance, system_id, &opengl_requirements); - if (!openxr_api->xr_result(result, "Failed to get OpenGL graphics requirements!")) { + if (!OpenXRAPI::get_singleton()->xr_result(result, "Failed to get OpenGL graphics requirements!")) { return false; } #endif @@ -177,7 +174,7 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in uint32_t swapchain_length; XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to get swapchaim image count [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to get swapchaim image count [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); return false; } @@ -200,7 +197,7 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to get swapchaim images [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to get swapchaim images [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); memfree(images); return false; } diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/openxr_opengl_extension.h index 473c5157c0..34d50447d7 100644 --- a/modules/openxr/extensions/openxr_opengl_extension.h +++ b/modules/openxr/extensions/openxr_opengl_extension.h @@ -74,8 +74,7 @@ class OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper { public: - OpenXROpenGLExtension(OpenXRAPI *p_openxr_api); - virtual ~OpenXROpenGLExtension() override; + virtual HashMap<String, bool *> get_requested_extensions() override; virtual void on_instance_created(const XrInstance p_instance) override; virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override; diff --git a/modules/openxr/extensions/openxr_palm_pose_extension.cpp b/modules/openxr/extensions/openxr_palm_pose_extension.cpp index 8f87aaea7f..493c14ca6f 100644 --- a/modules/openxr/extensions/openxr_palm_pose_extension.cpp +++ b/modules/openxr/extensions/openxr_palm_pose_extension.cpp @@ -37,17 +37,22 @@ OpenXRPalmPoseExtension *OpenXRPalmPoseExtension::get_singleton() { return singleton; } -OpenXRPalmPoseExtension::OpenXRPalmPoseExtension(OpenXRAPI *p_openxr_api) : - OpenXRExtensionWrapper(p_openxr_api) { +OpenXRPalmPoseExtension::OpenXRPalmPoseExtension() { singleton = this; - - request_extensions[XR_EXT_PALM_POSE_EXTENSION_NAME] = &available; } OpenXRPalmPoseExtension::~OpenXRPalmPoseExtension() { singleton = nullptr; } +HashMap<String, bool *> OpenXRPalmPoseExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_EXT_PALM_POSE_EXTENSION_NAME] = &available; + + return request_extensions; +} + bool OpenXRPalmPoseExtension::is_available() { return available; } diff --git a/modules/openxr/extensions/openxr_palm_pose_extension.h b/modules/openxr/extensions/openxr_palm_pose_extension.h index a63c57eb51..9d5daa59e4 100644 --- a/modules/openxr/extensions/openxr_palm_pose_extension.h +++ b/modules/openxr/extensions/openxr_palm_pose_extension.h @@ -37,9 +37,11 @@ class OpenXRPalmPoseExtension : public OpenXRExtensionWrapper { public: static OpenXRPalmPoseExtension *get_singleton(); - OpenXRPalmPoseExtension(OpenXRAPI *p_openxr_api); + OpenXRPalmPoseExtension(); virtual ~OpenXRPalmPoseExtension() override; + virtual HashMap<String, bool *> get_requested_extensions() override; + bool is_available(); private: diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp index ee5bda2881..e00c3bcdda 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp @@ -37,21 +37,24 @@ #include "servers/rendering/rendering_server_globals.h" #include "servers/rendering_server.h" -OpenXRVulkanExtension::OpenXRVulkanExtension(OpenXRAPI *p_openxr_api) : - OpenXRGraphicsExtensionWrapper(p_openxr_api) { +OpenXRVulkanExtension::OpenXRVulkanExtension() { VulkanContext::set_vulkan_hooks(this); - - request_extensions[XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME] = nullptr; // must be available - - ERR_FAIL_NULL(openxr_api); } OpenXRVulkanExtension::~OpenXRVulkanExtension() { VulkanContext::set_vulkan_hooks(nullptr); } +HashMap<String, bool *> OpenXRVulkanExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME] = nullptr; // must be available + + return request_extensions; +} + void OpenXRVulkanExtension::on_instance_created(const XrInstance p_instance) { - ERR_FAIL_NULL(openxr_api); + ERR_FAIL_NULL(OpenXRAPI::get_singleton()); // Obtain pointers to functions we're accessing here, they are (not yet) part of core. @@ -63,7 +66,7 @@ void OpenXRVulkanExtension::on_instance_created(const XrInstance p_instance) { } bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_version) { - ERR_FAIL_NULL_V(openxr_api, false); + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false); XrGraphicsRequirementsVulkan2KHR vulkan_requirements = { XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR, // type @@ -72,9 +75,9 @@ bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_versi 0 // maxApiVersionSupported }; - XrResult result = xrGetVulkanGraphicsRequirements2KHR(openxr_api->get_instance(), openxr_api->get_system_id(), &vulkan_requirements); + XrResult result = xrGetVulkanGraphicsRequirements2KHR(OpenXRAPI::get_singleton()->get_instance(), OpenXRAPI::get_singleton()->get_system_id(), &vulkan_requirements); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to get vulkan graphics requirements [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to get vulkan graphics requirements [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); return false; } @@ -118,7 +121,7 @@ bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p XrVulkanInstanceCreateInfoKHR xr_vulkan_instance_info = { XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, // type nullptr, // next - openxr_api->get_system_id(), // systemId + OpenXRAPI::get_singleton()->get_system_id(), // systemId 0, // createFlags vkGetInstanceProcAddr, // pfnGetInstanceProcAddr p_vulkan_create_info, // vulkanCreateInfo @@ -126,9 +129,9 @@ bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p }; VkResult vk_result = VK_SUCCESS; - XrResult result = xrCreateVulkanInstanceKHR(openxr_api->get_instance(), &xr_vulkan_instance_info, &vulkan_instance, &vk_result); + XrResult result = xrCreateVulkanInstanceKHR(OpenXRAPI::get_singleton()->get_instance(), &xr_vulkan_instance_info, &vulkan_instance, &vk_result); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to create vulkan instance [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to create vulkan instance [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); return false; } @@ -151,18 +154,18 @@ bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p } bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) { - ERR_FAIL_NULL_V(openxr_api, false); + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false); XrVulkanGraphicsDeviceGetInfoKHR get_info = { XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, // type nullptr, // next - openxr_api->get_system_id(), // systemId + OpenXRAPI::get_singleton()->get_system_id(), // systemId vulkan_instance, // vulkanInstance }; - XrResult result = xrGetVulkanGraphicsDevice2KHR(openxr_api->get_instance(), &get_info, &vulkan_physical_device); + XrResult result = xrGetVulkanGraphicsDevice2KHR(OpenXRAPI::get_singleton()->get_instance(), &get_info, &vulkan_physical_device); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to obtain vulkan physical device [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to obtain vulkan physical device [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); return false; } @@ -172,7 +175,7 @@ bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) { } bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) { - ERR_FAIL_NULL_V(openxr_api, false); + ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false); // the first entry in our queue list should be the one we need to remember... vulkan_queue_family_index = p_device_create_info->pQueueCreateInfos[0].queueFamilyIndex; @@ -181,7 +184,7 @@ bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_dev XrVulkanDeviceCreateInfoKHR create_info = { XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, // type nullptr, // next - openxr_api->get_system_id(), // systemId + OpenXRAPI::get_singleton()->get_system_id(), // systemId 0, // createFlags vkGetInstanceProcAddr, // pfnGetInstanceProcAddr vulkan_physical_device, // vulkanPhysicalDevice @@ -190,9 +193,9 @@ bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_dev }; VkResult vk_result = VK_SUCCESS; - XrResult result = xrCreateVulkanDeviceKHR(openxr_api->get_instance(), &create_info, &vulkan_device, &vk_result); + XrResult result = xrCreateVulkanDeviceKHR(OpenXRAPI::get_singleton()->get_instance(), &create_info, &vulkan_device, &vk_result); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to create vulkan device [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to create vulkan device [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); return false; } @@ -245,7 +248,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in uint32_t swapchain_length; XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to get swapchaim image count [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to get swapchaim image count [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); return false; } @@ -260,7 +263,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images); if (XR_FAILED(result)) { - print_line("OpenXR: Failed to get swapchaim images [", openxr_api->get_error_string(result), "]"); + print_line("OpenXR: Failed to get swapchaim images [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); memfree(images); return false; } diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h index 71abe3b166..b9d77d758d 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.h +++ b/modules/openxr/extensions/openxr_vulkan_extension.h @@ -58,9 +58,11 @@ class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks { public: - OpenXRVulkanExtension(OpenXRAPI *p_openxr_api); + OpenXRVulkanExtension(); virtual ~OpenXRVulkanExtension() override; + virtual HashMap<String, bool *> get_requested_extensions() override; + virtual void on_instance_created(const XrInstance p_instance) override; virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override; diff --git a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp new file mode 100644 index 0000000000..4dab90db2f --- /dev/null +++ b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp @@ -0,0 +1,119 @@ +/*************************************************************************/ +/* openxr_wmr_controller_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "openxr_wmr_controller_extension.h" +#include "../action_map/openxr_interaction_profile_meta_data.h" + +HashMap<String, bool *> OpenXRWMRControllerExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + // Note HP G2 is available on WMR and SteamVR, but Odessey is only available on WMR + request_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &available[WMR_HPMR]; + request_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &available[WMR_SAMSUNG_ODESSY]; + + return request_extensions; +} + +bool OpenXRWMRControllerExtension::is_available(WMRControllers p_type) { + return available[p_type]; +} + +void OpenXRWMRControllerExtension::on_register_metadata() { + OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + ERR_FAIL_NULL(metadata); + + // HP MR controller (newer G2 controllers) + metadata->register_interaction_profile("HPMR controller", "/interaction_profiles/hp/mixed_reality_controller", XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + + // Samsung Odyssey controller + metadata->register_interaction_profile("Samsung Odyssey controller", "/interaction_profiles/samsung/odyssey_controller", XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); +} diff --git a/modules/openxr/extensions/openxr_wmr_controller_extension.h b/modules/openxr/extensions/openxr_wmr_controller_extension.h new file mode 100644 index 0000000000..d71fab4bc5 --- /dev/null +++ b/modules/openxr/extensions/openxr_wmr_controller_extension.h @@ -0,0 +1,54 @@ +/*************************************************************************/ +/* openxr_wmr_controller_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPENXR_WMR_CONTROLLER_EXTENSION_H +#define OPENXR_WMR_CONTROLLER_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +class OpenXRWMRControllerExtension : public OpenXRExtensionWrapper { +public: + enum WMRControllers { + WMR_HPMR, + WMR_SAMSUNG_ODESSY, + WMR_MAX_CONTROLLERS + }; + + virtual HashMap<String, bool *> get_requested_extensions() override; + + bool is_available(WMRControllers p_type); + + virtual void on_register_metadata() override; + +private: + bool available[WMR_MAX_CONTROLLERS] = { false, false }; +}; + +#endif // OPENXR_WMR_CONTROLLER_EXTENSION_H diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index a075031ac9..8184edc30b 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -42,7 +42,6 @@ #ifdef ANDROID_ENABLED #define OPENXR_LOADER_NAME "libopenxr_loader.so" -#include "extensions/openxr_android_extension.h" #endif // We need to have all the graphics API defines before the Vulkan or OpenGL @@ -81,13 +80,11 @@ #include "extensions/openxr_composition_layer_depth_extension.h" #include "extensions/openxr_fb_display_refresh_rate_extension.h" #include "extensions/openxr_fb_passthrough_extension_wrapper.h" -#include "extensions/openxr_hand_tracking_extension.h" -#include "extensions/openxr_htc_vive_tracker_extension.h" -#include "extensions/openxr_palm_pose_extension.h" #include "modules/openxr/openxr_interface.h" OpenXRAPI *OpenXRAPI::singleton = nullptr; +Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers; bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) { // @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled" @@ -104,10 +101,6 @@ bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) { } } -OpenXRAPI *OpenXRAPI::get_singleton() { - return singleton; -} - String OpenXRAPI::get_default_action_map_resource_name() { String name = GLOBAL_GET("xr/openxr/default_action_map"); @@ -303,7 +296,7 @@ bool OpenXRAPI::create_instance() { // Append the extensions requested by the registered extension wrappers. HashMap<String, bool *> requested_extensions; for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { - const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_request_extensions(); + const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_requested_extensions(); // requested_extensions.insert(wrapper_request_extensions.begin(), wrapper_request_extensions.end()); for (auto &requested_extension : wrapper_request_extensions) { @@ -311,14 +304,6 @@ bool OpenXRAPI::create_instance() { } } - // Add optional extensions for controllers that may be supported. - // Overkill to create extension classes for this. - requested_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &ext_hp_mixed_reality_available; - requested_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &ext_samsung_odyssey_available; - requested_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_cosmos_available; - requested_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_focus3_available; - requested_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_huawei_controller_available; - // Check which extensions are supported enabled_extensions.clear(); @@ -1259,7 +1244,7 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { if (p_rendering_driver == "vulkan") { #ifdef VULKAN_ENABLED - graphics_extension = memnew(OpenXRVulkanExtension(this)); + graphics_extension = memnew(OpenXRVulkanExtension); register_extension_wrapper(graphics_extension); #else // shouldn't be possible... @@ -1267,7 +1252,7 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { #endif } else if (p_rendering_driver == "opengl3") { #ifdef GLES3_ENABLED - graphics_extension = memnew(OpenXROpenGLExtension(this)); + graphics_extension = memnew(OpenXROpenGLExtension); register_extension_wrapper(graphics_extension); #else // shouldn't be possible... @@ -1358,6 +1343,19 @@ void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_w registered_extension_wrappers.push_back(p_extension_wrapper); } +void OpenXRAPI::register_extension_metadata() { + for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { + extension_wrapper->on_register_metadata(); + } +} + +void OpenXRAPI::cleanup_extension_wrappers() { + for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { + memdelete(extension_wrapper); + } + registered_extension_wrappers.clear(); +} + Size2 OpenXRAPI::get_recommended_target_size() { ERR_FAIL_NULL_V(view_configuration_views, Size2()); @@ -1957,19 +1955,6 @@ OpenXRAPI::OpenXRAPI() { // reset a few things that can't be done in our class definition frame_state.predictedDisplayTime = 0; frame_state.predictedDisplayPeriod = 0; - -#ifdef ANDROID_ENABLED - // our android wrapper will initialize our android loader at this point - register_extension_wrapper(memnew(OpenXRAndroidExtension(this))); -#endif - - // register our other extensions - register_extension_wrapper(memnew(OpenXRPalmPoseExtension(this))); - register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension(this))); - register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this))); - register_extension_wrapper(memnew(OpenXRHandTrackingExtension(this))); - register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper(this))); - register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension(this))); } OpenXRAPI::~OpenXRAPI() { @@ -1979,12 +1964,6 @@ OpenXRAPI::~OpenXRAPI() { } composition_layer_providers.clear(); - // cleanup our extension wrappers - for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { - memdelete(extension_wrapper); - } - registered_extension_wrappers.clear(); - if (supported_extensions != nullptr) { memfree(supported_extensions); supported_extensions = nullptr; diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 806e859da0..46082c5e56 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -65,6 +65,9 @@ private: // our singleton static OpenXRAPI *singleton; + // Registered extension wrappers + static Vector<OpenXRExtensionWrapper *> registered_extension_wrappers; + // linked XR interface OpenXRInterface *xr_interface = nullptr; @@ -75,15 +78,8 @@ private: // extensions uint32_t num_supported_extensions = 0; XrExtensionProperties *supported_extensions = nullptr; - Vector<OpenXRExtensionWrapper *> registered_extension_wrappers; Vector<CharString> enabled_extensions; - bool ext_hp_mixed_reality_available = false; - bool ext_samsung_odyssey_available = false; - bool ext_vive_cosmos_available = false; - bool ext_vive_focus3_available = false; - bool ext_huawei_controller_available = false; - // composition layer providers Vector<OpenXRCompositionLayerProvider *> composition_layer_providers; @@ -307,14 +303,16 @@ public: bool interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path); static bool openxr_is_enabled(bool p_check_run_in_editor = true); - static OpenXRAPI *get_singleton(); + _FORCE_INLINE_ static OpenXRAPI *get_singleton() { return singleton; } XrResult get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr); String get_error_string(XrResult result); String get_swapchain_format_name(int64_t p_swapchain_format) const; void set_xr_interface(OpenXRInterface *p_xr_interface); - void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper); + static void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper); + static void register_extension_metadata(); + static void cleanup_extension_wrappers(); void set_form_factor(XrFormFactor p_form_factor); XrFormFactor get_form_factor() const { return form_factor; } diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index 0835bbd642..f026487ef8 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -41,6 +41,20 @@ #include "scene/openxr_hand.h" +#ifdef ANDROID_ENABLED +#include "extensions/openxr_android_extension.h" +#endif + +#include "extensions/openxr_composition_layer_depth_extension.h" +#include "extensions/openxr_fb_display_refresh_rate_extension.h" +#include "extensions/openxr_fb_passthrough_extension_wrapper.h" +#include "extensions/openxr_hand_tracking_extension.h" +#include "extensions/openxr_htc_controller_extension.h" +#include "extensions/openxr_htc_vive_tracker_extension.h" +#include "extensions/openxr_huawei_controller_extension.h" +#include "extensions/openxr_palm_pose_extension.h" +#include "extensions/openxr_wmr_controller_extension.h" + static OpenXRAPI *openxr_api = nullptr; static OpenXRInteractionProfileMetaData *openxr_interaction_profile_meta_data = nullptr; static Ref<OpenXRInterface> openxr_interface; @@ -69,7 +83,24 @@ static void _editor_init() { void initialize_openxr_module(ModuleInitializationLevel p_level) { if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { - // For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon. + if (OpenXRAPI::openxr_is_enabled(false)) { + // Always register our extension wrappers even if we don't initialise OpenXR. + // Some of these wrappers will add functionality to our editor. +#ifdef ANDROID_ENABLED + OpenXRAPI::register_extension_wrapper(memnew(OpenXRAndroidExtension)); +#endif + + // register our other extensions + OpenXRAPI::register_extension_wrapper(memnew(OpenXRPalmPoseExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCControllerExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRHuaweiControllerExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRHandTrackingExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRWMRControllerExtension)); + } if (OpenXRAPI::openxr_is_enabled()) { openxr_interaction_profile_meta_data = memnew(OpenXRInteractionProfileMetaData); @@ -139,6 +170,7 @@ void uninitialize_openxr_module(ModuleInitializationLevel p_level) { if (openxr_api) { openxr_api->finish(); + memdelete(openxr_api); openxr_api = nullptr; } @@ -147,4 +179,7 @@ void uninitialize_openxr_module(ModuleInitializationLevel p_level) { memdelete(openxr_interaction_profile_meta_data); openxr_interaction_profile_meta_data = nullptr; } + + // cleanup our extension wrappers + OpenXRAPI::cleanup_extension_wrappers(); } diff --git a/modules/openxr/util.h b/modules/openxr/util.h index 1b5e0451dc..e6d5bc73b6 100644 --- a/modules/openxr/util.h +++ b/modules/openxr/util.h @@ -40,7 +40,7 @@ ERR_FAIL_COND_V(XR_FAILED(get_instance_proc_addr_result), false); \ } while (0) -#define EXT_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(openxr_api, name) +#define EXT_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(OpenXRAPI::get_singleton(), name) #define OPENXR_API_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(this, name) #define INIT_XR_FUNC(openxr_api, name) \ @@ -50,7 +50,7 @@ ERR_FAIL_COND(XR_FAILED(get_instance_proc_addr_result)); \ } while (0) -#define EXT_INIT_XR_FUNC(name) INIT_XR_FUNC(openxr_api, name) +#define EXT_INIT_XR_FUNC(name) INIT_XR_FUNC(OpenXRAPI::get_singleton(), name) #define OPENXR_API_INIT_XR_FUNC(name) INIT_XR_FUNC(this, name) #define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \ diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index f3e7ae9b83..1c744afec0 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -385,11 +385,17 @@ void TextServerAdvanced::_free_rid(const RID &p_rid) { _THREAD_SAFE_METHOD_ if (font_owner.owns(p_rid)) { FontAdvanced *fd = font_owner.get_or_null(p_rid); - font_owner.free(p_rid); + { + MutexLock lock(fd->mutex); + font_owner.free(p_rid); + } memdelete(fd); } else if (shaped_owner.owns(p_rid)) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid); - shaped_owner.free(p_rid); + { + MutexLock lock(sd->mutex); + shaped_owner.free(p_rid); + } memdelete(sd); } } diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index ea7b7a271b..9fd8c8fb37 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -115,11 +115,17 @@ void TextServerFallback::_free_rid(const RID &p_rid) { _THREAD_SAFE_METHOD_ if (font_owner.owns(p_rid)) { FontFallback *fd = font_owner.get_or_null(p_rid); - font_owner.free(p_rid); + { + MutexLock lock(fd->mutex); + font_owner.free(p_rid); + } memdelete(fd); } else if (shaped_owner.owns(p_rid)) { ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_rid); - shaped_owner.free(p_rid); + { + MutexLock lock(sd->mutex); + shaped_owner.free(p_rid); + } memdelete(sd); } } diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 77cfa99aee..41d2579ac0 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -873,7 +873,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p int hand_tracking_frequency_index = p_preset->get("xr_features/hand_tracking_frequency"); bool backup_allowed = p_preset->get("user_data_backup/allow"); - bool classify_as_game = p_preset->get("package/classify_as_game"); + int app_category = p_preset->get("package/app_category"); bool retain_data_on_uninstall = p_preset->get("package/retain_data_on_uninstall"); bool exclude_from_recents = p_preset->get("package/exclude_from_recents"); bool is_resizeable = bool(GLOBAL_GET("display/window/size/resizable")); @@ -972,8 +972,12 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p encode_uint32(backup_allowed, &p_manifest.write[iofs + 16]); } + if (tname == "application" && attrname == "appCategory") { + encode_uint32(_get_app_category_value(app_category), &p_manifest.write[iofs + 16]); + } + if (tname == "application" && attrname == "isGame") { - encode_uint32(classify_as_game, &p_manifest.write[iofs + 16]); + encode_uint32(app_category == APP_CATEGORY_GAME, &p_manifest.write[iofs + 16]); } if (tname == "application" && attrname == "hasFragileUserData") { @@ -1731,7 +1735,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/classify_as_game"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "package/app_category", PROPERTY_HINT_ENUM, "Accessibility,Audio,Game,Image,Maps,News,Productivity,Social,Video"), APP_CATEGORY_GAME)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/retain_data_on_uninstall"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/exclude_from_recents"), false)); diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 8d016d3fac..1cbed4b3bb 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -72,6 +72,54 @@ String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_or } } +int _get_app_category_value(int category_index) { + switch (category_index) { + case APP_CATEGORY_ACCESSIBILITY: + return 8; + case APP_CATEGORY_AUDIO: + return 1; + case APP_CATEGORY_IMAGE: + return 3; + case APP_CATEGORY_MAPS: + return 6; + case APP_CATEGORY_NEWS: + return 5; + case APP_CATEGORY_PRODUCTIVITY: + return 7; + case APP_CATEGORY_SOCIAL: + return 4; + case APP_CATEGORY_VIDEO: + return 2; + case APP_CATEGORY_GAME: + default: + return 0; + } +} + +String _get_app_category_label(int category_index) { + switch (category_index) { + case APP_CATEGORY_ACCESSIBILITY: + return "accessibility"; + case APP_CATEGORY_AUDIO: + return "audio"; + case APP_CATEGORY_IMAGE: + return "image"; + case APP_CATEGORY_MAPS: + return "maps"; + case APP_CATEGORY_NEWS: + return "news"; + case APP_CATEGORY_PRODUCTIVITY: + return "productivity"; + case APP_CATEGORY_SOCIAL: + return "social"; + case APP_CATEGORY_VIDEO: + return "video"; + case APP_CATEGORY_GAME: + default: + return "game"; + } +} + // Utility method used to create a directory. Error create_directory(const String &p_dir) { if (!DirAccess::exists(p_dir)) { @@ -253,21 +301,27 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { } String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission) { + int app_category_index = (int)(p_preset->get("package/app_category")); + bool is_game = app_category_index == APP_CATEGORY_GAME; + int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); bool uses_xr = xr_mode_index == XR_MODE_OPENXR; + String manifest_application_text = vformat( " <application android:label=\"@string/godot_project_name_string\"\n" " android:allowBackup=\"%s\"\n" " android:icon=\"@mipmap/icon\"\n" + " android:appCategory=\"%s\"\n" " android:isGame=\"%s\"\n" " android:hasFragileUserData=\"%s\"\n" " android:requestLegacyExternalStorage=\"%s\"\n" - " tools:replace=\"android:allowBackup,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n" + " tools:replace=\"android:allowBackup,android:appCategory,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n" " tools:ignore=\"GoogleAppIndexingWarning\">\n\n" " <meta-data tools:node=\"remove\" android:name=\"xr_hand_tracking_version_name\" />\n" " <meta-data tools:node=\"remove\" android:name=\"xr_hand_tracking_metadata_name\" />\n", bool_to_string(p_preset->get("user_data_backup/allow")), - bool_to_string(p_preset->get("package/classify_as_game")), + _get_app_category_label(app_category_index), + bool_to_string(is_game), bool_to_string(p_preset->get("package/retain_data_on_uninstall")), bool_to_string(p_has_read_write_storage_permission)); diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 232b4458c6..9c9c5923f7 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -44,6 +44,18 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut </resources> )"; +// Application category. +// See https://developer.android.com/guide/topics/manifest/application-element#appCategory for standards +static const int APP_CATEGORY_ACCESSIBILITY = 0; +static const int APP_CATEGORY_AUDIO = 1; +static const int APP_CATEGORY_GAME = 2; +static const int APP_CATEGORY_IMAGE = 3; +static const int APP_CATEGORY_MAPS = 4; +static const int APP_CATEGORY_NEWS = 5; +static const int APP_CATEGORY_PRODUCTIVITY = 6; +static const int APP_CATEGORY_SOCIAL = 7; +static const int APP_CATEGORY_VIDEO = 8; + // Supported XR modes. // This should match the entries in 'platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java' static const int XR_MODE_REGULAR = 0; @@ -73,6 +85,10 @@ int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orien String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation); +int _get_app_category_value(int category_index); + +String _get_app_category_label(int category_index); + // Utility method used to create a directory. Error create_directory(const String &p_dir); diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index 1db135826a..8c8608cbbb 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -20,6 +20,7 @@ android:label="@string/godot_project_name_string" android:allowBackup="false" android:icon="@mipmap/icon" + android:appCategory="game" android:isGame="true" android:hasFragileUserData="false" android:requestLegacyExternalStorage="false" diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h index 0ca0d3d1fe..82351a536b 100644 --- a/platform/ios/display_server_ios.h +++ b/platform/ios/display_server_ios.h @@ -105,10 +105,10 @@ public: // MARK: - Input - // MARK: Touches + // MARK: Touches and Apple Pencil void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click); - void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y); + void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt); void touches_cancelled(int p_idx); // MARK: Keyboard diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index ce78b8d20f..789364494d 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -237,10 +237,12 @@ void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, perform_event(ev); } -void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { +void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt) { Ref<InputEventScreenDrag> ev; ev.instantiate(); ev->set_index(p_idx); + ev->set_pressure(p_pressure); + ev->set_tilt(p_tilt); ev->set_position(Vector2(p_x, p_y)); ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y)); perform_event(ev); diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm index 19cb914521..5aff75ea04 100644 --- a/platform/ios/godot_view.mm +++ b/platform/ios/godot_view.mm @@ -363,7 +363,9 @@ static const float earth_gravity = 9.80665; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; CGPoint prev_point = [touch previousLocationInView:self]; - DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor); + CGFloat alt = [touch altitudeAngle]; + CGVector azim = [touch azimuthUnitVectorInView:self]; + DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, [touch force] / [touch maximumPossibleForce], Vector2(azim.dx, azim.dy) * Math::cos(alt)); } } } diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 844b15e9fb..747dcbd76c 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -339,9 +339,6 @@ def configure(env: "Environment"): env.Prepend(CPPPATH=["#platform/linuxbsd"]) if env["x11"]: - if not env["vulkan"]: - print("Error: X11 support requires vulkan=yes") - env.Exit(255) env.Append(CPPDEFINES=["X11_ENABLED"]) env.Append(CPPDEFINES=["UNIX_ENABLED"]) diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 57f125a754..c44c3635cf 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -1235,10 +1235,10 @@ Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const { return ret; } -DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { _THREAD_SAFE_METHOD_ - WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect); + WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_screen); for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, id); @@ -1257,6 +1257,8 @@ void DisplayServerX11::show_window(WindowID p_id) { DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id); XMapWindow(x11_display, wd.x11_window); + XSync(x11_display, False); + _validate_mode_on_map(p_id); } void DisplayServerX11::delete_sub_window(WindowID p_id) { @@ -1505,16 +1507,24 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window // Check if screen is valid ERR_FAIL_INDEX(p_screen, get_screen_count()); + if (window_get_current_screen(p_window) == p_screen) { + return; + } + if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN) { Point2i position = screen_get_position(p_screen); Size2i size = screen_get_size(p_screen); XMoveResizeWindow(x11_display, wd.x11_window, position.x, position.y, size.x, size.y); } else { - if (p_screen != window_get_current_screen(p_window)) { - Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); - window_set_position(ofs + screen_get_position(p_screen), p_window); - } + Rect2i srect = screen_get_usable_rect(p_screen); + Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); + Size2i wsize = window_get_size(p_window); + wpos += srect.position; + + wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3); + wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3); + window_set_position(wpos, p_window); } } @@ -4531,7 +4541,7 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W return ds; } -DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { //Create window XVisualInfo visualInfo; @@ -4607,8 +4617,38 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V valuemask |= CWOverrideRedirect | CWSaveUnder; } + Rect2i win_rect = p_rect; + if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { + Rect2i screen_rect = Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); + + win_rect = screen_rect; + } else { + int nearest_area = 0; + int pos_screen = -1; + for (int i = 0; i < get_screen_count(); i++) { + Rect2i r; + r.position = screen_get_position(i); + r.size = screen_get_size(i); + Rect2 inters = r.intersection(p_rect); + + int area = inters.size.width * inters.size.height; + if (area > nearest_area) { + pos_screen = i; + nearest_area = area; + } + } + + Rect2i srect = screen_get_usable_rect(p_screen); + Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i()); + wpos += srect.position; + wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3); + wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3); + + win_rect.position = wpos; + } + { - wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes); + wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), win_rect.position.x, win_rect.position.y, win_rect.size.width > 0 ? win_rect.size.width : 1, win_rect.size.height > 0 ? win_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes); // Enable receiving notification when the window is initialized (MapNotify) // so the focus can be set at the right time. @@ -4729,13 +4769,13 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V #if defined(VULKAN_ENABLED) if (context_vulkan) { - Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height); + Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, win_rect.size.width, win_rect.size.height); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window"); } #endif #ifdef GLES3_ENABLED if (gl_manager) { - Error err = gl_manager->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height); + Error err = gl_manager->window_create(id, wd.x11_window, x11_display, win_rect.size.width, win_rect.size.height); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window"); window_set_vsync_mode(p_vsync_mode, id); } @@ -5038,12 +5078,13 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode Point2i window_position( (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); + window_position += screen_get_position(0); if (p_position != nullptr) { window_position = *p_position; } - WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution)); + WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), 0); if (main_window == INVALID_WINDOW_ID) { r_error = ERR_CANT_CREATE; return; @@ -5054,8 +5095,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } } show_window(main_window); - XSync(x11_display, False); - _validate_mode_on_map(main_window); #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index 2578ca06fd..d8d914bffc 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -185,7 +185,7 @@ class DisplayServerX11 : public DisplayServer { WindowID last_focused_window = INVALID_WINDOW_ID; WindowID window_id_counter = MAIN_WINDOW_ID; - WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect); + WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen); String internal_clipboard; String internal_clipboard_primary; @@ -365,7 +365,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override; virtual void show_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override; diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index bd26f6e417..4a2d6032b9 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -99,6 +99,8 @@ public: Callable drop_files_callback; ObjectID instance_id; + bool fs_transition = false; + bool initial_size = true; WindowID transient_parent = INVALID_WINDOW_ID; bool exclusive = false; @@ -189,7 +191,7 @@ private: const NSMenu *_get_menu_root(const String &p_menu_root) const; NSMenu *_get_menu_root(const String &p_menu_root); - WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect); + WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect, int p_screen); void _update_window_style(WindowData p_wd); void _set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window); @@ -334,7 +336,7 @@ public: virtual Vector<int> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override; virtual void show_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 5c979dbf22..5421739971 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -109,7 +109,7 @@ NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) { return menu; } -DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) { +DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect, int p_screen) { WindowID id; const float scale = screen_get_max_scale(); { @@ -119,19 +119,36 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod ERR_FAIL_COND_V_MSG(wd.window_delegate == nil, INVALID_WINDOW_ID, "Can't create a window delegate"); [wd.window_delegate setWindowID:window_id_counter]; - Point2i position = p_rect.position; + int nearest_area = 0; + int pos_screen = -1; + for (int i = 0; i < get_screen_count(); i++) { + Rect2i r = screen_get_usable_rect(i); + Rect2 inters = r.intersection(p_rect); + int area = inters.size.width * inters.size.height; + if (area > nearest_area && area > 0) { + pos_screen = i; + nearest_area = area; + } + } + + Rect2i srect = screen_get_usable_rect(p_screen); + Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i()); + wpos += srect.position; + wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3); + wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3); // OS X native y-coordinate relative to _get_screens_origin() is negative, // Godot passes a positive value. - position.y *= -1; - position += _get_screens_origin(); + wpos.y *= -1; + wpos += _get_screens_origin(); // initWithContentRect uses bottom-left corner of the window’s frame as origin. wd.window_object = [[GodotWindow alloc] - initWithContentRect:NSMakeRect(position.x / scale, (position.y - p_rect.size.height) / scale, p_rect.size.width / scale, p_rect.size.height / scale) + initWithContentRect:NSMakeRect(0, 0, p_rect.size.width / scale, p_rect.size.height / scale) styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO]; ERR_FAIL_COND_V_MSG(wd.window_object == nil, INVALID_WINDOW_ID, "Can't create a window"); + [wd.window_object setFrameTopLeftPoint:NSMakePoint(wpos.x / scale, wpos.y / scale)]; [wd.window_object setWindowID:window_id_counter]; wd.window_view = [[GodotContentView alloc] init]; @@ -2208,10 +2225,10 @@ Vector<DisplayServer::WindowID> DisplayServerMacOS::get_window_list() const { return ret; } -DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { _THREAD_SAFE_METHOD_ - WindowID id = _create_window(p_mode, p_vsync_mode, p_rect); + WindowID id = _create_window(p_mode, p_vsync_mode, p_rect, p_screen); for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, id); @@ -2328,8 +2345,14 @@ void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_wind was_fullscreen = true; } + Rect2i srect = screen_get_usable_rect(p_screen); Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); - window_set_position(wpos + screen_get_position(p_screen), p_window); + Size2i wsize = window_get_size(p_window); + wpos += srect.position; + + wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3); + wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3); + window_set_position(wpos, p_window); if (was_fullscreen) { // Re-enter fullscreen mode. @@ -3781,7 +3804,7 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM window_position = *p_position; } - WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution)); + WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution), 0); ERR_FAIL_COND(main_window == INVALID_WINDOW_ID); for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm index cb70a5db86..27afa60bed 100644 --- a/platform/macos/godot_content_view.mm +++ b/platform/macos/godot_content_view.mm @@ -65,16 +65,28 @@ if (ds && ds->has_window(window_id)) { DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); NSRect frameRect = [wd.window_object frame]; - bool left = (wd.last_frame_rect.origin.x != frameRect.origin.x); - bool top = (wd.last_frame_rect.origin.y == frameRect.origin.y); - if (left && top) { - self.layerContentsPlacement = NSViewLayerContentsPlacementBottomRight; - } else if (left && !top) { - self.layerContentsPlacement = NSViewLayerContentsPlacementTopRight; - } else if (!left && top) { - self.layerContentsPlacement = NSViewLayerContentsPlacementBottomLeft; + if (wd.fs_transition || wd.initial_size) { + self.layerContentsPlacement = NSViewLayerContentsPlacementScaleAxesIndependently; + wd.initial_size = false; } else { - self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft; + bool left = (wd.last_frame_rect.origin.x != frameRect.origin.x); + bool bottom = (wd.last_frame_rect.origin.y != frameRect.origin.y); + bool right = (wd.last_frame_rect.origin.x + wd.last_frame_rect.size.width != frameRect.origin.x + frameRect.size.width); + bool top = (wd.last_frame_rect.origin.y + wd.last_frame_rect.size.height != frameRect.origin.y + frameRect.size.height); + + if (left && top) { + self.layerContentsPlacement = NSViewLayerContentsPlacementBottomRight; + } else if (left && bottom) { + self.layerContentsPlacement = NSViewLayerContentsPlacementTopRight; + } else if (left) { + self.layerContentsPlacement = NSViewLayerContentsPlacementRight; + } else if (right && top) { + self.layerContentsPlacement = NSViewLayerContentsPlacementBottomLeft; + } else if (right && bottom) { + self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft; + } else if (right) { + self.layerContentsPlacement = NSViewLayerContentsPlacementLeft; + } } wd.last_frame_rect = frameRect; } @@ -440,7 +452,7 @@ NSEventSubtype subtype = [event subtype]; if (subtype == NSEventSubtypeTabletPoint) { const NSPoint p = [event tilt]; - mm->set_tilt(Vector2(p.x, p.y)); + mm->set_tilt(Vector2(p.x, -p.y)); mm->set_pen_inverted(last_pen_inverted); } else if (subtype == NSEventSubtypeTabletProximity) { // Check if using the eraser end of pen only on proximity event. diff --git a/platform/macos/godot_window_delegate.h b/platform/macos/godot_window_delegate.h index 01cc13a016..98c226aa2f 100644 --- a/platform/macos/godot_window_delegate.h +++ b/platform/macos/godot_window_delegate.h @@ -38,8 +38,6 @@ @interface GodotWindowDelegate : NSObject <NSWindowDelegate> { DisplayServer::WindowID window_id; - NSRect old_frame; - NSWindowStyleMask old_style_mask; } - (void)setWindowID:(DisplayServer::WindowID)wid; diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm index 27efd3ebb2..aa5da14651 100644 --- a/platform/macos/godot_window_delegate.mm +++ b/platform/macos/godot_window_delegate.mm @@ -70,24 +70,24 @@ ds->window_destroy(window_id); } -- (NSArray<NSWindow *> *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window { +- (void)windowWillEnterFullScreen:(NSNotification *)notification { DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { - return nullptr; + return; } - old_frame = [window frame]; - old_style_mask = [window styleMask]; - - NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init]; - [windows addObject:window]; - - return windows; + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + wd.fs_transition = true; } -- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration { - [(GodotWindow *)window setAnimDuration:duration]; - [window setFrame:[[window screen] frame] display:YES animate:YES]; +- (void)windowDidFailToEnterFullScreen:(NSWindow *)window { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (!ds || !ds->has_window(window_id)) { + return; + } + + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + wd.fs_transition = false; } - (void)windowDidEnterFullScreen:(NSNotification *)notification { @@ -98,29 +98,31 @@ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); wd.fullscreen = true; + wd.fs_transition = false; // Reset window size limits. [wd.window_object setContentMinSize:NSMakeSize(0, 0)]; [wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; - [(GodotWindow *)wd.window_object setAnimDuration:-1.0f]; // Reset custom window buttons. if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) { ds->window_set_custom_window_buttons(wd, false); } - // Force window resize event. - [self windowDidResize:notification]; ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE); + + // Force window resize event and redraw. + [self windowDidResize:notification]; } -- (NSArray<NSWindow *> *)customWindowsToExitFullScreenForWindow:(NSWindow *)window { +- (void)windowWillExitFullScreen:(NSNotification *)notification { DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { - return nullptr; + return; } DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + wd.fs_transition = true; // Restore custom window buttons. if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) { @@ -128,16 +130,22 @@ } ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE); - - NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init]; - [windows addObject:wd.window_object]; - return windows; } -- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration { - [(GodotWindow *)window setAnimDuration:duration]; - [window setStyleMask:old_style_mask]; - [window setFrame:old_frame display:YES animate:YES]; +- (void)windowDidFailToExitFullScreen:(NSWindow *)window { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (!ds || !ds->has_window(window_id)) { + return; + } + + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); + wd.fs_transition = false; + + if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) { + ds->window_set_custom_window_buttons(wd, false); + } + + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE); } - (void)windowDidExitFullScreen:(NSNotification *)notification { @@ -153,8 +161,7 @@ wd.fullscreen = false; wd.exclusive_fullscreen = false; - - [(GodotWindow *)wd.window_object setAnimDuration:-1.0f]; + wd.fs_transition = false; // Set window size limits. const float scale = ds->screen_get_max_scale(); @@ -177,7 +184,7 @@ [wd.window_object setLevel:NSFloatingWindowLevel]; } - // Force window resize event. + // Force window resize event and redraw. [self windowDidResize:notification]; } @@ -305,6 +312,8 @@ ds->update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); } + [self windowDidResize:notification]; // Emit resize event, to ensure content is resized if the window was resized while it was hidden. + ds->set_last_focused_window(window_id); ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN); } diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index e7864ebac0..fb996ec1ff 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -625,10 +625,10 @@ DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(cons return INVALID_WINDOW_ID; } -DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { _THREAD_SAFE_METHOD_ - WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect); + WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_screen); ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window."); WindowData &wd = windows[window_id]; @@ -865,19 +865,24 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi ERR_FAIL_COND(!windows.has(p_window)); ERR_FAIL_INDEX(p_screen, get_screen_count()); + if (window_get_current_screen(p_window) == p_screen) { + return; + } const WindowData &wd = windows[p_window]; if (wd.fullscreen) { - int cs = window_get_current_screen(p_window); - if (cs == p_screen) { - return; - } Point2 pos = screen_get_position(p_screen); Size2 size = screen_get_size(p_screen); MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE); } else { - Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); - window_set_position(ofs + screen_get_position(p_screen), p_window); + Rect2i srect = screen_get_usable_rect(p_screen); + Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); + Size2i wsize = window_get_size(p_window); + wpos += srect.position; + + wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3); + wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3); + window_set_position(wpos, p_window); } // Don't let the mouse leave the window when resizing to a smaller resolution. @@ -3534,7 +3539,7 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const } } -DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { DWORD dwExStyle; DWORD dwStyle; @@ -3548,24 +3553,37 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, WindowRect.bottom = p_rect.position.y + p_rect.size.y; if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { + Rect2i screen_rect = Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); + + WindowRect.left = screen_rect.position.x; + WindowRect.right = screen_rect.position.x + screen_rect.size.x; + WindowRect.top = screen_rect.position.y; + WindowRect.bottom = screen_rect.position.y + screen_rect.size.y; + } else { int nearest_area = 0; - Rect2i screen_rect; + int pos_screen = -1; for (int i = 0; i < get_screen_count(); i++) { Rect2i r; r.position = screen_get_position(i); r.size = screen_get_size(i); Rect2 inters = r.intersection(p_rect); int area = inters.size.width * inters.size.height; - if (area >= nearest_area) { - screen_rect = r; + if (area > nearest_area) { + pos_screen = i; nearest_area = area; } } - WindowRect.left = screen_rect.position.x; - WindowRect.right = screen_rect.position.x + screen_rect.size.x; - WindowRect.top = screen_rect.position.y; - WindowRect.bottom = screen_rect.position.y + screen_rect.size.y; + Rect2i srect = screen_get_usable_rect(p_screen); + Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i()); + wpos += srect.position; + wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3); + wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3); + + WindowRect.left = wpos.x; + WindowRect.right = wpos.x + p_rect.size.x; + WindowRect.top = wpos.y; + WindowRect.bottom = wpos.y + p_rect.size.y; } AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); @@ -3709,7 +3727,6 @@ WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr; // UXTheme API. bool DisplayServerWindows::dark_title_available = false; bool DisplayServerWindows::ux_theme_available = false; -IsDarkModeAllowedForAppPtr DisplayServerWindows::IsDarkModeAllowedForApp = nullptr; ShouldAppsUseDarkModePtr DisplayServerWindows::ShouldAppsUseDarkMode = nullptr; GetImmersiveColorFromColorSetExPtr DisplayServerWindows::GetImmersiveColorFromColorSetEx = nullptr; GetImmersiveColorTypeFromNamePtr DisplayServerWindows::GetImmersiveColorTypeFromName = nullptr; @@ -3727,7 +3744,7 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS { } SHC_PROCESS_DPI_AWARENESS; bool DisplayServerWindows::is_dark_mode_supported() const { - return ux_theme_available && IsDarkModeAllowedForApp(); + return ux_theme_available; } bool DisplayServerWindows::is_dark_mode() const { @@ -3817,13 +3834,12 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win // Load UXTheme. HMODULE ux_theme_lib = LoadLibraryW(L"uxtheme.dll"); if (ux_theme_lib) { - IsDarkModeAllowedForApp = (IsDarkModeAllowedForAppPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(136)); ShouldAppsUseDarkMode = (ShouldAppsUseDarkModePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(132)); GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(95)); GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(96)); GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98)); - ux_theme_available = IsDarkModeAllowedForApp && ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference; + ux_theme_available = ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference; if (os_ver.dwBuildNumber >= 22000) { dark_title_available = true; } @@ -3933,7 +3949,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win window_position = *p_position; } - WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution)); + WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution), 0); ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 4702bb7765..fe67febe40 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -152,7 +152,6 @@ typedef UINT(WINAPI *WTInfoPtr)(UINT p_category, UINT p_index, LPVOID p_output); typedef BOOL(WINAPI *WTPacketPtr)(HANDLE p_ctx, UINT p_param, LPVOID p_packets); typedef BOOL(WINAPI *WTEnablePtr)(HANDLE p_ctx, BOOL p_enable); -typedef bool(WINAPI *IsDarkModeAllowedForAppPtr)(); typedef bool(WINAPI *ShouldAppsUseDarkModePtr)(); typedef DWORD(WINAPI *GetImmersiveColorFromColorSetExPtr)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode); typedef int(WINAPI *GetImmersiveColorTypeFromNamePtr)(const WCHAR *name); @@ -288,7 +287,6 @@ class DisplayServerWindows : public DisplayServer { // UXTheme API static bool dark_title_available; static bool ux_theme_available; - static IsDarkModeAllowedForAppPtr IsDarkModeAllowedForApp; static ShouldAppsUseDarkModePtr ShouldAppsUseDarkMode; static GetImmersiveColorFromColorSetExPtr GetImmersiveColorFromColorSetEx; static GetImmersiveColorTypeFromNamePtr GetImmersiveColorTypeFromName; @@ -428,7 +426,7 @@ class DisplayServerWindows : public DisplayServer { uint64_t time_since_popup = 0; Ref<Image> icon; - WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect); + WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen); WindowID window_id_counter = MAIN_WINDOW_ID; RBMap<WindowID, WindowData> windows; @@ -524,7 +522,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override; virtual void show_window(WindowID p_window) override; virtual void delete_sub_window(WindowID p_window) override; diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index df75d34e0f..fccaf63319 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -661,5 +661,6 @@ CollisionObject2D::CollisionObject2D() { } CollisionObject2D::~CollisionObject2D() { + ERR_FAIL_NULL(PhysicsServer2D::get_singleton()); PhysicsServer2D::get_singleton()->free(rid); } diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index c6296f4732..68dc85486d 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -1507,6 +1507,7 @@ CPUParticles2D::CPUParticles2D() { } CPUParticles2D::~CPUParticles2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(multimesh); RS::get_singleton()->free(mesh); } diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index ccbc080768..95e24028a6 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -688,6 +688,7 @@ GPUParticles2D::GPUParticles2D() { } GPUParticles2D::~GPUParticles2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(particles); RS::get_singleton()->free(mesh); } diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp index 3ec744ff8e..9e12c7aa3b 100644 --- a/scene/2d/joint_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -246,6 +246,7 @@ Joint2D::Joint2D() { } Joint2D::~Joint2D() { + ERR_FAIL_NULL(PhysicsServer2D::get_singleton()); PhysicsServer2D::get_singleton()->free(joint); } diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 78b5199358..e07393a9c7 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -321,6 +321,7 @@ Light2D::Light2D() { } Light2D::~Light2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(canvas_light); } diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 67e82140e4..e7997c6eff 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -148,6 +148,7 @@ OccluderPolygon2D::OccluderPolygon2D() { } OccluderPolygon2D::~OccluderPolygon2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(occ_polygon); } @@ -291,5 +292,7 @@ LightOccluder2D::LightOccluder2D() { } LightOccluder2D::~LightOccluder2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + RS::get_singleton()->free(occluder); } diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index 2bbe88b0e0..3936724dd4 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -380,7 +380,7 @@ void LineBuilder::build() { current_distance1 += pos0.distance_to(pos1); } if (_interpolate_color) { - color1 = gradient->get_color(gradient->get_points_count() - 1); + color1 = gradient->get_color(gradient->get_point_count() - 1); } if (retrieve_curve) { width_factor = curve->sample_baked(1.f); @@ -406,7 +406,7 @@ void LineBuilder::build() { // End cap (round) if (end_cap_mode == Line2D::LINE_CAP_ROUND) { // Note: color is not used in case we don't interpolate... - Color color = _interpolate_color ? gradient->get_color(gradient->get_points_count() - 1) : Color(0, 0, 0); + Color color = _interpolate_color ? gradient->get_color(gradient->get_point_count() - 1) : Color(0, 0, 0); float dist = 0; if (texture_mode == Line2D::LINE_TEXTURE_TILE) { dist = width_factor / tile_aspect; diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 62afe0d89b..4455142a6c 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -197,6 +197,7 @@ NavigationAgent2D::NavigationAgent2D() { } NavigationAgent2D::~NavigationAgent2D() { + ERR_FAIL_NULL(NavigationServer2D::get_singleton()); NavigationServer2D::get_singleton()->free(agent); agent = RID(); // Pointless } diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp index d639e1cc89..34005dbd9e 100644 --- a/scene/2d/navigation_link_2d.cpp +++ b/scene/2d/navigation_link_2d.cpp @@ -285,6 +285,7 @@ NavigationLink2D::NavigationLink2D() { } NavigationLink2D::~NavigationLink2D() { + ERR_FAIL_NULL(NavigationServer2D::get_singleton()); NavigationServer2D::get_singleton()->free(link); link = RID(); } diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index cbec4db4c5..4d9d46fb06 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -116,6 +116,7 @@ NavigationObstacle2D::NavigationObstacle2D() { } NavigationObstacle2D::~NavigationObstacle2D() { + ERR_FAIL_NULL(NavigationServer2D::get_singleton()); NavigationServer2D::get_singleton()->free(agent); agent = RID(); // Pointless } diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 675ef7c780..78c65256e8 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -343,6 +343,7 @@ NavigationRegion2D::NavigationRegion2D() { } NavigationRegion2D::~NavigationRegion2D() { + ERR_FAIL_NULL(NavigationServer2D::get_singleton()); NavigationServer2D::get_singleton()->free(region); #ifdef DEBUG_ENABLED diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index e41664b006..5b00a3a2dc 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -664,6 +664,7 @@ Polygon2D::Polygon2D() { Polygon2D::~Polygon2D() { // This will free the internally-allocated mesh instance, if allocated. + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID()); RS::get_singleton()->free(mesh); } diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 62787d4488..fa0358fabc 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -529,6 +529,7 @@ Bone2D::Bone2D() { Bone2D::~Bone2D() { #ifdef TOOLS_ENABLED if (!editor_gizmo_rid.is_null()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(editor_gizmo_rid); } #endif // TOOLS_ENABLED @@ -803,5 +804,6 @@ Skeleton2D::Skeleton2D() { } Skeleton2D::~Skeleton2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(skeleton); } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 3136752a2e..f52dbd1c53 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1108,6 +1108,7 @@ void TileMap::_rendering_update_layer(int p_layer) { void TileMap::_rendering_cleanup_layer(int p_layer) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer *rs = RenderingServer::get_singleton(); if (layers[p_layer].canvas_item.is_valid()) { rs->free(layers[p_layer].canvas_item); @@ -1280,6 +1281,7 @@ void TileMap::_rendering_create_quadrant(TileMapQuadrant *p_quadrant) { } void TileMap::_rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); // Free the canvas items. for (const RID &ci : p_quadrant->canvas_items) { RenderingServer::get_singleton()->free(ci); @@ -1596,6 +1598,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r void TileMap::_physics_cleanup_quadrant(TileMapQuadrant *p_quadrant) { // Remove a quadrant. + ERR_FAIL_NULL(PhysicsServer2D::get_singleton()); for (RID body : p_quadrant->bodies) { bodies_coords.erase(body); PhysicsServer2D::get_singleton()->free(body); @@ -1754,6 +1757,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List void TileMap::_navigation_cleanup_quadrant(TileMapQuadrant *p_quadrant) { // Clear navigation shapes in the quadrant. + ERR_FAIL_NULL(NavigationServer2D::get_singleton()); for (const KeyValue<Vector2i, Vector<RID>> &E : p_quadrant->navigation_regions) { for (int i = 0; i < E.value.size(); i++) { RID region = E.value[i]; diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 2a50575749..03c24e63ef 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -744,8 +744,10 @@ Camera3D::Camera3D() { } Camera3D::~Camera3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(camera); if (pyramid_shape.is_valid()) { + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); PhysicsServer3D::get_singleton()->free(pyramid_shape); } } diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 66546092f2..1b94ff822c 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -352,6 +352,8 @@ void CollisionObject3D::_shape_changed(const Ref<Shape3D> &p_shape) { } void CollisionObject3D::_update_debug_shapes() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + if (!is_inside_tree()) { debug_shapes_to_update.clear(); return; @@ -393,6 +395,8 @@ void CollisionObject3D::_update_debug_shapes() { } void CollisionObject3D::_clear_debug_shapes() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + for (KeyValue<uint32_t, ShapeData> &E : shapes) { ShapeData &shapedata = E.value; ShapeData::ShapeBase *shape_bases = shapedata.shapes.ptrw(); @@ -627,6 +631,7 @@ int CollisionObject3D::shape_owner_get_shape_index(uint32_t p_owner, int p_shape } void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); ERR_FAIL_COND(!shapes.has(p_owner)); ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size()); @@ -722,5 +727,6 @@ CollisionObject3D::CollisionObject3D() { } CollisionObject3D::~CollisionObject3D() { + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); PhysicsServer3D::get_singleton()->free(rid); } diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 5ac8535bb6..6d47375589 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -1701,5 +1701,6 @@ CPUParticles3D::CPUParticles3D() { } CPUParticles3D::~CPUParticles3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(multimesh); } diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index fc442986a8..ee1086fb88 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -254,5 +254,6 @@ Decal::Decal() { } Decal::~Decal() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(decal); } diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp index 4606e70310..d9912c47b1 100644 --- a/scene/3d/fog_volume.cpp +++ b/scene/3d/fog_volume.cpp @@ -118,5 +118,6 @@ FogVolume::FogVolume() { } FogVolume::~FogVolume() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(volume); } diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 17dfe2610e..6302a9e1b8 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -634,5 +634,6 @@ GPUParticles3D::GPUParticles3D() { } GPUParticles3D::~GPUParticles3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(particles); } diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 476820b1c4..f6546b2d1f 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -58,6 +58,7 @@ GPUParticlesCollision3D::GPUParticlesCollision3D(RS::ParticlesCollisionType p_ty } GPUParticlesCollision3D::~GPUParticlesCollision3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(collision); } @@ -819,6 +820,7 @@ GPUParticlesAttractor3D::GPUParticlesAttractor3D(RS::ParticlesCollisionType p_ty set_base(collision); } GPUParticlesAttractor3D::~GPUParticlesAttractor3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(collision); } diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp index 1a18f43e7b..d86c156d99 100644 --- a/scene/3d/joint_3d.cpp +++ b/scene/3d/joint_3d.cpp @@ -234,6 +234,7 @@ Joint3D::Joint3D() { } Joint3D::~Joint3D() { + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); PhysicsServer3D::get_singleton()->free(joint); } diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index 262dc0db37..d3020fc5b7 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -966,6 +966,7 @@ Label3D::~Label3D() { TS->free_rid(text_rid); + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(mesh); for (KeyValue<SurfaceKey, SurfaceData> E : surfaces) { RenderingServer::get_singleton()->free(E.value.material); diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 3f43e718b8..23a08f0292 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -476,6 +476,7 @@ Light3D::Light3D() { } Light3D::~Light3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->instance_set_base(get_instance(), RID()); if (light.is_valid()) { diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 1b5427c80d..108bbe072e 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -313,6 +313,7 @@ LightmapGIData::LightmapGIData() { } LightmapGIData::~LightmapGIData() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(lightmap); } diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 741f7397ad..3acb33f42a 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -204,6 +204,7 @@ NavigationAgent3D::NavigationAgent3D() { } NavigationAgent3D::~NavigationAgent3D() { + ERR_FAIL_NULL(NavigationServer3D::get_singleton()); NavigationServer3D::get_singleton()->free(agent); agent = RID(); // Pointless } diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp index bee7c7f39b..009abfc8fd 100644 --- a/scene/3d/navigation_link_3d.cpp +++ b/scene/3d/navigation_link_3d.cpp @@ -227,10 +227,12 @@ NavigationLink3D::NavigationLink3D() { } NavigationLink3D::~NavigationLink3D() { + ERR_FAIL_NULL(NavigationServer3D::get_singleton()); NavigationServer3D::get_singleton()->free(link); link = RID(); #ifdef DEBUG_ENABLED + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (debug_instance.is_valid()) { RenderingServer::get_singleton()->free(debug_instance); } diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index f241d65649..6431bd2b77 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -122,6 +122,7 @@ NavigationObstacle3D::NavigationObstacle3D() { } NavigationObstacle3D::~NavigationObstacle3D() { + ERR_FAIL_NULL(NavigationServer3D::get_singleton()); NavigationServer3D::get_singleton()->free(agent); agent = RID(); // Pointless } diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 86b78f847e..0e0233c0cd 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -375,12 +375,15 @@ NavigationRegion3D::~NavigationRegion3D() { if (navigation_mesh.is_valid()) { navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); } + ERR_FAIL_NULL(NavigationServer3D::get_singleton()); NavigationServer3D::get_singleton()->free(region); #ifdef DEBUG_ENABLED NavigationServer3D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed)); NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh)); NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh)); + + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (debug_instance.is_valid()) { RenderingServer::get_singleton()->free(debug_instance); } diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp index 4e1ed5654a..7166d99b92 100644 --- a/scene/3d/occluder_instance_3d.cpp +++ b/scene/3d/occluder_instance_3d.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/core_string_names.h" +#include "core/io/marshalls.h" #include "core/math/geometry_2d.h" #include "core/math/triangulate.h" #include "scene/3d/importer_mesh_instance_3d.h" @@ -138,6 +139,7 @@ Occluder3D::Occluder3D() { Occluder3D::~Occluder3D() { if (occluder.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(occluder); } } @@ -533,11 +535,20 @@ void OccluderInstance3D::_bake_surface(const Transform3D &p_transform, Array p_s } if (!Math::is_zero_approx(p_simplification_dist) && SurfaceTool::simplify_func) { - float error_scale = SurfaceTool::simplify_scale_func((float *)vertices.ptr(), vertices.size(), sizeof(Vector3)); + Vector<float> vertices_f32 = vector3_to_float32_array(vertices.ptr(), vertices.size()); + + float error_scale = SurfaceTool::simplify_scale_func(vertices_f32.ptr(), vertices.size(), sizeof(float) * 3); float target_error = p_simplification_dist / error_scale; float error = -1.0f; int target_index_count = MIN(indices.size(), 36); - uint32_t index_count = SurfaceTool::simplify_func((unsigned int *)indices.ptrw(), (unsigned int *)indices.ptr(), indices.size(), (float *)vertices.ptr(), vertices.size(), sizeof(Vector3), target_index_count, target_error, &error); + + uint32_t index_count = SurfaceTool::simplify_func( + (unsigned int *)indices.ptrw(), + (unsigned int *)indices.ptr(), + indices.size(), + vertices_f32.ptr(), vertices.size(), sizeof(float) * 3, + target_index_count, target_error, &error); + indices.resize(index_count); } diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 02ab297d8e..ea0cfce987 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -40,6 +40,7 @@ Path3D::Path3D() { } Path3D::~Path3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (debug_instance.is_valid()) { RS::get_singleton()->free(debug_instance); } diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index d29f337fc8..fd0b7912ae 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -1246,6 +1246,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo platform_rid = RID(); platform_object_id = ObjectID(); platform_velocity = Vector3(); + platform_angular_velocity = Vector3(); platform_ceiling_velocity = Vector3(); floor_normal = Vector3(); wall_normal = Vector3(); @@ -1506,6 +1507,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) { platform_object_id = ObjectID(); floor_normal = Vector3(); platform_velocity = Vector3(); + platform_angular_velocity = Vector3(); bool first_slide = true; for (int iteration = 0; iteration < max_slides; ++iteration) { @@ -1708,6 +1710,7 @@ void CharacterBody3D::_set_platform_data(const PhysicsServer3D::MotionCollision platform_rid = p_collision.collider; platform_object_id = p_collision.collider_id; platform_velocity = p_collision.collider_velocity; + platform_angular_velocity = p_collision.collider_angular_velocity; platform_layer = PhysicsServer3D::get_singleton()->body_get_collision_layer(platform_rid); } @@ -1780,6 +1783,10 @@ const Vector3 &CharacterBody3D::get_platform_velocity() const { return platform_velocity; } +const Vector3 &CharacterBody3D::get_platform_angular_velocity() const { + return platform_angular_velocity; +} + Vector3 CharacterBody3D::get_linear_velocity() const { return get_real_velocity(); } @@ -1932,6 +1939,7 @@ void CharacterBody3D::_notification(int p_what) { platform_object_id = ObjectID(); motion_results.clear(); platform_velocity = Vector3(); + platform_angular_velocity = Vector3(); } break; } } @@ -1986,6 +1994,7 @@ void CharacterBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody3D::get_real_velocity); ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody3D::get_floor_angle, DEFVAL(Vector3(0.0, 1.0, 0.0))); ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody3D::get_platform_velocity); + ClassDB::bind_method(D_METHOD("get_platform_angular_velocity"), &CharacterBody3D::get_platform_angular_velocity); ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody3D::get_slide_collision_count); ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision); ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody3D::_get_last_slide_collision); @@ -3358,6 +3367,7 @@ PhysicalBone3D::~PhysicalBone3D() { if (joint_data) { memdelete(joint_data); } + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); PhysicsServer3D::get_singleton()->free(joint); } diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 36b7ce774c..9c5cb48762 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -371,6 +371,7 @@ public: const Vector3 &get_real_velocity() const; real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const; const Vector3 &get_platform_velocity() const; + const Vector3 &get_platform_angular_velocity() const; virtual Vector3 get_linear_velocity() const override; @@ -423,6 +424,7 @@ private: Vector3 ceiling_normal; Vector3 last_motion; Vector3 platform_velocity; + Vector3 platform_angular_velocity; Vector3 platform_ceiling_velocity; Vector3 previous_position; Vector3 real_velocity; diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index bc3cc31963..f8164ee1aa 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -257,5 +257,6 @@ ReflectionProbe::ReflectionProbe() { } ReflectionProbe::~ReflectionProbe() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(probe); } diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index b205c2cde0..27310e7cee 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -58,10 +58,10 @@ Ref<Skin> SkinReference::get_skin() const { } SkinReference::~SkinReference() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (skeleton_node) { skeleton_node->skin_bindings.erase(this); } - RS::get_singleton()->free(skeleton); } diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index 1814baa9e9..31d3f1aeb7 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -704,6 +704,7 @@ SoftBody3D::SoftBody3D() : SoftBody3D::~SoftBody3D() { memdelete(rendering_server_handler); + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); PhysicsServer3D::get_singleton()->free(physics_rid); } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index e488ff3059..3629464cd1 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -611,6 +611,7 @@ SpriteBase3D::SpriteBase3D() { } SpriteBase3D::~SpriteBase3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(mesh); RenderingServer::get_singleton()->free(material); } diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp index 6d4c18a69e..70c9321338 100644 --- a/scene/3d/visible_on_screen_notifier_3d.cpp +++ b/scene/3d/visible_on_screen_notifier_3d.cpp @@ -99,6 +99,7 @@ VisibleOnScreenNotifier3D::VisibleOnScreenNotifier3D() { VisibleOnScreenNotifier3D::~VisibleOnScreenNotifier3D() { RID base_old = get_base(); set_base(RID()); + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(base_old); } diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 3b21f5c03a..07ca63dcd6 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -157,6 +157,7 @@ VisualInstance3D::VisualInstance3D() { } VisualInstance3D::~VisualInstance3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(instance); } diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index 7caf2f4874..2cb15715c6 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -242,6 +242,7 @@ VoxelGIData::VoxelGIData() { } VoxelGIData::~VoxelGIData() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(probe); } @@ -516,5 +517,6 @@ VoxelGI::VoxelGI() { } VoxelGI::~VoxelGI() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(voxel_gi); } diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index d54740e9b0..4c677b6a9f 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -415,9 +415,6 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s fading_pos += p_time; } fade_blend = MIN(1.0, fading_pos / fading_time); - if (fade_blend > 1.0) { - fading_from = StringName(); - } } } @@ -426,9 +423,12 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } double rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. - double fade_blend_inv = 1.0 - fade_blend; if (fading_from != StringName()) { + double fade_blend_inv = 1.0 - fade_blend; p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend_inv) ? CMP_EPSILON : fade_blend_inv, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + if (fade_blend >= 1.0) { + fading_from = StringName(); + } } //guess playback position diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index aa58e1044a..448b9e9ad2 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -563,6 +563,10 @@ PropertyTweener::PropertyTweener(Object *p_target, NodePath p_property, Variant base_final_val = p_to; final_val = base_final_val; duration = p_duration; + + if (p_target->is_ref_counted()) { + ref_copy = p_target; + } } PropertyTweener::PropertyTweener() { @@ -640,6 +644,11 @@ void CallbackTweener::_bind_methods() { CallbackTweener::CallbackTweener(Callable p_callback) { callback = p_callback; + + Object *callback_instance = p_callback.get_object(); + if (callback_instance && callback_instance->is_ref_counted()) { + ref_copy = callback_instance; + } } CallbackTweener::CallbackTweener() { @@ -728,6 +737,11 @@ MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, delta_val = Animation::subtract_variant(p_to, p_from); final_val = p_to; duration = p_duration; + + Object *callback_instance = p_callback.get_object(); + if (callback_instance && callback_instance->is_ref_counted()) { + ref_copy = callback_instance; + } } MethodTweener::MethodTweener() { diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 345974ecc5..4b69dc337c 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -208,6 +208,8 @@ private: Variant final_val; Variant delta_val; + Ref<RefCounted> ref_copy; // Makes sure that RefCounted objects are not freed too early. + double duration = 0; Tween::TransitionType trans_type = Tween::TRANS_MAX; // This is set inside set_tween(); Tween::EaseType ease_type = Tween::EASE_MAX; @@ -249,6 +251,8 @@ protected: private: Callable callback; double delay = 0; + + Ref<RefCounted> ref_copy; }; class MethodTweener : public Tweener { @@ -280,6 +284,8 @@ private: Variant delta_val; Variant final_val; Callable callback; + + Ref<RefCounted> ref_copy; }; #endif // TWEEN_H diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 11a3803b35..a846ab9485 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -411,7 +411,7 @@ void FileDialog::_go_back() { } void FileDialog::_go_forward() { - if (local_history_pos == local_history.size() - 1) { + if (local_history_pos >= local_history.size() - 1) { return; } diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 82ef53e317..3c404c65b5 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -345,6 +345,7 @@ void MenuBar::_notification(int p_what) { } break; case NOTIFICATION_MOUSE_EXIT: { focused_menu = -1; + selected_menu = -1; queue_redraw(); } break; case NOTIFICATION_TRANSLATION_CHANGED: diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index f87829cf71..beaffc14b0 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -154,7 +154,9 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { queue_redraw(); } - _update_hover(); + if (!tabs.is_empty()) { + _update_hover(); + } return; } @@ -362,12 +364,19 @@ void TabBar::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { + bool rtl = is_layout_rtl(); + Vector2 size = get_size(); + if (tabs.is_empty()) { + // Draw the drop indicator where the first tab would be if there are no tabs. + if (dragging_valid_tab) { + int x = rtl ? size.x : 0; + theme_cache.drop_mark_icon->draw(get_canvas_item(), Point2(x - (theme_cache.drop_mark_icon->get_width() / 2), (size.height - theme_cache.drop_mark_icon->get_height()) / 2), theme_cache.drop_mark_color); + } + return; } - bool rtl = is_layout_rtl(); - Vector2 size = get_size(); int limit_minus_buttons = size.width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); int ofs = tabs[offset].ofs_cache; @@ -1092,7 +1101,8 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { hover_now += 1; } } else { - hover_now = is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x) ? 0 : get_tab_count() - 1; + int x = tabs.is_empty() ? 0 : get_tab_rect(0).position.x; + hover_now = is_layout_rtl() ^ (p_point.x < x) ? 0 : get_tab_count() - 1; } move_tab(tab_from_id, hover_now); @@ -1118,7 +1128,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { hover_now += 1; } } else { - hover_now = is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x) ? 0 : get_tab_count(); + hover_now = tabs.is_empty() || (is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x)) ? 0 : get_tab_count(); } Tab moving_tab = from_tabs->tabs[tab_from_id]; @@ -1154,10 +1164,13 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { int TabBar::get_tab_idx_at_point(const Point2 &p_point) const { int hover_now = -1; - for (int i = offset; i <= max_drawn_tab; i++) { - Rect2 rect = get_tab_rect(i); - if (rect.has_point(p_point)) { - hover_now = i; + + if (!tabs.is_empty()) { + for (int i = offset; i <= max_drawn_tab; i++) { + Rect2 rect = get_tab_rect(i); + if (rect.has_point(p_point)) { + hover_now = i; + } } } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 79bad44e15..b105ad5165 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2580,8 +2580,8 @@ void Tree::_range_click_timeout() { mb.instantiate(); int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width; - if (h_scroll->is_visible()) { - x_limit -= h_scroll->get_minimum_size().width; + if (v_scroll->is_visible()) { + x_limit -= v_scroll->get_minimum_size().width; } cache.rtl = is_layout_rtl(); @@ -3640,8 +3640,8 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { propagate_mouse_activated = false; int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width; - if (h_scroll->is_visible()) { - x_limit -= h_scroll->get_minimum_size().width; + if (v_scroll->is_visible()) { + x_limit -= v_scroll->get_minimum_size().width; } cache.rtl = is_layout_rtl(); @@ -3847,41 +3847,38 @@ Size2 Tree::get_internal_min_size() const { } void Tree::update_scrollbars() { - Size2 size = get_size(); - int tbh; - if (show_column_titles) { - tbh = _get_title_button_height(); - } else { - tbh = 0; - } - - Size2 hmin = h_scroll->get_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); - - v_scroll->set_begin(Point2(size.width - vmin.width, theme_cache.panel_style->get_margin(SIDE_TOP))); - v_scroll->set_end(Point2(size.width, size.height - theme_cache.panel_style->get_margin(SIDE_TOP) - theme_cache.panel_style->get_margin(SIDE_BOTTOM))); - - h_scroll->set_begin(Point2(0, size.height - hmin.height)); - h_scroll->set_end(Point2(size.width - vmin.width, size.height)); - - Size2 internal_min_size = get_internal_min_size(); - - bool display_vscroll = internal_min_size.height + theme_cache.panel_style->get_margin(SIDE_TOP) > size.height; - bool display_hscroll = internal_min_size.width + theme_cache.panel_style->get_margin(SIDE_LEFT) > size.width; + const Size2 size = get_size(); + const Size2 hmin = h_scroll->get_combined_minimum_size(); + const Size2 vmin = v_scroll->get_combined_minimum_size(); + + const Rect2 content_rect = Rect2(theme_cache.panel_style->get_offset(), size - theme_cache.panel_style->get_minimum_size()); + v_scroll->set_begin(content_rect.get_position() + Vector2(content_rect.get_size().x - vmin.width, 0)); + v_scroll->set_end(content_rect.get_end() - Vector2(0, hmin.height)); + h_scroll->set_begin(content_rect.get_position() + Vector2(0, content_rect.get_size().y - hmin.height)); + h_scroll->set_end(content_rect.get_end() - Vector2(vmin.width, 0)); + + const Size2 internal_min_size = get_internal_min_size(); + const int title_button_height = _get_title_button_height(); + + Size2 tree_content_size = content_rect.get_size() - Vector2(0, title_button_height); + bool display_vscroll = internal_min_size.height > tree_content_size.height; + bool display_hscroll = internal_min_size.width > tree_content_size.width; for (int i = 0; i < 2; i++) { // Check twice, as both values are dependent on each other. if (display_hscroll) { - display_vscroll = internal_min_size.height + theme_cache.panel_style->get_margin(SIDE_TOP) + hmin.height > size.height; + tree_content_size.height = content_rect.get_size().height - title_button_height - hmin.height; + display_vscroll = internal_min_size.height > tree_content_size.height; } if (display_vscroll) { - display_hscroll = internal_min_size.width + theme_cache.panel_style->get_margin(SIDE_LEFT) + vmin.width > size.width; + tree_content_size.width = content_rect.get_size().width - vmin.width; + display_hscroll = internal_min_size.width > tree_content_size.width; } } if (display_vscroll) { v_scroll->show(); v_scroll->set_max(internal_min_size.height); - v_scroll->set_page(size.height - hmin.height - tbh); + v_scroll->set_page(tree_content_size.height); theme_cache.offset.y = v_scroll->get_value(); } else { v_scroll->hide(); @@ -3891,7 +3888,7 @@ void Tree::update_scrollbars() { if (display_hscroll) { h_scroll->show(); h_scroll->set_max(internal_min_size.width); - h_scroll->set_page(size.width - vmin.width); + h_scroll->set_page(tree_content_size.width); theme_cache.offset.x = h_scroll->get_value(); } else { h_scroll->hide(); @@ -4015,8 +4012,8 @@ void Tree::_notification(int p_what) { Point2 draw_ofs; draw_ofs += bg->get_offset(); Size2 draw_size = get_size() - bg->get_minimum_size(); - if (h_scroll->is_visible()) { - draw_size.width -= h_scroll->get_minimum_size().width; + if (v_scroll->is_visible()) { + draw_size.width -= v_scroll->get_minimum_size().width; } bg->draw(ci, Rect2(Point2(), get_size())); diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index f3812eb497..404c289a6a 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -1305,6 +1305,7 @@ CanvasItem::CanvasItem() : } CanvasItem::~CanvasItem() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(canvas_item); } @@ -1459,5 +1460,6 @@ CanvasTexture::CanvasTexture() { canvas_texture = RS::get_singleton()->canvas_texture_create(); } CanvasTexture::~CanvasTexture() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(canvas_texture); } diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 97b784e9d0..2aa8df10ab 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -360,5 +360,6 @@ CanvasLayer::CanvasLayer() { } CanvasLayer::~CanvasLayer() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(canvas); } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index afc31ae480..c0b81c9b9a 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -80,6 +80,7 @@ void ViewportTexture::setup_local_to_scene() { vp->viewport_textures.insert(this); + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (proxy_ph.is_valid()) { RS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid); RS::get_singleton()->free(proxy_ph); @@ -153,6 +154,8 @@ ViewportTexture::~ViewportTexture() { vp->viewport_textures.erase(this); } + ERR_FAIL_NULL(RenderingServer::get_singleton()); + if (proxy_ph.is_valid()) { RS::get_singleton()->free(proxy_ph); } @@ -301,6 +304,8 @@ void Viewport::_sub_window_remove(Window *p_window) { int index = _sub_window_find(p_window); ERR_FAIL_COND(index == -1); + ERR_FAIL_NULL(RenderingServer::get_singleton()); + RS::get_singleton()->free(gui.sub_windows[index].canvas_item); gui.sub_windows.remove_at(index); @@ -4117,6 +4122,7 @@ Viewport::~Viewport() { for (ViewportTexture *E : viewport_textures) { E->vp = nullptr; } + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(viewport); } diff --git a/scene/main/window.cpp b/scene/main/window.cpp index c71c3e195b..f18b712153 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -462,9 +462,8 @@ void Window::_make_window() { } DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID); - window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size)); + window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size), current_screen); ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); - DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id); DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id); DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id); String tr_title = atr(title); diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp index 8e4876e01f..292accddc1 100644 --- a/scene/resources/camera_attributes.cpp +++ b/scene/resources/camera_attributes.cpp @@ -135,6 +135,7 @@ CameraAttributes::CameraAttributes() { } CameraAttributes::~CameraAttributes() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(camera_attributes); } diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp index b16059c218..0cc5faffb1 100644 --- a/scene/resources/canvas_item_material.cpp +++ b/scene/resources/canvas_item_material.cpp @@ -294,6 +294,8 @@ CanvasItemMaterial::CanvasItemMaterial() : CanvasItemMaterial::~CanvasItemMaterial() { MutexLock lock(material_mutex); + ERR_FAIL_NULL(RenderingServer::get_singleton()); + if (shader_map.has(current_key)) { shader_map[current_key].users--; if (shader_map[current_key].users == 0) { diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 571ddee763..a2638c39ca 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -509,14 +509,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Texture2D> empty_icon = memnew(ImageTexture); - const Ref<StyleBoxFlat> style_scrollbar = make_flat_stylebox(style_normal_color, 4, 4, 4, 4, 10); + const Ref<StyleBoxFlat> style_h_scrollbar = make_flat_stylebox(style_normal_color, 0, 4, 0, 4, 10); + const Ref<StyleBoxFlat> style_v_scrollbar = make_flat_stylebox(style_normal_color, 4, 0, 4, 0, 10); Ref<StyleBoxFlat> style_scrollbar_grabber = make_flat_stylebox(style_progress_color, 4, 4, 4, 4, 10); Ref<StyleBoxFlat> style_scrollbar_grabber_highlight = make_flat_stylebox(style_focus_color, 4, 4, 4, 4, 10); Ref<StyleBoxFlat> style_scrollbar_grabber_pressed = make_flat_stylebox(style_focus_color * Color(0.75, 0.75, 0.75), 4, 4, 4, 4, 10); // HScrollBar - theme->set_stylebox("scroll", "HScrollBar", style_scrollbar); + theme->set_stylebox("scroll", "HScrollBar", style_h_scrollbar); theme->set_stylebox("scroll_focus", "HScrollBar", focus); theme->set_stylebox("grabber", "HScrollBar", style_scrollbar_grabber); theme->set_stylebox("grabber_highlight", "HScrollBar", style_scrollbar_grabber_highlight); @@ -531,7 +532,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // VScrollBar - theme->set_stylebox("scroll", "VScrollBar", style_scrollbar); + theme->set_stylebox("scroll", "VScrollBar", style_v_scrollbar); theme->set_stylebox("scroll_focus", "VScrollBar", focus); theme->set_stylebox("grabber", "VScrollBar", style_scrollbar_grabber); theme->set_stylebox("grabber_highlight", "VScrollBar", style_scrollbar_grabber_highlight); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 23bd8a4be4..f97cffc3fc 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1550,5 +1550,6 @@ Environment::Environment() { } Environment::~Environment() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(environment); } diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp index 46b44d681f..2aca552716 100644 --- a/scene/resources/fog_material.cpp +++ b/scene/resources/fog_material.cpp @@ -132,6 +132,7 @@ void FogMaterial::_bind_methods() { void FogMaterial::cleanup_shader() { if (shader.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(shader); } } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 584a7e7eac..78b4edfcf7 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -270,24 +270,18 @@ void Font::set_cache_capacity(int p_single_line, int p_multi_line) { } Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const { - uint64_t hash = p_text.hash64(); - hash = hash_djb2_one_64(p_font_size, hash); - if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) { - hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash); - hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash); - } - hash = hash_djb2_one_64(p_direction, hash); - hash = hash_djb2_one_64(p_orientation, hash); + bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL); + ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation); Ref<TextLine> buffer; - if (cache.has(hash)) { - buffer = cache.get(hash); + if (cache.has(key)) { + buffer = cache.get(key); } else { buffer.instantiate(); buffer->set_direction(p_direction); buffer->set_orientation(p_orientation); buffer->add_string(p_text, Ref<Font>(this), p_font_size); - cache.insert(hash, buffer); + cache.insert(key, buffer); } buffer->set_width(p_width); @@ -300,17 +294,11 @@ Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignmen } Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const { - uint64_t hash = p_text.hash64(); - hash = hash_djb2_one_64(p_font_size, hash); - hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash); - hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash); - hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash); - hash = hash_djb2_one_64(p_direction, hash); - hash = hash_djb2_one_64(p_orientation, hash); + ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation); Ref<TextParagraph> lines_buffer; - if (cache_wrap.has(hash)) { - lines_buffer = cache_wrap.get(hash); + if (cache_wrap.has(key)) { + lines_buffer = cache_wrap.get(key); } else { lines_buffer.instantiate(); lines_buffer->set_direction(p_direction); @@ -319,7 +307,7 @@ Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment lines_buffer->set_width(p_width); lines_buffer->set_break_flags(p_brk_flags); lines_buffer->set_justification_flags(p_jst_flags); - cache_wrap.insert(hash, lines_buffer); + cache_wrap.insert(key, lines_buffer); } lines_buffer->set_alignment(p_alignment); @@ -329,24 +317,18 @@ Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment } void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const { - uint64_t hash = p_text.hash64(); - hash = hash_djb2_one_64(p_font_size, hash); - if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) { - hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash); - hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash); - } - hash = hash_djb2_one_64(p_direction, hash); - hash = hash_djb2_one_64(p_orientation, hash); + bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL); + ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation); Ref<TextLine> buffer; - if (cache.has(hash)) { - buffer = cache.get(hash); + if (cache.has(key)) { + buffer = cache.get(key); } else { buffer.instantiate(); buffer->set_direction(p_direction); buffer->set_orientation(p_orientation); buffer->add_string(p_text, Ref<Font>(this), p_font_size); - cache.insert(hash, buffer); + cache.insert(key, buffer); } Vector2 ofs = p_pos; @@ -366,17 +348,11 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t } void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const { - uint64_t hash = p_text.hash64(); - hash = hash_djb2_one_64(p_font_size, hash); - hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash); - hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash); - hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash); - hash = hash_djb2_one_64(p_direction, hash); - hash = hash_djb2_one_64(p_orientation, hash); + ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation); Ref<TextParagraph> lines_buffer; - if (cache_wrap.has(hash)) { - lines_buffer = cache_wrap.get(hash); + if (cache_wrap.has(key)) { + lines_buffer = cache_wrap.get(key); } else { lines_buffer.instantiate(); lines_buffer->set_direction(p_direction); @@ -385,7 +361,7 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S lines_buffer->set_width(p_width); lines_buffer->set_break_flags(p_brk_flags); lines_buffer->set_justification_flags(p_jst_flags); - cache_wrap.insert(hash, lines_buffer); + cache_wrap.insert(key, lines_buffer); } Vector2 ofs = p_pos; @@ -402,24 +378,18 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S } void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const { - uint64_t hash = p_text.hash64(); - hash = hash_djb2_one_64(p_font_size, hash); - if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) { - hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash); - hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash); - } - hash = hash_djb2_one_64(p_direction, hash); - hash = hash_djb2_one_64(p_orientation, hash); + bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL); + ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation); Ref<TextLine> buffer; - if (cache.has(hash)) { - buffer = cache.get(hash); + if (cache.has(key)) { + buffer = cache.get(key); } else { buffer.instantiate(); buffer->set_direction(p_direction); buffer->set_orientation(p_orientation); buffer->add_string(p_text, Ref<Font>(this), p_font_size); - cache.insert(hash, buffer); + cache.insert(key, buffer); } Vector2 ofs = p_pos; @@ -439,17 +409,11 @@ void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const Str } void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const { - uint64_t hash = p_text.hash64(); - hash = hash_djb2_one_64(p_font_size, hash); - hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash); - hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash); - hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash); - hash = hash_djb2_one_64(p_direction, hash); - hash = hash_djb2_one_64(p_orientation, hash); + ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation); Ref<TextParagraph> lines_buffer; - if (cache_wrap.has(hash)) { - lines_buffer = cache_wrap.get(hash); + if (cache_wrap.has(key)) { + lines_buffer = cache_wrap.get(key); } else { lines_buffer.instantiate(); lines_buffer->set_direction(p_direction); @@ -458,7 +422,7 @@ void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, lines_buffer->set_width(p_width); lines_buffer->set_break_flags(p_brk_flags); lines_buffer->set_justification_flags(p_jst_flags); - cache_wrap.insert(hash, lines_buffer); + cache_wrap.insert(key, lines_buffer); } Vector2 ofs = p_pos; diff --git a/scene/resources/font.h b/scene/resources/font.h index e9f7507652..44198a3111 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -47,9 +47,44 @@ class TextParagraph; class Font : public Resource { GDCLASS(Font, Resource); + struct ShapedTextKey { + String text; + int font_size = 14; + float width = 0.f; + BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_NONE; + BitField<TextServer::LineBreakFlag> brk_flags = TextServer::BREAK_MANDATORY; + TextServer::Direction direction = TextServer::DIRECTION_AUTO; + TextServer::Orientation orientation = TextServer::ORIENTATION_HORIZONTAL; + + bool operator==(const ShapedTextKey &p_b) const { + return (font_size == p_b.font_size) && (width == p_b.width) && (jst_flags == p_b.jst_flags) && (brk_flags == p_b.brk_flags) && (direction == p_b.direction) && (orientation == p_b.orientation) && (text == p_b.text); + } + + ShapedTextKey() {} + ShapedTextKey(const String &p_text, int p_font_size, float p_width, BitField<TextServer::JustificationFlag> p_jst_flags, BitField<TextServer::LineBreakFlag> p_brk_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) { + text = p_text; + font_size = p_font_size; + width = p_width; + jst_flags = p_jst_flags; + brk_flags = p_brk_flags; + direction = p_direction; + orientation = p_orientation; + } + }; + + struct ShapedTextKeyHasher { + _FORCE_INLINE_ static uint32_t hash(const ShapedTextKey &p_a) { + uint32_t hash = p_a.text.hash(); + hash = hash_murmur3_one_32(p_a.font_size, hash); + hash = hash_murmur3_one_float(p_a.width, hash); + hash = hash_murmur3_one_32(p_a.brk_flags | (p_a.jst_flags << 6) | (p_a.direction << 12) | (p_a.orientation << 15), hash); + return hash_fmix32(hash); + } + }; + // Shaped string cache. - mutable LRUCache<uint64_t, Ref<TextLine>> cache; - mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap; + mutable LRUCache<ShapedTextKey, Ref<TextLine>, ShapedTextKeyHasher> cache; + mutable LRUCache<ShapedTextKey, Ref<TextParagraph>, ShapedTextKeyHasher> cache_wrap; protected: // Output. diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp index f04eb75d86..4890bb32c4 100644 --- a/scene/resources/gradient.cpp +++ b/scene/resources/gradient.cpp @@ -58,7 +58,7 @@ void Gradient::_bind_methods() { ClassDB::bind_method(D_METHOD("sample", "offset"), &Gradient::get_color_at_offset); - ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count); + ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_point_count); ClassDB::bind_method(D_METHOD("set_offsets", "offsets"), &Gradient::set_offsets); ClassDB::bind_method(D_METHOD("get_offsets"), &Gradient::get_offsets); @@ -190,6 +190,6 @@ Color Gradient::get_color(int pos) { return points[pos].color; } -int Gradient::get_points_count() const { +int Gradient::get_point_count() const { return points.size(); } diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h index 2b91331ab0..16ddf5df2a 100644 --- a/scene/resources/gradient.h +++ b/scene/resources/gradient.h @@ -171,7 +171,7 @@ public: } } - int get_points_count() const; + int get_point_count() const; }; VARIANT_ENUM_CAST(Gradient::InterpolationMode); diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp index 90cc3ea5f4..2defe729cc 100644 --- a/scene/resources/immediate_mesh.cpp +++ b/scene/resources/immediate_mesh.cpp @@ -410,5 +410,6 @@ ImmediateMesh::ImmediateMesh() { mesh = RS::get_singleton()->mesh_create(); } ImmediateMesh::~ImmediateMesh() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(mesh); } diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index d1278f9340..b5e02b2f76 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -30,6 +30,7 @@ #include "importer_mesh.h" +#include "core/io/marshalls.h" #include "core/math/random_pcg.h" #include "core/math/static_raycaster.h" #include "scene/resources/surface_tool.h" @@ -424,9 +425,8 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli normal_weights[j] = 2.0; // Give some weight to normal preservation, may be worth exposing as an import setting } - const float max_mesh_error = FLT_MAX; // We don't want to limit by error, just by index target - float scale = SurfaceTool::simplify_scale_func((const float *)merged_vertices_ptr, merged_vertex_count, sizeof(Vector3)); - float mesh_error = 0.0f; + Vector<float> merged_vertices_f32 = vector3_to_float32_array(merged_vertices_ptr, merged_vertex_count); + float scale = SurfaceTool::simplify_scale_func(merged_vertices_f32.ptr(), merged_vertex_count, sizeof(float) * 3); unsigned int index_target = 12; // Start with the smallest target, 4 triangles unsigned int last_index_count = 0; @@ -446,11 +446,25 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli raycaster->commit(); } + const float max_mesh_error = FLT_MAX; // We don't want to limit by error, just by index target + float mesh_error = 0.0f; + while (index_target < index_count) { PackedInt32Array new_indices; new_indices.resize(index_count); - size_t new_index_count = SurfaceTool::simplify_with_attrib_func((unsigned int *)new_indices.ptrw(), (const uint32_t *)merged_indices_ptr, index_count, (const float *)merged_vertices_ptr, merged_vertex_count, sizeof(Vector3), index_target, max_mesh_error, &mesh_error, (float *)merged_normals.ptr(), normal_weights.ptr(), 3); + Vector<float> merged_normals_f32 = vector3_to_float32_array(merged_normals.ptr(), merged_normals.size()); + + size_t new_index_count = SurfaceTool::simplify_with_attrib_func( + (unsigned int *)new_indices.ptrw(), + (const uint32_t *)merged_indices_ptr, index_count, + merged_vertices_f32.ptr(), merged_vertex_count, + sizeof(float) * 3, // Vertex stride + index_target, + max_mesh_error, + &mesh_error, + merged_normals_f32.ptr(), + normal_weights.ptr(), 3); if (new_index_count < last_index_count * 1.5f) { index_target = index_target * 1.5f; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index a16d2c2072..44ce90cc4a 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -141,6 +141,7 @@ Material::Material() { } Material::~Material() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(material); } @@ -3005,6 +3006,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : } BaseMaterial3D::~BaseMaterial3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); MutexLock lock(material_mutex); if (shader_map.has(current_key)) { diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index af770ddede..a610290a11 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -2117,6 +2117,7 @@ ArrayMesh::ArrayMesh() { ArrayMesh::~ArrayMesh() { if (mesh.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(mesh); } } @@ -2132,5 +2133,6 @@ PlaceholderMesh::PlaceholderMesh() { } PlaceholderMesh::~PlaceholderMesh() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(rid); } diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index 8afb0563b2..2ea357d814 100644 --- a/scene/resources/multimesh.cpp +++ b/scene/resources/multimesh.cpp @@ -365,5 +365,6 @@ MultiMesh::MultiMesh() { } MultiMesh::~MultiMesh() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(multimesh); } diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp index 04077e95a7..273fbdf03c 100644 --- a/scene/resources/navigation_polygon.cpp +++ b/scene/resources/navigation_polygon.cpp @@ -295,7 +295,7 @@ void NavigationPolygon::make_polygons_from_outlines() { if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! ERR_PRINT("NavigationPolygon: Convex partition failed! Failed to convert outlines to a valid NavigationMesh." "\nNavigationPolygon outlines can not overlap vertices or edges inside same outline or with other outlines or have any intersections." - "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with opposite winding order."); + "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with same winding order."); return; } diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp index b77430c154..a07a8ac7cd 100644 --- a/scene/resources/particle_process_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -1894,6 +1894,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() : } ParticleProcessMaterial::~ParticleProcessMaterial() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); MutexLock lock(material_mutex); if (shader_map.has(current_key)) { diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 54d3676c15..aeb62d6709 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -340,6 +340,7 @@ PrimitiveMesh::PrimitiveMesh() { } PrimitiveMesh::~PrimitiveMesh() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(mesh); } diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 48ec084b02..c6621ce482 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -208,6 +208,7 @@ Shader::Shader() { } Shader::~Shader() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(shader); } diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp index 735134e27b..32ce0abf7a 100644 --- a/scene/resources/sky.cpp +++ b/scene/resources/sky.cpp @@ -106,5 +106,6 @@ Sky::Sky() { } Sky::~Sky() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(sky); } diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 94967352c8..185cbdc6bf 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -46,7 +46,7 @@ void SurfaceTool::strip_mesh_arrays(PackedVector3Array &r_vertices, PackedInt32A Vector<uint32_t> remap; remap.resize(r_vertices.size()); - uint32_t new_vertex_count = generate_remap_func(remap.ptrw(), (unsigned int *)r_indices.ptr(), r_indices.size(), (float *)r_vertices.ptr(), r_vertices.size(), sizeof(Vector3)); + uint32_t new_vertex_count = generate_remap_func(remap.ptrw(), (unsigned int *)r_indices.ptr(), r_indices.size(), r_vertices.ptr(), r_vertices.size(), sizeof(Vector3)); remap_vertex_func(r_vertices.ptrw(), r_vertices.ptr(), r_vertices.size(), sizeof(Vector3), remap.ptr()); r_vertices.resize(new_vertex_count); remap_index_func((unsigned int *)r_indices.ptrw(), (unsigned int *)r_indices.ptr(), r_indices.size(), remap.ptr()); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 48eaf98aa3..6193c62788 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -324,6 +324,7 @@ ImageTexture::ImageTexture() {} ImageTexture::~ImageTexture() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(texture); } } @@ -630,6 +631,7 @@ PortableCompressedTexture2D::PortableCompressedTexture2D() {} PortableCompressedTexture2D::~PortableCompressedTexture2D() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(texture); } } @@ -1041,6 +1043,7 @@ CompressedTexture2D::CompressedTexture2D() {} CompressedTexture2D::~CompressedTexture2D() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(texture); } } @@ -1225,6 +1228,7 @@ ImageTexture3D::ImageTexture3D() { ImageTexture3D::~ImageTexture3D() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(texture); } } @@ -1386,6 +1390,7 @@ CompressedTexture3D::CompressedTexture3D() {} CompressedTexture3D::~CompressedTexture3D() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(texture); } } @@ -1911,6 +1916,7 @@ CurveTexture::CurveTexture() {} CurveTexture::~CurveTexture() { if (_texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(_texture); } } @@ -2109,6 +2115,7 @@ CurveXYZTexture::CurveXYZTexture() {} CurveXYZTexture::~CurveXYZTexture() { if (_texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(_texture); } } @@ -2121,6 +2128,7 @@ GradientTexture1D::GradientTexture1D() { GradientTexture1D::~GradientTexture1D() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(texture); } } @@ -2263,6 +2271,7 @@ GradientTexture2D::GradientTexture2D() { GradientTexture2D::~GradientTexture2D() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(texture); } } @@ -2303,9 +2312,9 @@ void GradientTexture2D::_update() { Ref<Image> image; image.instantiate(); - if (gradient->get_points_count() <= 1) { // No need to interpolate. + if (gradient->get_point_count() <= 1) { // No need to interpolate. image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8); - image->fill((gradient->get_points_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1)); + image->fill((gradient->get_point_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1)); } else { if (use_hdr) { image->initialize_data(width, height, false, Image::FORMAT_RGBAF); @@ -2521,6 +2530,7 @@ void ProxyTexture::set_base(const Ref<Texture2D> &p_texture) { base = p_texture; if (base.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (proxy_ph.is_valid()) { RS::get_singleton()->texture_proxy_update(proxy, base->get_rid()); RS::get_singleton()->free(proxy_ph); @@ -2571,6 +2581,7 @@ ProxyTexture::ProxyTexture() { } ProxyTexture::~ProxyTexture() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); if (proxy_ph.is_valid()) { RS::get_singleton()->free(proxy_ph); } @@ -2828,6 +2839,7 @@ AnimatedTexture::AnimatedTexture() { } AnimatedTexture::~AnimatedTexture() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(proxy); RS::get_singleton()->free(proxy_ph); } @@ -3031,6 +3043,7 @@ ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) { ImageTextureLayered::~ImageTextureLayered() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(texture); } } @@ -3198,6 +3211,7 @@ CompressedTextureLayered::CompressedTextureLayered(LayeredType p_type) { CompressedTextureLayered::~CompressedTextureLayered() { if (texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(texture); } } @@ -3353,6 +3367,7 @@ CameraTexture::CameraTexture() {} CameraTexture::~CameraTexture() { if (_texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(_texture); } } @@ -3394,6 +3409,7 @@ PlaceholderTexture2D::PlaceholderTexture2D() { } PlaceholderTexture2D::~PlaceholderTexture2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(rid); } @@ -3441,6 +3457,7 @@ PlaceholderTexture3D::PlaceholderTexture3D() { rid = RS::get_singleton()->texture_3d_placeholder_create(); } PlaceholderTexture3D::~PlaceholderTexture3D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(rid); } @@ -3499,5 +3516,6 @@ PlaceholderTextureLayered::PlaceholderTextureLayered(LayeredType p_type) { rid = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type)); } PlaceholderTextureLayered::~PlaceholderTextureLayered() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(rid); } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 6b8f8097a8..fc2366a78c 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -2650,6 +2650,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom0", "CUSTOM0" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom1", "CUSTOM1" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom2", "CUSTOM2" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "custom3", "CUSTOM3" }, // Node3D, Fragment { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" }, diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 75deb1e60b..85ce47f06c 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -89,6 +89,9 @@ World2D::World2D() { } World2D::~World2D() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + ERR_FAIL_NULL(PhysicsServer2D::get_singleton()); + ERR_FAIL_NULL(NavigationServer2D::get_singleton()); RenderingServer::get_singleton()->free(canvas); PhysicsServer2D::get_singleton()->free(space); NavigationServer2D::get_singleton()->free(navigation_map); diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index ae8c9a182f..8808da95d7 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -157,6 +157,9 @@ World3D::World3D() { } World3D::~World3D() { + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); + ERR_FAIL_NULL(RenderingServer::get_singleton()); + ERR_FAIL_NULL(NavigationServer3D::get_singleton()); PhysicsServer3D::get_singleton()->free(space); RenderingServer::get_singleton()->free(scenario); NavigationServer3D::get_singleton()->free(navigation_map); diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp index 624c06ecf1..e5b160ae27 100644 --- a/servers/camera/camera_feed.cpp +++ b/servers/camera/camera_feed.cpp @@ -165,6 +165,7 @@ CameraFeed::CameraFeed(String p_name, FeedPosition p_position) { CameraFeed::~CameraFeed() { // Free our textures + ERR_FAIL_NULL(RenderingServer::get_singleton()); RenderingServer::get_singleton()->free(texture[CameraServer::FEED_Y_IMAGE]); RenderingServer::get_singleton()->free(texture[CameraServer::FEED_CBCR_IMAGE]); } diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 523cc714f0..68d625b083 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -379,7 +379,7 @@ bool DisplayServer::screen_is_kept_on() const { return false; } -DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server."); } diff --git a/servers/display_server.h b/servers/display_server.h index 4c36b0acb9..67e7a82e25 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -312,7 +312,7 @@ public: WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE), }; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0); virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index 94b5f3c1e9..c4f6c7f165 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -66,7 +66,7 @@ public: Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); } - WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override { return 0; } + WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override { return 0; } void show_window(WindowID p_id) override {} void delete_sub_window(WindowID p_id) override {} diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp index ca76a819ec..47f767425b 100644 --- a/servers/physics_3d/godot_collision_solver_3d.cpp +++ b/servers/physics_3d/godot_collision_solver_3d.cpp @@ -513,10 +513,6 @@ bool GodotCollisionSolver3D::solve_distance_world_boundary(const GodotShape3D *p } bool GodotCollisionSolver3D::solve_distance(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis) { - if (p_shape_A->is_concave()) { - return false; - } - if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { Vector3 a, b; bool col = solve_distance_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b); diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index c98409e2c4..813970848a 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -992,6 +992,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: Vector3 rel_vec = result.contact - (body->get_transform().origin + body->get_center_of_mass()); collision.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec); + collision.collider_angular_velocity = body->get_angular_velocity(); } r_result->travel = safe * p_parameters.motion; diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 20f23ae031..bd4512a3d5 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -772,6 +772,9 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("joint_make_groove", "joint", "groove1_a", "groove2_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_groove, DEFVAL(RID()), DEFVAL(RID())); ClassDB::bind_method(D_METHOD("joint_make_damped_spring", "joint", "anchor_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_damped_spring, DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("pin_joint_set_param", "joint", "param", "value"), &PhysicsServer2D::pin_joint_set_param); + ClassDB::bind_method(D_METHOD("pin_joint_get_param", "joint", "param"), &PhysicsServer2D::pin_joint_get_param); + ClassDB::bind_method(D_METHOD("damped_spring_joint_set_param", "joint", "param", "value"), &PhysicsServer2D::damped_spring_joint_set_param); ClassDB::bind_method(D_METHOD("damped_spring_joint_get_param", "joint", "param"), &PhysicsServer2D::damped_spring_joint_get_param); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index ca1ff57c99..922baad663 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -541,6 +541,7 @@ public: Vector3 position; Vector3 normal; Vector3 collider_velocity; + Vector3 collider_angular_velocity; real_t depth = 0.0; int local_shape = 0; ObjectID collider_id; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 5b465fb45c..bcee7315c8 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -3465,7 +3465,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED) { //material is only meant for alpha pass flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; - if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED)) { + if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED)) { flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; } @@ -3481,7 +3481,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet SceneShaderForwardClustered::MaterialData *material_shadow = nullptr; void *surface_shadow = nullptr; - if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size) { + if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; material_shadow = static_cast<SceneShaderForwardClustered::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D)); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 914ca25899..9074a23472 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -61,7 +61,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uses_alpha = false; uses_alpha_clip = false; uses_blend_alpha = false; - uses_depth_pre_pass = false; + uses_depth_prepass_alpha = false; uses_discard = false; uses_roughness = false; uses_normal = false; @@ -114,7 +114,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { // Use alpha clip pipeline for alpha hash/dither. // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows. actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip; - actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; + actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_prepass_alpha; actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; @@ -309,10 +309,11 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { } RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; - if (depth_pre_pass_enabled && casts_shadows()) { + if (depth_pre_pass_enabled && casts_shadows() && !uses_depth_prepass_alpha) { // We already have a depth from the depth pre-pass, there is no need to write it again. // In addition we can use COMPARE_OP_EQUAL instead of COMPARE_OP_LESS_OR_EQUAL. // This way we can use the early depth test to discard transparent fragments before the fragment shader even starts. + // This cannot be used with depth_prepass_alpha as it uses a different threshold during the depth-prepass and regular drawing. depth_stencil.depth_compare_operator = RD::COMPARE_OP_EQUAL; depth_stencil.enable_depth_write = false; } @@ -394,7 +395,7 @@ bool SceneShaderForwardClustered::ShaderData::casts_shadows() const { bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha; bool has_alpha = has_base_alpha || uses_blend_alpha; - return !has_alpha || (uses_depth_pre_pass && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED)); + return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED)); } RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const { diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 51e4dd44d5..367f44f50c 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -153,7 +153,7 @@ public: bool uses_alpha = false; bool uses_blend_alpha = false; bool uses_alpha_clip = false; - bool uses_depth_pre_pass = false; + bool uses_depth_prepass_alpha = false; bool uses_discard = false; bool uses_roughness = false; bool uses_normal = false; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 53bcb1c038..7904ea0527 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2378,7 +2378,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED) { //material is only meant for alpha pass flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; - if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) { + if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) { flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; } @@ -2394,7 +2394,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI SceneShaderForwardMobile::MaterialData *material_shadow = nullptr; void *surface_shadow = nullptr; - if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip) { + if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D)); diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 224bb34189..543b1e29f9 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -63,7 +63,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uses_alpha = false; uses_alpha_clip = false; uses_blend_alpha = false; - uses_depth_pre_pass = false; + uses_depth_prepass_alpha = false; uses_discard = false; uses_roughness = false; uses_normal = false; @@ -115,7 +115,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { // Use alpha clip pipeline for alpha hash/dither. // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows. actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip; - actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; + actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_prepass_alpha; // actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; // actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; @@ -341,7 +341,7 @@ bool SceneShaderForwardMobile::ShaderData::casts_shadows() const { bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha; bool has_alpha = has_base_alpha || uses_blend_alpha; - return !has_alpha || (uses_depth_pre_pass && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED)); + return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED)); } RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const { diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 18a897a9e9..f90acf0247 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -114,7 +114,7 @@ public: bool uses_alpha = false; bool uses_blend_alpha = false; bool uses_alpha_clip = false; - bool uses_depth_pre_pass = false; + bool uses_depth_prepass_alpha = false; bool uses_discard = false; bool uses_roughness = false; bool uses_normal = false; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 675e81c62a..58cbdd0be7 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -833,6 +833,10 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); + if (instance->layer_mask == p_mask) { + return; + } + instance->layer_mask = p_mask; if (instance->scenario && instance->array_index >= 0) { instance->scenario->instance_data[instance->array_index].layer_mask = p_mask; @@ -842,6 +846,13 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); geom->geometry_instance->set_layer_mask(p_mask); + + if (geom->can_cast_shadows) { + for (HashSet<RendererSceneCull::Instance *>::Iterator I = geom->lights.begin(); I != geom->lights.end(); ++I) { + InstanceLightData *light = static_cast<InstanceLightData *>((*I)->base_data); + light->shadow_dirty = true; + } + } } } @@ -2253,7 +2264,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in } } -bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_mesh_lod_threshold) { +bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_mesh_lod_threshold, uint32_t p_visible_layers) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); Transform3D light_transform = p_instance->transform; @@ -2309,7 +2320,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { continue; } else { if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { @@ -2387,7 +2398,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { continue; } else { if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { @@ -2450,7 +2461,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) { continue; } else { if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { @@ -2891,7 +2902,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul if (IN_FRUSTUM(cull_data.cull->shadows[j].cascades[k].frustum) && VIS_CHECK) { uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; - if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) { + if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS && LAYER_CHECK) { cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); mesh_visible = true; } @@ -3218,7 +3229,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) { //must redraw! RENDER_TIMESTAMP("> Render Light3D " + itos(i)); - light->shadow_dirty = _light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_mesh_lod_threshold); + light->shadow_dirty = _light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_mesh_lod_threshold, p_visible_layers); RENDER_TIMESTAMP("< Render Light3D " + itos(i)); } else { light->shadow_dirty = redraw; diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 106871edfd..4a55d9ba55 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -988,7 +988,7 @@ public: void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect); - _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_mesh_lod_threshold); + _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_mesh_lod_threshold, uint32_t p_visible_layers = 0xFFFFFF); RID _render_get_environment(RID p_camera, RID p_scenario); diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp index e1ca5a7103..627e6941cf 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.cpp +++ b/servers/rendering/renderer_scene_occlusion_cull.cpp @@ -60,6 +60,8 @@ void RendererSceneOcclusionCull::HZBuffer::clear() { if (debug_image.is_valid()) { debug_image.unref(); } + + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(debug_texture); } diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index ec4ae98397..b437ed1512 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -123,6 +123,7 @@ XRInterface::XRInterface() {} XRInterface::~XRInterface() { if (vrs.vrs_texture.is_valid()) { + ERR_FAIL_NULL(RenderingServer::get_singleton()); RS::get_singleton()->free(vrs.vrs_texture); vrs.vrs_texture = RID(); } diff --git a/tests/core/object/test_object.h b/tests/core/object/test_object.h index f5c5de7fdf..5feb3a4054 100644 --- a/tests/core/object/test_object.h +++ b/tests/core/object/test_object.h @@ -281,6 +281,84 @@ TEST_CASE("[Object] Absent name getter") { actual_value == Variant(), "The returned value should equal nil variant."); } + +TEST_CASE("[Object] Signals") { + Object object; + + CHECK_FALSE(object.has_signal("my_custom_signal")); + + List<MethodInfo> signals_before; + object.get_signal_list(&signals_before); + + object.add_user_signal(MethodInfo("my_custom_signal")); + + CHECK(object.has_signal("my_custom_signal")); + + List<MethodInfo> signals_after; + object.get_signal_list(&signals_after); + + // Should be one more signal. + CHECK_EQ(signals_before.size() + 1, signals_after.size()); + + SUBCASE("Adding the same user signal again should not have any effect") { + CHECK(object.has_signal("my_custom_signal")); + ERR_PRINT_OFF; + object.add_user_signal(MethodInfo("my_custom_signal")); + ERR_PRINT_ON; + CHECK(object.has_signal("my_custom_signal")); + + List<MethodInfo> signals_after_existing_added; + object.get_signal_list(&signals_after_existing_added); + + CHECK_EQ(signals_after.size(), signals_after_existing_added.size()); + } + + SUBCASE("Trying to add a preexisting signal should not have any effect") { + CHECK(object.has_signal("script_changed")); + ERR_PRINT_OFF; + object.add_user_signal(MethodInfo("script_changed")); + ERR_PRINT_ON; + CHECK(object.has_signal("script_changed")); + + List<MethodInfo> signals_after_existing_added; + object.get_signal_list(&signals_after_existing_added); + + CHECK_EQ(signals_after.size(), signals_after_existing_added.size()); + } + + SUBCASE("Adding an empty signal should not have any effect") { + CHECK_FALSE(object.has_signal("")); + ERR_PRINT_OFF; + object.add_user_signal(MethodInfo("")); + ERR_PRINT_ON; + CHECK_FALSE(object.has_signal("")); + + List<MethodInfo> signals_after_empty_added; + object.get_signal_list(&signals_after_empty_added); + + CHECK_EQ(signals_after.size(), signals_after_empty_added.size()); + } + + SUBCASE("Emitting a non existing signal will return an error") { + Error err = object.emit_signal("some_signal"); + CHECK(err == ERR_UNAVAILABLE); + } + + SUBCASE("Emitting an existing signal should call the connected method") { + Array empty_signal_args; + empty_signal_args.push_back(Array()); + + SIGNAL_WATCH(&object, "my_custom_signal"); + SIGNAL_CHECK_FALSE("my_custom_signal"); + + Error err = object.emit_signal("my_custom_signal"); + CHECK(err == OK); + + SIGNAL_CHECK("my_custom_signal", empty_signal_args); + SIGNAL_UNWATCH(&object, "my_custom_signal"); + } +} + } // namespace TestObject #endif // TEST_OBJECT_H diff --git a/tests/core/test_time.h b/tests/core/test_time.h index 177512c832..ae3d624fe8 100644 --- a/tests/core/test_time.h +++ b/tests/core/test_time.h @@ -91,7 +91,7 @@ TEST_CASE("[Time] Datetime dictionary conversion methods") { datetime[YEAR_KEY] = 2014; datetime[MONTH_KEY] = 2; datetime[DAY_KEY] = 9; - datetime[WEEKDAY_KEY] = Time::Weekday::WEEKDAY_SUNDAY; + datetime[WEEKDAY_KEY] = Weekday::WEEKDAY_SUNDAY; datetime[HOUR_KEY] = 22; datetime[MINUTE_KEY] = 10; datetime[SECOND_KEY] = 30; @@ -100,7 +100,7 @@ TEST_CASE("[Time] Datetime dictionary conversion methods") { date_only[YEAR_KEY] = 2014; date_only[MONTH_KEY] = 2; date_only[DAY_KEY] = 9; - date_only[WEEKDAY_KEY] = Time::Weekday::WEEKDAY_SUNDAY; + date_only[WEEKDAY_KEY] = Weekday::WEEKDAY_SUNDAY; Dictionary time_only; time_only[HOUR_KEY] = 22; @@ -115,8 +115,8 @@ TEST_CASE("[Time] Datetime dictionary conversion methods") { CHECK_MESSAGE(time->get_date_dict_from_unix_time(1391904000).hash() == date_only.hash(), "Time get_date_dict_from_unix_time: The date timestamp for GODOT IS OPEN SOURCE is converted to a dictionary as expected."); CHECK_MESSAGE(time->get_time_dict_from_unix_time(79830).hash() == time_only.hash(), "Time get_time_dict_from_unix_time: The time timestamp for GODOT IS OPEN SOURCE is converted to a dictionary as expected."); - CHECK_MESSAGE((Time::Weekday)(int)time->get_datetime_dict_from_unix_time(0)[WEEKDAY_KEY] == Time::Weekday::WEEKDAY_THURSDAY, "Time get_datetime_dict_from_unix_time: The weekday for the Unix epoch is a Thursday as expected."); - CHECK_MESSAGE((Time::Weekday)(int)time->get_datetime_dict_from_unix_time(1391983830)[WEEKDAY_KEY] == Time::Weekday::WEEKDAY_SUNDAY, "Time get_datetime_dict_from_unix_time: The weekday for GODOT IS OPEN SOURCE is a Sunday as expected."); + CHECK_MESSAGE((Weekday)(int)time->get_datetime_dict_from_unix_time(0)[WEEKDAY_KEY] == Weekday::WEEKDAY_THURSDAY, "Time get_datetime_dict_from_unix_time: The weekday for the Unix epoch is a Thursday as expected."); + CHECK_MESSAGE((Weekday)(int)time->get_datetime_dict_from_unix_time(1391983830)[WEEKDAY_KEY] == Weekday::WEEKDAY_SUNDAY, "Time get_datetime_dict_from_unix_time: The weekday for GODOT IS OPEN SOURCE is a Sunday as expected."); CHECK_MESSAGE(time->get_datetime_dict_from_datetime_string("2014-02-09T22:10:30").hash() == datetime.hash(), "Time get_datetime_dict_from_string: The dictionary from string for GODOT IS OPEN SOURCE works as expected."); CHECK_MESSAGE(!time->get_datetime_dict_from_datetime_string("2014-02-09T22:10:30", false).has(WEEKDAY_KEY), "Time get_datetime_dict_from_string: The dictionary from string for GODOT IS OPEN SOURCE without weekday doesn't contain the weekday key as expected."); diff --git a/tests/scene/test_gradient.h b/tests/scene/test_gradient.h index b0e6128932..6049abbec2 100644 --- a/tests/scene/test_gradient.h +++ b/tests/scene/test_gradient.h @@ -42,7 +42,7 @@ TEST_CASE("[Gradient] Default gradient") { Ref<Gradient> gradient = memnew(Gradient); CHECK_MESSAGE( - gradient->get_points_count() == 2, + gradient->get_point_count() == 2, "Default gradient should contain the expected number of points."); CHECK_MESSAGE( @@ -77,7 +77,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified in order)") { gradient->set_points(points); CHECK_MESSAGE( - gradient->get_points_count() == 3, + gradient->get_point_count() == 3, "Custom gradient should contain the expected number of points."); CHECK_MESSAGE( @@ -98,7 +98,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified in order)") { gradient->remove_point(1); CHECK_MESSAGE( - gradient->get_points_count() == 2, + gradient->get_point_count() == 2, "Custom gradient should contain the expected number of points after removing one point."); CHECK_MESSAGE( gradient->get_color_at_offset(0.5).is_equal_approx(Color(0.5, 1, 0)), @@ -119,7 +119,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified out-of-order)") { gradient->set_points(points); CHECK_MESSAGE( - gradient->get_points_count() == 6, + gradient->get_point_count() == 6, "Custom out-of-order gradient should contain the expected number of points."); CHECK_MESSAGE( @@ -137,7 +137,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified out-of-order)") { gradient->remove_point(0); CHECK_MESSAGE( - gradient->get_points_count() == 5, + gradient->get_point_count() == 5, "Custom out-of-order gradient should contain the expected number of points after removing one point."); // The color will be clamped to the nearest point (which is at offset 0.2). CHECK_MESSAGE( diff --git a/tests/scene/test_node.h b/tests/scene/test_node.h new file mode 100644 index 0000000000..68ec41f07a --- /dev/null +++ b/tests/scene/test_node.h @@ -0,0 +1,415 @@ +/*************************************************************************/ +/* test_node.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_NODE_H +#define TEST_NODE_H + +#include "scene/main/node.h" + +#include "tests/test_macros.h" + +namespace TestNode { + +TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") { + Node *node = memnew(Node); + + // Check initial scene tree setup. + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 0); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 1); + + // Check initial node setup. + CHECK(node->get_name() == StringName()); + CHECK_FALSE(node->is_inside_tree()); + CHECK_EQ(node->get_parent(), nullptr); + ERR_PRINT_OFF; + CHECK(node->get_path().is_empty()); + ERR_PRINT_ON; + CHECK_EQ(node->get_child_count(), 0); + + SceneTree::get_singleton()->get_root()->add_child(node); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 2); + + CHECK(node->get_name() != StringName()); + CHECK(node->is_inside_tree()); + CHECK_EQ(SceneTree::get_singleton()->get_root(), node->get_parent()); + CHECK_FALSE(node->get_path().is_empty()); + CHECK_EQ(node->get_child_count(), 0); + + SUBCASE("Node should be accessible as first child") { + Node *child = SceneTree::get_singleton()->get_root()->get_child(0); + CHECK_EQ(child, node); + } + + SUBCASE("Node should be accessible via the node path") { + Node *child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node->get_path()); + CHECK_EQ(child_by_path, node); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node")); + CHECK_EQ(child_by_path, nullptr); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node")); + CHECK_EQ(child_by_path, nullptr); + + node->set_name("Node"); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node->get_path()); + CHECK_EQ(child_by_path, node); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node")); + CHECK_EQ(child_by_path, node); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node")); + CHECK_EQ(child_by_path, node); + } + + SUBCASE("Node should be accessible via group") { + List<Node *> nodes; + SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes); + CHECK(nodes.is_empty()); + + node->add_to_group("nodes"); + + SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes); + CHECK_EQ(nodes.size(), 1); + List<Node *>::Element *E = nodes.front(); + CHECK_EQ(E->get(), node); + } + + SUBCASE("Node should be possible to find") { + Node *child = SceneTree::get_singleton()->get_root()->find_child("Node", true, false); + CHECK_EQ(child, nullptr); + + node->set_name("Node"); + + child = SceneTree::get_singleton()->get_root()->find_child("Node", true, false); + CHECK_EQ(child, node); + } + + SUBCASE("Node should be possible to remove") { + SceneTree::get_singleton()->get_root()->remove_child(node); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 0); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 1); + + CHECK_FALSE(node->is_inside_tree()); + CHECK_EQ(node->get_parent(), nullptr); + ERR_PRINT_OFF; + CHECK(node->get_path().is_empty()); + ERR_PRINT_ON; + } + + SUBCASE("Node should be possible to move") { + SceneTree::get_singleton()->get_root()->move_child(node, 0); + + Node *child = SceneTree::get_singleton()->get_root()->get_child(0); + CHECK_EQ(child, node); + CHECK(node->is_inside_tree()); + } + + memdelete(node); +} + +TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") { + Node *node1 = memnew(Node); + Node *node2 = memnew(Node); + Node *node1_1 = memnew(Node); + + SceneTree::get_singleton()->get_root()->add_child(node1); + SceneTree::get_singleton()->get_root()->add_child(node2); + + node1->add_child(node1_1); + + CHECK(node1_1->is_inside_tree()); + CHECK_EQ(node1_1->get_parent(), node1); + CHECK_EQ(node1->get_child_count(), 1); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4); + + SUBCASE("Nodes should be accessible via get_child(..)") { + Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0); + CHECK_EQ(child1, node1); + + Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1); + CHECK_EQ(child2, node2); + + Node *child1_1 = node1->get_child(0); + CHECK_EQ(child1_1, node1_1); + } + + SUBCASE("Removed nodes should also remove their children from the scene tree") { + // Should also remove node1_1 from the scene tree. + SceneTree::get_singleton()->get_root()->remove_child(node1); + + CHECK_EQ(node1->get_child_count(), 1); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 2); + + // First child should now be the second node. + Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0); + CHECK_EQ(child1, node2); + } + + SUBCASE("Removed children nodes should not affect their parent in the scene tree") { + node1->remove_child(node1_1); + + CHECK_EQ(node1_1->get_parent(), nullptr); + CHECK_EQ(node1->get_child_count(), 0); + + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 3); + } + + SUBCASE("Nodes should be in the expected order when a node is moved to the back") { + SceneTree::get_singleton()->get_root()->move_child(node1, 1); + + Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0); + CHECK_EQ(child1, node2); + + Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1); + CHECK_EQ(child2, node1); + } + + SUBCASE("Nodes should be in the expected order when a node is moved to the front") { + SceneTree::get_singleton()->get_root()->move_child(node2, 0); + + Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0); + CHECK_EQ(child1, node2); + + Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1); + CHECK_EQ(child2, node1); + } + + SUBCASE("Nodes should be in the expected order when reparented") { + CHECK_EQ(node2->get_child_count(), 0); + + node1->remove_child(node1_1); + CHECK_EQ(node1->get_child_count(), 0); + CHECK_EQ(node1_1->get_parent(), nullptr); + + node2->add_child(node1_1); + CHECK_EQ(node2->get_child_count(), 1); + CHECK_EQ(node1_1->get_parent(), node2); + + Node *child = node2->get_child(0); + CHECK_EQ(child, node1_1); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4); + } + + SUBCASE("Nodes should be possible to find") { + Node *child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false); + CHECK_EQ(child, nullptr); + + node1->set_name("Node1"); + node2->set_name("Node2"); + node1_1->set_name("NestedNode"); + + child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false); + CHECK_EQ(child, node1_1); + + // First node that matches with the name is node1. + child = SceneTree::get_singleton()->get_root()->find_child("Node?", true, false); + CHECK_EQ(child, node1); + + SceneTree::get_singleton()->get_root()->move_child(node2, 0); + + // It should be node2, as it is now the first one in the tree. + child = SceneTree::get_singleton()->get_root()->find_child("Node?", true, false); + CHECK_EQ(child, node2); + } + + SUBCASE("Nodes should be accessible via their node path") { + Node *child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node1->get_path()); + CHECK_EQ(child_by_path, node1); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node2->get_path()); + CHECK_EQ(child_by_path, node2); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node1_1->get_path()); + CHECK_EQ(child_by_path, node1_1); + + node1->set_name("Node1"); + node1_1->set_name("NestedNode"); + + child_by_path = node1->get_node_or_null(NodePath("NestedNode")); + CHECK_EQ(child_by_path, node1_1); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node1/NestedNode")); + CHECK_EQ(child_by_path, node1_1); + + child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node1/NestedNode")); + CHECK_EQ(child_by_path, node1_1); + } + + SUBCASE("Nodes should be accessible via their groups") { + List<Node *> nodes; + SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes); + CHECK(nodes.is_empty()); + + SceneTree::get_singleton()->get_nodes_in_group("other_nodes", &nodes); + CHECK(nodes.is_empty()); + + node1->add_to_group("nodes"); + node2->add_to_group("other_nodes"); + node1_1->add_to_group("nodes"); + node1_1->add_to_group("other_nodes"); + + SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes); + CHECK_EQ(nodes.size(), 2); + + List<Node *>::Element *E = nodes.front(); + CHECK_EQ(E->get(), node1); + E = E->next(); + CHECK_EQ(E->get(), node1_1); + + // Clear and try again with the other group. + nodes.clear(); + + SceneTree::get_singleton()->get_nodes_in_group("other_nodes", &nodes); + CHECK_EQ(nodes.size(), 2); + + E = nodes.front(); + CHECK_EQ(E->get(), node1_1); + E = E->next(); + CHECK_EQ(E->get(), node2); + + // Clear and try again with the other group and one node removed. + nodes.clear(); + + node1->remove_from_group("nodes"); + SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes); + CHECK_EQ(nodes.size(), 1); + + E = nodes.front(); + CHECK_EQ(E->get(), node1_1); + } + + memdelete(node1_1); + memdelete(node1); + memdelete(node2); +} + +TEST_CASE("[Node] Processing") { + Node *node = memnew(Node); + + SUBCASE("Processing") { + CHECK_FALSE(node->is_processing()); + + node->set_process(true); + + CHECK(node->is_processing()); + + node->set_process(false); + + CHECK_FALSE(node->is_processing()); + } + + SUBCASE("Physics processing") { + CHECK_FALSE(node->is_physics_processing()); + + node->set_physics_process(true); + + CHECK(node->is_physics_processing()); + + node->set_physics_process(false); + + CHECK_FALSE(node->is_physics_processing()); + } + + SUBCASE("Unhandled input processing") { + CHECK_FALSE(node->is_processing_unhandled_input()); + + node->set_process_unhandled_input(true); + + CHECK(node->is_processing_unhandled_input()); + + node->set_process_unhandled_input(false); + + CHECK_FALSE(node->is_processing_unhandled_input()); + } + + SUBCASE("Input processing") { + CHECK_FALSE(node->is_processing_input()); + + node->set_process_input(true); + + CHECK(node->is_processing_input()); + + node->set_process_input(false); + + CHECK_FALSE(node->is_processing_input()); + } + + SUBCASE("Unhandled key input processing") { + CHECK_FALSE(node->is_processing_unhandled_key_input()); + + node->set_process_unhandled_key_input(true); + + CHECK(node->is_processing_unhandled_key_input()); + + node->set_process_unhandled_key_input(false); + + CHECK_FALSE(node->is_processing_unhandled_key_input()); + } + + SUBCASE("Shortcut input processing") { + CHECK_FALSE(node->is_processing_shortcut_input()); + + node->set_process_shortcut_input(true); + + CHECK(node->is_processing_shortcut_input()); + + node->set_process_shortcut_input(false); + + CHECK_FALSE(node->is_processing_shortcut_input()); + } + + SUBCASE("Internal processing") { + CHECK_FALSE(node->is_processing_internal()); + + node->set_process_internal(true); + + CHECK(node->is_processing_internal()); + + node->set_process_internal(false); + + CHECK_FALSE(node->is_processing_internal()); + } + + memdelete(node); +} + +} // namespace TestNode + +#endif // TEST_NODE_H diff --git a/tests/test_main.cpp b/tests/test_main.cpp index f51d7c8e4d..3ef8e2de6f 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -92,6 +92,7 @@ #include "tests/scene/test_code_edit.h" #include "tests/scene/test_curve.h" #include "tests/scene/test_gradient.h" +#include "tests/scene/test_node.h" #include "tests/scene/test_path_2d.h" #include "tests/scene/test_path_3d.h" #include "tests/scene/test_primitives.h" |