Compare commits

...

33 commits

Author SHA1 Message Date
Thaddeus Crews
16a11ac88b
Merge pull request #111358 from Ivorforce/no-variant-hasher
Remove `VariantHasher` and `VariantComparator` in favour of specialising `HashMapHasherDefault` and `HashMapComparatorDefault`.
2025-10-10 10:26:12 -05:00
Thaddeus Crews
3e1af9a12a
Merge pull request #109021 from KoBeWi/visual_code
Don't save code property of VisualShader
2025-10-10 10:26:11 -05:00
Thaddeus Crews
e33f89fe27
Merge pull request #111323 from HolonProduction/rm-script
Remove `Object::script`
2025-10-10 10:26:09 -05:00
Thaddeus Crews
d10eca9c59
Merge pull request #111448 from Giganzo/sprite-frames-editor-shortcut-name
Use Title Case for shortcut names in SpriteFramesEditorPlugin
2025-10-10 10:26:08 -05:00
Thaddeus Crews
edcbdc5706
Merge pull request #107573 from lodetrick/tilemap-hide-overlay
Fade TileMap editor overlay when zoomed out
2025-10-10 10:26:07 -05:00
Thaddeus Crews
89ce203427
Merge pull request #106997 from Ivorforce/fixed-move-semantics
Fix `FixedVector` move and copy semantics.
2025-10-10 10:26:06 -05:00
Thaddeus Crews
99ab454a64
Merge pull request #111473 from KoBeWi/easing-i18n-redux
Fix some easing presets not translated
2025-10-10 10:26:04 -05:00
Thaddeus Crews
c417769226
Merge pull request #111470 from Ivorforce/debug-circular-include
Remove circular unneeded `debug_adapter_protocol.h` include from `debug_adapter_parser.h`
2025-10-10 10:26:03 -05:00
Thaddeus Crews
4ea49aecaf
Merge pull request #110990 from timothyqiu/x11-min-max
X11: Fix minimization of maximized windows
2025-10-10 10:26:02 -05:00
Thaddeus Crews
d4a87d9bb3
Merge pull request #106636 from Ivorforce/dictionary-mutating-fix
Fix `Dictionary::operator[]` from C++ accidentally modifying `const` dictionaries.
2025-10-10 10:26:01 -05:00
Thaddeus Crews
8150cb9200
Merge pull request #111403 from AeioMuch/fix_double_precision_wrong_indexes
Fix wrong indices used for transform & UBO matrix for double precision build
2025-10-10 10:25:59 -05:00
Thaddeus Crews
d598753c1a
Merge pull request #111466 from BastiaanOlij/fix_gles3_lightmap_uv2_attrib
Ensure uv2_attrib(_input) is available when rendering lightmap.
2025-10-10 10:25:58 -05:00
Thaddeus Crews
dd3b17de88
Merge pull request #105449 from raulsntos/MissingNode/recording_signals
Add `recording_signals` to MissingNode, and rename `MTVIRTUAL` to `DEBUG_VIRTUAL`
2025-10-10 10:25:57 -05:00
Thaddeus Crews
cf9e2ea6da
Merge pull request #111432 from zorbathut/pr/libgodot_linux_fix
Fix LibGodot build errors on Linux.
2025-10-10 10:25:56 -05:00
Thaddeus Crews
21e5b41642
Merge pull request #108837 from aaronfranke/json-handle-nan-inf
Handle NaN and Infinity in JSON stringify function
2025-10-10 10:25:55 -05:00
Thaddeus Crews
fb01d80e88
Merge pull request #111393 from xuhuisheng/dev/auto_expand_selected
Should expand root when `auto_expand` is on
2025-10-10 10:25:53 -05:00
kobewi
b9f7f2d767 Fix some easing presets not translated
Co-authored-by: Haoyu Qiu <timothyqiu32@gmail.com>
2025-10-10 13:21:56 +02:00
Ben Rog-Wilhelm
0a584250ae Fix: Libgodot build on Linux. 2025-10-10 04:31:14 -05:00
Lukas Tenbrink
56abd0ece3 Remove circular unneeded debug_adapter_protocol.h include from debug_adapter_parser.h. 2025-10-10 10:40:47 +02:00
Bastiaan Olij
3a003b2d96 Ensure uv2_attrib(_input) is available when rendering lightmap. 2025-10-10 14:17:34 +11:00
Raul Santos
09ad9e535b
Rename MTVIRTUAL to DEBUG_VIRTUAL 2025-10-09 22:11:18 +02:00
Raul Santos
fdecca2f18
Add recording_signals to MissingNode
Allows connecting unknown signals to MissingNode so they aren't lost when the Node type is missing.
2025-10-09 22:08:59 +02:00
AeioMuch
dae2122388 Fix wrong indexes for double precision 2025-10-09 22:01:41 +02:00
Giganzo
3a3894e22c Use Title Case for shortcut names in SpriteFramesEditorPlugin 2025-10-09 12:04:03 +02:00
xuhuisheng
4ba09aceb9 should expand root when auto_expand is on 2025-10-08 13:19:23 +08:00
Lukas Tenbrink
d2ee378d1c Remove VariantHasher and VariantComparator in favour of specializing HashMapHasherDefault and HashMapComparatorDefault. 2025-10-07 13:47:39 +02:00
HolonProduction
2adecffbc3 Remove Object::script 2025-10-06 16:27:53 +02:00
Logan Detrick
c3fdc85d16 Hide TileMap overlay when too zoomed out 2025-09-30 16:03:16 -07:00
Haoyu Qiu
12f8c78231 X11: Fix minimization of maximized windows 2025-09-28 12:19:54 +08:00
Lukas Tenbrink
0be2a77156 Fix Dictionary::operator[] from C++ accidentally modifying const dictionaries.
Fix `AudioStreamWav` inserting keys into the input dictionary.
2025-09-18 21:17:42 +02:00
Aaron Franke
e90cea9250
Handle NaN and Infinity in JSON stringify function 2025-08-24 10:09:43 -07:00
kobewi
31b5375a1c Don't save code property of VisualShader 2025-07-27 14:25:02 +02:00
Lukas Tenbrink
c3476b8205 Fix FixedVector move semantics. 2025-05-31 18:22:16 +02:00
46 changed files with 504 additions and 340 deletions

View file

@ -76,6 +76,17 @@ void JSON::_stringify(String &r_result, const Variant &p_var, const String &p_in
case Variant::FLOAT: {
const double num = p_var;
// JSON does not support NaN or Infinity, so use extremely large numbers for infinity.
if (!Math::is_finite(num)) {
if (num == Math::INF) {
r_result += "1e99999";
} else if (num == -Math::INF) {
r_result += "-1e99999";
} else {
r_result += "\"NaN\"";
}
return;
}
// Only for exactly 0. If we have approximately 0 let the user decide how much
// precision they want.
if (num == double(0.0)) {

View file

@ -1047,18 +1047,8 @@ String Object::to_string() {
return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
}
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
//this function is not meant to be used in any of these ways
ERR_FAIL_COND(p_script.is_null());
ERR_FAIL_NULL(p_instance);
ERR_FAIL_COND(script_instance != nullptr || !script.is_null());
script = p_script;
script_instance = p_instance;
}
void Object::set_script(const Variant &p_script) {
if (script == p_script) {
if (get_script() == p_script) {
return;
}
@ -1068,8 +1058,6 @@ void Object::set_script(const Variant &p_script) {
ERR_FAIL_COND_MSG(s->is_abstract(), vformat("Cannot set object script. Script '%s' should not be abstract.", s->get_path()));
}
script = p_script;
if (script_instance) {
memdelete(script_instance);
script_instance = nullptr;
@ -1099,16 +1087,10 @@ void Object::set_script_instance(ScriptInstance *p_instance) {
}
script_instance = p_instance;
if (p_instance) {
script = p_instance->get_script();
} else {
script = Variant();
}
}
Variant Object::get_script() const {
return script;
return script_instance ? Variant(script_instance->get_script()) : Variant();
}
bool Object::has_meta(const StringName &p_name) const {
@ -1291,7 +1273,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
#ifdef DEBUG_ENABLED
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name);
//check in script
ERR_FAIL_COND_V_MSG(!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name), ERR_UNAVAILABLE, vformat("Can't emit non-existing signal \"%s\".", p_name));
ERR_FAIL_COND_V_MSG(!signal_is_valid && script_instance && !script_instance->get_script()->has_script_signal(p_name), ERR_UNAVAILABLE, vformat("Can't emit non-existing signal \"%s\".", p_name));
#endif
//not connected? just return
return ERR_UNAVAILABLE;
@ -1361,7 +1343,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
if (ce.error != Callable::CallError::CALL_OK) {
#ifdef DEBUG_ENABLED
if (flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (script.is_null() || !Ref<Script>(script)->is_tool())) {
if (flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (!script_instance || !script_instance->get_script()->is_tool())) {
continue;
}
#endif
@ -1465,11 +1447,8 @@ TypedArray<Dictionary> Object::_get_incoming_connections() const {
}
bool Object::has_signal(const StringName &p_name) const {
if (!script.is_null()) {
Ref<Script> scr = script;
if (scr.is_valid() && scr->has_script_signal(p_name)) {
return true;
}
if (script_instance && script_instance->get_script()->has_script_signal(p_name)) {
return true;
}
if (ClassDB::has_signal(get_class_name(), p_name)) {
@ -1486,11 +1465,8 @@ bool Object::has_signal(const StringName &p_name) const {
void Object::get_signal_list(List<MethodInfo> *p_signals) const {
OBJ_SIGNAL_LOCK
if (!script.is_null()) {
Ref<Script> scr = script;
if (scr.is_valid()) {
scr->get_script_signal_list(p_signals);
}
if (script_instance) {
script_instance->get_script()->get_script_signal_list(p_signals);
}
ClassDB::get_signal_list(get_class_name(), p_signals);
@ -1571,14 +1547,14 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui
if (!s) {
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
//check in script
if (!signal_is_valid && !script.is_null()) {
if (Ref<Script>(script)->has_script_signal(p_signal)) {
if (!signal_is_valid && script_instance) {
if (script_instance->get_script()->has_script_signal(p_signal)) {
signal_is_valid = true;
}
#ifdef TOOLS_ENABLED
else {
//allow connecting signals anyway if script is invalid, see issue #17070
if (!Ref<Script>(script)->is_valid()) {
if (!script_instance->get_script()->is_valid()) {
signal_is_valid = true;
}
}
@ -1634,7 +1610,7 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable
return false;
}
if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) {
if (script_instance && script_instance->get_script()->has_script_signal(p_signal)) {
return false;
}
@ -1654,7 +1630,7 @@ bool Object::has_connections(const StringName &p_signal) const {
return false;
}
if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) {
if (script_instance && script_instance->get_script()->has_script_signal(p_signal)) {
return false;
}
@ -1675,7 +1651,7 @@ bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
SignalData *s = signal_map.getptr(p_signal);
if (!s) {
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) ||
(!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal));
(script_instance && script_instance->get_script()->has_script_signal(p_signal));
ERR_FAIL_COND_V_MSG(signal_is_valid, false, vformat("Attempt to disconnect a nonexistent connection from '%s'. Signal: '%s', callable: '%s'.", to_string(), p_signal, p_callable));
}
ERR_FAIL_NULL_V_MSG(s, false, vformat("Disconnecting nonexistent signal '%s' in '%s'.", p_signal, to_string()));

View file

@ -670,7 +670,6 @@ private:
HashSet<String> editor_section_folding;
#endif
ScriptInstance *script_instance = nullptr;
Variant script; // Reference does not exist yet, store it in a Variant.
HashMap<StringName, Variant> metadata;
HashMap<StringName, Variant *> metadata_properties;
mutable const GDType *_gdtype_ptr = nullptr;
@ -926,22 +925,22 @@ public:
/* SCRIPT */
// When in debug, some non-virtual functions can be overridden for multithreaded guards.
// When in debug, some non-virtual functions can be overridden.
#ifdef DEBUG_ENABLED
#define MTVIRTUAL virtual
#define DEBUG_VIRTUAL virtual
#else
#define MTVIRTUAL
#define DEBUG_VIRTUAL
#endif // DEBUG_ENABLED
MTVIRTUAL void set_script(const Variant &p_script);
MTVIRTUAL Variant get_script() const;
DEBUG_VIRTUAL void set_script(const Variant &p_script);
DEBUG_VIRTUAL Variant get_script() const;
MTVIRTUAL bool has_meta(const StringName &p_name) const;
MTVIRTUAL void set_meta(const StringName &p_name, const Variant &p_value);
MTVIRTUAL void remove_meta(const StringName &p_name);
MTVIRTUAL Variant get_meta(const StringName &p_name, const Variant &p_default = Variant()) const;
MTVIRTUAL void get_meta_list(List<StringName> *p_list) const;
MTVIRTUAL void merge_meta_from(const Object *p_src);
DEBUG_VIRTUAL bool has_meta(const StringName &p_name) const;
DEBUG_VIRTUAL void set_meta(const StringName &p_name, const Variant &p_value);
DEBUG_VIRTUAL void remove_meta(const StringName &p_name);
DEBUG_VIRTUAL Variant get_meta(const StringName &p_name, const Variant &p_default = Variant()) const;
DEBUG_VIRTUAL void get_meta_list(List<StringName> *p_list) const;
DEBUG_VIRTUAL void merge_meta_from(const Object *p_src);
#ifdef TOOLS_ENABLED
void set_edited(bool p_edited);
@ -953,9 +952,6 @@ public:
void set_script_instance(ScriptInstance *p_instance);
_FORCE_INLINE_ ScriptInstance *get_script_instance() const { return script_instance; }
// Some script languages can't control instance creation, so this function eases the process.
void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance);
void add_user_signal(const MethodInfo &p_signal);
template <typename... VarArgs>
@ -968,18 +964,18 @@ public:
return emit_signalp(p_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
MTVIRTUAL Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount);
MTVIRTUAL bool has_signal(const StringName &p_name) const;
MTVIRTUAL void get_signal_list(List<MethodInfo> *p_signals) const;
MTVIRTUAL void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
MTVIRTUAL void get_all_signal_connections(List<Connection> *p_connections) const;
MTVIRTUAL int get_persistent_signal_connection_count() const;
MTVIRTUAL void get_signals_connected_to_this(List<Connection> *p_connections) const;
DEBUG_VIRTUAL Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount);
DEBUG_VIRTUAL bool has_signal(const StringName &p_name) const;
DEBUG_VIRTUAL void get_signal_list(List<MethodInfo> *p_signals) const;
DEBUG_VIRTUAL void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
DEBUG_VIRTUAL void get_all_signal_connections(List<Connection> *p_connections) const;
DEBUG_VIRTUAL int get_persistent_signal_connection_count() const;
DEBUG_VIRTUAL void get_signals_connected_to_this(List<Connection> *p_connections) const;
MTVIRTUAL Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0);
MTVIRTUAL void disconnect(const StringName &p_signal, const Callable &p_callable);
MTVIRTUAL bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
MTVIRTUAL bool has_connections(const StringName &p_signal) const;
DEBUG_VIRTUAL Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0);
DEBUG_VIRTUAL void disconnect(const StringName &p_signal, const Callable &p_callable);
DEBUG_VIRTUAL bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
DEBUG_VIRTUAL bool has_connections(const StringName &p_signal) const;
template <typename... VarArgs>
void call_deferred(const StringName &p_name, VarArgs... p_args) {

View file

@ -53,6 +53,7 @@ class FixedVector {
public:
_FORCE_INLINE_ constexpr FixedVector() = default;
constexpr FixedVector(std::initializer_list<T> p_init) {
ERR_FAIL_COND(p_init.size() > CAPACITY);
for (const T &element : p_init) {
@ -60,9 +61,7 @@ public:
}
}
template <uint32_t p_capacity>
constexpr FixedVector(const FixedVector<T, p_capacity> &p_from) {
ERR_FAIL_COND(p_from.size() > CAPACITY);
constexpr FixedVector(const FixedVector &p_from) {
if constexpr (std::is_trivially_copyable_v<T>) {
// Copy size and all provided elements at once.
memcpy((void *)&_size, (void *)&p_from._size, sizeof(_size) + DATA_PADDING + p_from.size() * sizeof(T));
@ -73,15 +72,48 @@ public:
}
}
template <uint32_t p_capacity>
constexpr FixedVector(FixedVector<T, p_capacity> &&p_from) {
ERR_FAIL_COND(p_from.size() > CAPACITY);
constexpr FixedVector(FixedVector &&p_from) {
// Copy size and all provided elements at once.
// Note: Assumes trivial relocatability.
memcpy((void *)&_size, (void *)&p_from._size, sizeof(_size) + DATA_PADDING + p_from.size() * sizeof(T));
p_from._size = 0;
}
constexpr FixedVector &operator=(const FixedVector &p_from) {
if constexpr (std::is_trivially_copyable_v<T>) {
// Copy size and all provided elements at once.
memcpy((void *)&_size, (void *)&p_from._size, sizeof(_size) + DATA_PADDING + p_from.size() * sizeof(T));
} else {
// Destruct extraneous elements.
if constexpr (!std::is_trivially_destructible_v<T>) {
for (uint32_t i = p_from.size(); i < _size; i++) {
ptr()[i].~T();
}
}
_size = 0; // Loop-assign the rest.
for (const T &element : p_from) {
ptr()[_size++] = element;
}
}
return *this;
}
constexpr FixedVector &operator=(FixedVector &&p_from) {
// Destruct extraneous elements.
if constexpr (!std::is_trivially_destructible_v<T>) {
for (uint32_t i = p_from.size(); i < _size; i++) {
ptr()[i].~T();
}
}
// Relocate elements (and size) into our buffer.
memcpy((void *)&_size, (void *)&p_from._size, sizeof(_size) + DATA_PADDING + p_from.size() * sizeof(T));
p_from._size = 0;
return *this;
}
~FixedVector() {
if constexpr (!std::is_trivially_destructible_v<T>) {
for (uint32_t i = 0; i < _size; i++) {
@ -138,6 +170,12 @@ public:
_size++;
}
constexpr void push_back(T &&p_val) {
ERR_FAIL_COND(_size >= CAPACITY);
memnew_placement(ptr() + _size, T(std::move(p_val)));
_size++;
}
constexpr void pop_back() {
ERR_FAIL_COND(_size == 0);
_size--;

View file

@ -47,7 +47,7 @@ STATIC_ASSERT_INCOMPLETE_TYPE(class, String);
struct DictionaryPrivate {
SafeRefCount refcount;
Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator> variant_map;
HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator> variant_map;
ContainerTypeValidate typed_key;
ContainerTypeValidate typed_value;
Variant *typed_fallback = nullptr; // Allows a typed dictionary to return dummy values when attempting an invalid access.
@ -131,8 +131,10 @@ const Variant &Dictionary::operator[](const Variant &p_key) const {
VariantInternal::initialize(_p->typed_fallback, _p->typed_value.type);
return *_p->typed_fallback;
} else {
// Will not insert key, so no initialization is necessary.
return _p->variant_map[key];
static Variant empty;
const Variant *value = _p->variant_map.getptr(key);
ERR_FAIL_COND_V_MSG(!value, empty, "Bug: Dictionary::operator[] used when there was no value for the given key, please report.");
return *value;
}
}
@ -141,7 +143,7 @@ const Variant *Dictionary::getptr(const Variant &p_key) const {
if (unlikely(!_p->typed_key.validate(key, "getptr"))) {
return nullptr;
}
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(key));
HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(key));
if (!E) {
return nullptr;
}
@ -154,7 +156,7 @@ Variant *Dictionary::getptr(const Variant &p_key) {
if (unlikely(!_p->typed_key.validate(key, "getptr"))) {
return nullptr;
}
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E(_p->variant_map.find(key));
HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator>::Iterator E(_p->variant_map.find(key));
if (!E) {
return nullptr;
}
@ -169,7 +171,7 @@ Variant *Dictionary::getptr(const Variant &p_key) {
Variant Dictionary::get_valid(const Variant &p_key) const {
Variant key = p_key;
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "get_valid"), Variant());
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(key));
HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator>::ConstIterator E(_p->variant_map.find(key));
if (!E) {
return Variant();
@ -278,7 +280,7 @@ bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_c
}
recursion_count++;
for (const KeyValue<Variant, Variant> &this_E : _p->variant_map) {
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator other_E(p_dictionary._p->variant_map.find(this_E.key));
HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator>::ConstIterator other_E(p_dictionary._p->variant_map.find(this_E.key));
if (!other_E || !this_E.value.hash_compare(other_E->value, recursion_count, false)) {
return false;
}
@ -436,7 +438,7 @@ void Dictionary::assign(const Dictionary &p_dictionary) {
}
int size = p_dictionary._p->variant_map.size();
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator> variant_map = HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>(size);
HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator> variant_map = HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator>(size);
Vector<Variant> key_array;
key_array.resize(size);
@ -569,7 +571,7 @@ const Variant *Dictionary::next(const Variant *p_key) const {
}
Variant key = *p_key;
ERR_FAIL_COND_V(!_p->typed_key.validate(key, "next"), nullptr);
HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::Iterator E = _p->variant_map.find(key);
HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator>::Iterator E = _p->variant_map.find(key);
if (!E) {
return nullptr;

View file

@ -42,7 +42,6 @@ struct ContainerType;
struct ContainerTypeValidate;
struct DictionaryPrivate;
struct StringLikeVariantComparator;
struct VariantHasher;
class Dictionary {
mutable DictionaryPrivate *_p;
@ -51,7 +50,7 @@ class Dictionary {
void _unref() const;
public:
using ConstIterator = HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator;
using ConstIterator = HashMap<Variant, Variant, HashMapHasherDefault, StringLikeVariantComparator>::ConstIterator;
ConstIterator begin() const;
ConstIterator end() const;

View file

@ -884,12 +884,9 @@ Vector<Variant> varray(VarArgs... p_args) {
return Vector<Variant>{ p_args... };
}
struct VariantHasher {
static _FORCE_INLINE_ uint32_t hash(const Variant &p_variant) { return p_variant.hash(); }
};
struct VariantComparator {
static _FORCE_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); }
template <>
struct HashMapComparatorDefault<Variant> {
static bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); }
};
struct StringLikeVariantComparator {

View file

@ -19,5 +19,8 @@
<member name="recording_properties" type="bool" setter="set_recording_properties" getter="is_recording_properties">
If [code]true[/code], allows new properties to be set along with existing ones. If [code]false[/code], only existing properties' values can be set, and new properties cannot be added.
</member>
<member name="recording_signals" type="bool" setter="set_recording_signals" getter="is_recording_signals">
If [code]true[/code], allows new signals to be connected to along with existing ones. If [code]false[/code], only existing signals can be connected to, and new signals cannot be added.
</member>
</members>
</class>

View file

@ -560,7 +560,7 @@ void vertex_shader(vec4 vertex_angle_attrib_input,
#if defined(UV_USED)
vec2 uv_attrib_input,
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(RENDER_MATERIAL)
vec2 uv2_attrib_input,
#endif
#ifdef USE_MULTIVIEW
@ -915,7 +915,7 @@ void main() {
#if defined(UV_USED)
uv_attrib,
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(RENDER_MATERIAL)
uv2_attrib,
#endif
#ifdef USE_MULTIVIEW
@ -948,7 +948,7 @@ void main() {
#if defined(UV_USED)
uv_attrib,
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(RENDER_MATERIAL)
uv2_attrib,
#endif
#ifdef USE_MULTIVIEW

View file

@ -8280,10 +8280,10 @@ AnimationTrackEditor::AnimationTrackEditor() {
transition_selection->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Translation context is needed.
ease_selection = memnew(OptionButton);
ease_selection->set_accessibility_name(TTRC("Ease Type:"));
ease_selection->add_item(TTR("In", "Ease Type"), Tween::EASE_IN);
ease_selection->add_item(TTR("Out", "Ease Type"), Tween::EASE_OUT);
ease_selection->add_item(TTR("InOut", "Ease Type"), Tween::EASE_IN_OUT);
ease_selection->add_item(TTR("OutIn", "Ease Type"), Tween::EASE_OUT_IN);
ease_selection->add_item(TTR("Ease In", "Ease Type"), Tween::EASE_IN);
ease_selection->add_item(TTR("Ease Out", "Ease Type"), Tween::EASE_OUT);
ease_selection->add_item(TTR("Ease In-Out", "Ease Type"), Tween::EASE_IN_OUT);
ease_selection->add_item(TTR("Ease Out-In", "Ease Type"), Tween::EASE_OUT_IN);
ease_selection->select(Tween::EASE_IN_OUT); // Default
ease_selection->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Translation context is needed.
ease_fps = memnew(SpinBox);

View file

@ -30,7 +30,7 @@
#include "debug_adapter_parser.h"
#include "editor/debugger/debug_adapter/debug_adapter_types.h"
#include "editor/debugger/debug_adapter/debug_adapter_protocol.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/debugger/script_editor_debugger.h"
#include "editor/export/editor_export_platform.h"

View file

@ -32,8 +32,7 @@
#include "core/config/project_settings.h"
#include "core/debugger/remote_debugger.h"
#include "debug_adapter_protocol.h"
#include "debug_adapter_types.h"
#include "editor/debugger/debug_adapter/debug_adapter_types.h"
struct DAPeer;
class DebugAdapterProtocol;

View file

@ -34,6 +34,7 @@
#include "core/debugger/debugger_marshalls.h"
#include "core/io/json.h"
#include "core/io/marshalls.h"
#include "editor/debugger/debug_adapter/debug_adapter_parser.h"
#include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"

View file

@ -31,11 +31,10 @@
#pragma once
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/remote_debugger.h"
#include "core/io/stream_peer_tcp.h"
#include "core/io/tcp_server.h"
#include "debug_adapter_parser.h"
#include "debug_adapter_types.h"
#include "editor/debugger/debug_adapter/debug_adapter_types.h"
#include "scene/debugger/scene_debugger.h"
#define DAP_MAX_BUFFER_SIZE 4194304 // 4MB

View file

@ -30,7 +30,7 @@
#pragma once
#include "debug_adapter_protocol.h"
#include "editor/debugger/debug_adapter/debug_adapter_protocol.h"
#include "editor/plugins/editor_plugin.h"
class DebugAdapterServer : public EditorPlugin {

View file

@ -1796,22 +1796,42 @@ void EditorPropertyEasing::_spin_focus_exited() {
void EditorPropertyEasing::setup(bool p_positive_only, bool p_flip) {
flip = p_flip;
positive_only = p_positive_only;
// Names need translation context, so they are set in NOTIFICATION_TRANSLATION_CHANGED.
preset->add_item("", EASING_LINEAR);
preset->add_item("", EASING_IN);
preset->add_item("", EASING_OUT);
preset->add_item("", EASING_ZERO);
if (!positive_only) {
preset->add_item("", EASING_IN_OUT);
preset->add_item("", EASING_OUT_IN);
}
}
void EditorPropertyEasing::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
preset->clear();
preset->add_icon_item(get_editor_theme_icon(SNAME("CurveLinear")), "Linear", EASING_LINEAR);
preset->add_icon_item(get_editor_theme_icon(SNAME("CurveIn")), "Ease In", EASING_IN);
preset->add_icon_item(get_editor_theme_icon(SNAME("CurveOut")), "Ease Out", EASING_OUT);
preset->add_icon_item(get_editor_theme_icon(SNAME("CurveConstant")), "Zero", EASING_ZERO);
preset->set_item_icon(preset->get_item_index(EASING_LINEAR), get_editor_theme_icon(SNAME("CurveLinear")));
preset->set_item_icon(preset->get_item_index(EASING_IN), get_editor_theme_icon(SNAME("CurveIn")));
preset->set_item_icon(preset->get_item_index(EASING_OUT), get_editor_theme_icon(SNAME("CurveOut")));
preset->set_item_icon(preset->get_item_index(EASING_ZERO), get_editor_theme_icon(SNAME("CurveConstant")));
if (!positive_only) {
preset->add_icon_item(get_editor_theme_icon(SNAME("CurveInOut")), "Ease In-Out", EASING_IN_OUT);
preset->add_icon_item(get_editor_theme_icon(SNAME("CurveOutIn")), "Ease Out-In", EASING_OUT_IN);
preset->set_item_icon(preset->get_item_index(EASING_IN_OUT), get_editor_theme_icon(SNAME("CurveInOut")));
preset->set_item_icon(preset->get_item_index(EASING_OUT_IN), get_editor_theme_icon(SNAME("CurveOutIn")));
}
easing_draw->set_custom_minimum_size(Size2(0, get_theme_font(SceneStringName(font), SNAME("Label"))->get_height(get_theme_font_size(SceneStringName(font_size), SNAME("Label"))) * 2));
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
preset->set_item_text(preset->get_item_index(EASING_LINEAR), TTR("Linear", "Ease Type"));
preset->set_item_text(preset->get_item_index(EASING_IN), TTR("Ease In", "Ease Type"));
preset->set_item_text(preset->get_item_index(EASING_OUT), TTR("Ease Out", "Ease Type"));
preset->set_item_text(preset->get_item_index(EASING_ZERO), TTR("Zero", "Ease Type"));
if (!positive_only) {
preset->set_item_text(preset->get_item_index(EASING_IN_OUT), TTR("Ease In-Out", "Ease Type"));
preset->set_item_text(preset->get_item_index(EASING_OUT_IN), TTR("Ease Out-In", "Ease Type"));
}
} break;
}
}
@ -1823,6 +1843,7 @@ EditorPropertyEasing::EditorPropertyEasing() {
add_child(easing_draw);
preset = memnew(PopupMenu);
preset->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
add_child(preset);
preset->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyEasing::_set_preset));

View file

@ -4246,108 +4246,113 @@ void TileMapLayerEditor::_draw_overlay() {
Transform2D xform_inv = xform.affine_inverse();
Vector2i tile_shape_size = tile_set->get_tile_size();
// Draw tiles with invalid IDs in the grid.
TypedArray<Vector2i> used_cells = edited_layer->get_used_cells();
for (int i = 0; i < used_cells.size(); i++) {
Vector2i coords = used_cells[i];
int tile_source_id = edited_layer->get_cell_source_id(coords);
if (tile_source_id >= 0) {
Vector2i tile_atlas_coords = edited_layer->get_cell_atlas_coords(coords);
int tile_alternative_tile = edited_layer->get_cell_alternative_tile(coords);
// Fade the overlay out when size too small.
Vector2 hint_distance = xform.get_scale() * tile_shape_size;
float scale_fading = MIN(1, (MIN(hint_distance.x, hint_distance.y) - 5) / 5);
if (scale_fading > 0) {
// Draw tiles with invalid IDs in the grid.
TypedArray<Vector2i> used_cells = edited_layer->get_used_cells();
for (int i = 0; i < used_cells.size(); i++) {
Vector2i coords = used_cells[i];
int tile_source_id = edited_layer->get_cell_source_id(coords);
if (tile_source_id >= 0) {
Vector2i tile_atlas_coords = edited_layer->get_cell_atlas_coords(coords);
int tile_alternative_tile = edited_layer->get_cell_alternative_tile(coords);
TileSetSource *source = nullptr;
if (tile_set->has_source(tile_source_id)) {
source = *tile_set->get_source(tile_source_id);
}
TileSetSource *source = nullptr;
if (tile_set->has_source(tile_source_id)) {
source = *tile_set->get_source(tile_source_id);
}
if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) {
// Generate a random color from the hashed identifier of the tiles.
Array to_hash = { tile_source_id, tile_atlas_coords, tile_alternative_tile };
uint32_t hash = RandomPCG(to_hash.hash()).rand();
if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) {
// Generate a random color from the hashed identifier of the tiles.
Array to_hash = { tile_source_id, tile_atlas_coords, tile_alternative_tile };
uint32_t hash = RandomPCG(to_hash.hash()).rand();
Color color;
color = color.from_hsv(
(float)((hash >> 24) & 0xFF) / 256.0,
Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
0.8);
Color color;
color = color.from_hsv(
(float)((hash >> 24) & 0xFF) / 256.0,
Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
0.8 * scale_fading);
// Display the warning pattern.
Transform2D tile_xform;
tile_xform.set_origin(tile_set->map_to_local(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(custom_overlay, xform * tile_xform, color, true, warning_pattern_texture);
// Display the warning pattern.
Transform2D tile_xform;
tile_xform.set_origin(tile_set->map_to_local(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(custom_overlay, xform * tile_xform, color, true, warning_pattern_texture);
// Draw the warning icon.
Vector2::Axis min_axis = missing_tile_texture->get_size().min_axis_index();
Vector2 icon_size;
icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3;
icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]);
Rect2 rect = Rect2(xform.xform(tile_set->map_to_local(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale());
custom_overlay->draw_texture_rect(missing_tile_texture, rect);
// Draw the warning icon.
Vector2::Axis min_axis = missing_tile_texture->get_size().min_axis_index();
Vector2 icon_size;
icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3;
icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]);
Rect2 rect = Rect2(xform.xform(tile_set->map_to_local(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale());
custom_overlay->draw_texture_rect(missing_tile_texture, rect, false, Color(1, 1, 1, scale_fading));
}
}
}
}
// Fading on the border.
const int fading = 5;
// Fading on the border.
const int fading = 5;
// Determine the drawn area.
Size2 screen_size = custom_overlay->get_size();
Rect2i screen_rect;
screen_rect.position = tile_set->local_to_map(xform_inv.xform(Vector2()));
screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(Vector2(0, screen_size.height))));
screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(Vector2(screen_size.width, 0))));
screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(screen_size)));
screen_rect = screen_rect.grow(1);
// Determine the drawn area.
Size2 screen_size = custom_overlay->get_size();
Rect2i screen_rect;
screen_rect.position = tile_set->local_to_map(xform_inv.xform(Vector2()));
screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(Vector2(0, screen_size.height))));
screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(Vector2(screen_size.width, 0))));
screen_rect.expand_to(tile_set->local_to_map(xform_inv.xform(screen_size)));
screen_rect = screen_rect.grow(1);
Rect2i tilemap_used_rect = edited_layer->get_used_rect();
Rect2i tilemap_used_rect = edited_layer->get_used_rect();
Rect2i displayed_rect = tilemap_used_rect.intersection(screen_rect);
displayed_rect = displayed_rect.grow(fading);
Rect2i displayed_rect = tilemap_used_rect.intersection(screen_rect);
displayed_rect = displayed_rect.grow(fading);
// Reduce the drawn area to avoid crashes if needed.
int max_size = 100;
if (displayed_rect.size.x > max_size) {
displayed_rect = displayed_rect.grow_individual(-(displayed_rect.size.x - max_size) / 2, 0, -(displayed_rect.size.x - max_size) / 2, 0);
}
if (displayed_rect.size.y > max_size) {
displayed_rect = displayed_rect.grow_individual(0, -(displayed_rect.size.y - max_size) / 2, 0, -(displayed_rect.size.y - max_size) / 2);
}
// Reduce the drawn area to avoid crashes if needed.
int max_size = 100;
if (displayed_rect.size.x > max_size) {
displayed_rect = displayed_rect.grow_individual(-(displayed_rect.size.x - max_size) / 2, 0, -(displayed_rect.size.x - max_size) / 2, 0);
}
if (displayed_rect.size.y > max_size) {
displayed_rect = displayed_rect.grow_individual(0, -(displayed_rect.size.y - max_size) / 2, 0, -(displayed_rect.size.y - max_size) / 2);
}
// Draw the grid.
bool display_grid = EDITOR_GET("editors/tiles_editor/display_grid");
if (display_grid) {
Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
// Draw the grid.
bool display_grid = EDITOR_GET("editors/tiles_editor/display_grid");
if (display_grid) {
Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) {
for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) {
Vector2i pos_in_rect = Vector2i(x, y) - displayed_rect.position;
// Fade out the border of the grid.
float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f);
float right_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.x, (float)(displayed_rect.size.x - fading), (float)(pos_in_rect.x + 1)), 0.0f, 1.0f);
float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f);
float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)(pos_in_rect.y + 1)), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
tile_xform.set_origin(tile_set->map_to_local(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity * scale_fading;
tile_set->draw_tile_shape(custom_overlay, xform * tile_xform, color, false);
}
}
}
// Draw the IDs for debug.
/*Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) {
for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) {
Vector2i pos_in_rect = Vector2i(x, y) - displayed_rect.position;
// Fade out the border of the grid.
float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f);
float right_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.x, (float)(displayed_rect.size.x - fading), (float)(pos_in_rect.x + 1)), 0.0f, 1.0f);
float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f);
float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)(pos_in_rect.y + 1)), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
tile_xform.set_origin(tile_set->map_to_local(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
tile_set->draw_tile_shape(custom_overlay, xform * tile_xform, color, false);
custom_overlay->draw_string(font, xform.xform(tile_set->map_to_local(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y)));
}
}
}*/
}
// Draw the IDs for debug.
/*Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) {
for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) {
custom_overlay->draw_string(font, xform.xform(tile_set->map_to_local(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y)));
}
}*/
// Draw the plugins.
tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_draw_over_viewport(custom_overlay);
}

View file

@ -1444,7 +1444,7 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
if (auto_expand_selected) {
// Make visible when it's collapsed.
TreeItem *node = item->get_parent();
while (node && node != tree->get_root()) {
while (node) {
node->set_collapsed(false);
node = node->get_parent();
}

View file

@ -2263,9 +2263,9 @@ SpriteFramesEditor::SpriteFramesEditor() {
move_down->connect(SceneStringName(pressed), callable_mp(this, &SpriteFramesEditor::_down_pressed));
load->set_shortcut_context(frame_list);
load->set_shortcut(ED_SHORTCUT("sprite_frames/load_from_file", TTRC("Add frame from file"), KeyModifierMask::CMD_OR_CTRL | Key::O));
load->set_shortcut(ED_SHORTCUT("sprite_frames/load_from_file", TTRC("Add Frame from File"), KeyModifierMask::CMD_OR_CTRL | Key::O));
load_sheet->set_shortcut_context(frame_list);
load_sheet->set_shortcut(ED_SHORTCUT("sprite_frames/load_from_sheet", TTRC("Add frames from sprite sheet"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::O));
load_sheet->set_shortcut(ED_SHORTCUT("sprite_frames/load_from_sheet", TTRC("Add Frames from Sprite Sheet"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::O));
delete_frame->set_shortcut_context(frame_list);
delete_frame->set_shortcut(ED_SHORTCUT("sprite_frames/delete", TTRC("Delete Frame"), Key::KEY_DELETE));
copy->set_shortcut_context(frame_list);

View file

@ -82,15 +82,6 @@ private:
Ref<ArrayMesh> root_mesh;
struct Vector3Hasher {
_ALWAYS_INLINE_ uint32_t hash(const Vector3 &p_vec3) const {
uint32_t h = hash_murmur3_one_float(p_vec3.x);
h = hash_murmur3_one_float(p_vec3.y, h);
h = hash_murmur3_one_float(p_vec3.z, h);
return h;
}
};
struct ShapeUpdateSurface {
Vector<Vector3> vertices;
Vector<Vector3> normals;

View file

@ -3833,7 +3833,7 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {
}
void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
HashMap<Variant, GDScriptParser::ExpressionNode *, VariantHasher, StringLikeVariantComparator> elements;
HashMap<Variant, GDScriptParser::ExpressionNode *, HashMapHasherDefault, StringLikeVariantComparator> elements;
for (int i = 0; i < p_dictionary->elements.size(); i++) {
const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];

View file

@ -104,7 +104,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
List<int> temp_stack;
#endif
HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
HashMap<Variant, int> constant_map;
RBMap<StringName, int> name_map;
#ifdef TOOLS_ENABLED
Vector<StringName> named_globals;

View file

@ -33,7 +33,7 @@
#include "core/io/compression.h"
#include "core/io/marshalls.h"
int GDScriptTokenizerBuffer::_token_to_binary(const Token &p_token, Vector<uint8_t> &r_buffer, int p_start, HashMap<StringName, uint32_t> &r_identifiers_map, HashMap<Variant, uint32_t, VariantHasher, VariantComparator> &r_constants_map) {
int GDScriptTokenizerBuffer::_token_to_binary(const Token &p_token, Vector<uint8_t> &r_buffer, int p_start, HashMap<StringName, uint32_t> &r_identifiers_map, HashMap<Variant, uint32_t> &r_constants_map) {
int pos = p_start;
int token_type = p_token.type & TOKEN_MASK;
@ -239,7 +239,7 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer)
Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code, CompressMode p_compress_mode) {
HashMap<StringName, uint32_t> identifier_map;
HashMap<Variant, uint32_t, VariantHasher, VariantComparator> constant_map;
HashMap<Variant, uint32_t> constant_map;
Vector<uint8_t> token_buffer;
HashMap<uint32_t, uint32_t> token_lines;
HashMap<uint32_t, uint32_t> token_columns;

View file

@ -63,7 +63,7 @@ public:
HashMap<int, CommentData> dummy;
#endif // TOOLS_ENABLED
static int _token_to_binary(const Token &p_token, Vector<uint8_t> &r_buffer, int p_start, HashMap<StringName, uint32_t> &r_identifiers_map, HashMap<Variant, uint32_t, VariantHasher, VariantComparator> &r_constants_map);
static int _token_to_binary(const Token &p_token, Vector<uint8_t> &r_buffer, int p_start, HashMap<StringName, uint32_t> &r_identifiers_map, HashMap<Variant, uint32_t> &r_constants_map);
Token _binary_to_token(const uint8_t *p_buffer);
public:

View file

@ -1432,7 +1432,7 @@ void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_int
CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(p_unmanaged, script.ptr(), gchandle);
p_unmanaged->set_script_and_instance(script, csharp_instance);
p_unmanaged->set_script_instance(csharp_instance);
csharp_instance->connect_event_signals();
}

View file

@ -79,7 +79,7 @@ SnapshotDataObject::SnapshotDataObject(SceneDebuggerObject &p_obj, GameStateSnap
if (scr.is_valid()) {
ScriptInstance *scr_instance = scr->placeholder_instance_create(this);
if (scr_instance) {
set_script_and_instance(pvalue, scr_instance);
set_script_instance(scr_instance);
}
}
}

View file

@ -535,7 +535,7 @@ class TextServerAdvanced : public TextServerExtension {
Rect2 rect;
double baseline = 0;
};
HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects;
HashMap<Variant, EmbeddedObject> objects;
/* Shaped data */
TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.

View file

@ -458,7 +458,7 @@ class TextServerFallback : public TextServerExtension {
Rect2 rect;
double baseline = 0;
};
HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects;
HashMap<Variant, EmbeddedObject> objects;
/* Shaped data */
TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.

View file

@ -43,7 +43,6 @@ if env["dbus"]:
if env["library_type"] == "static_library":
prog = env.add_library("#bin/godot", common_linuxbsd)
elif env["library_type"] == "shared_library":
env.Append(CCFLAGS=["-fPIC"])
prog = env.add_shared_library("#bin/godot", common_linuxbsd)
else:
prog = env.add_program("#bin/godot", common_linuxbsd)

View file

@ -182,6 +182,9 @@ def configure(env: "SConsEnvironment"):
env.Append(CCFLAGS=["-ffp-contract=off"])
if env["library_type"] == "shared_library":
env.Append(CCFLAGS=["-fPIC"])
# LTO
if env["lto"] == "auto": # Enable LTO for production.

View file

@ -3,6 +3,8 @@ from misc.utility.scons_hints import *
Import("env")
File = env.File
# TODO: Add warning to headers and code about their autogenerated status.
if env["use_sowrap"]:
# We have to implement separate builders for so wrappers as the
@ -41,14 +43,14 @@ else:
def generate_from_xml(name, path):
header = env.WAYLAND_API_HEADER(f"protocol/{name}.gen.h", path)
source = env.WAYLAND_API_CODE(f"protocol/{name}.gen.c", path)
header = env.WAYLAND_API_HEADER(File(f"protocol/{name}.gen.h"), path)
source = env.WAYLAND_API_CODE(File(f"protocol/{name}.gen.c"), path)
env.NoCache(header, source)
return env.Object(f"protocol/{name}.gen.c")
return source
objects = [
generated_sources = [
# Core protocol
generate_from_xml("wayland", "#thirdparty/wayland/protocol/wayland.xml"),
# Stable protocols
@ -97,34 +99,31 @@ objects = [
),
]
source_files = [
"detect_prime_egl.cpp",
"display_server_wayland.cpp",
"key_mapping_xkb.cpp",
"wayland_thread.cpp",
source_files = generated_sources + [
File("detect_prime_egl.cpp"),
File("display_server_wayland.cpp"),
File("key_mapping_xkb.cpp"),
File("wayland_thread.cpp"),
]
if env["use_sowrap"]:
source_files.append(
[
"dynwrappers/wayland-cursor-so_wrap.c",
"dynwrappers/wayland-client-core-so_wrap.c",
"dynwrappers/wayland-egl-core-so_wrap.c",
File("dynwrappers/wayland-cursor-so_wrap.c"),
File("dynwrappers/wayland-client-core-so_wrap.c"),
File("dynwrappers/wayland-egl-core-so_wrap.c"),
]
)
if env["libdecor"]:
source_files.append("dynwrappers/libdecor-so_wrap.c")
source_files.append(File("dynwrappers/libdecor-so_wrap.c"))
if env["vulkan"]:
source_files.append("rendering_context_driver_vulkan_wayland.cpp")
source_files.append(File("rendering_context_driver_vulkan_wayland.cpp"))
if env["opengl3"]:
source_files.append("egl_manager_wayland.cpp")
source_files.append("egl_manager_wayland_gles.cpp")
source_files.append(File("egl_manager_wayland.cpp"))
source_files.append(File("egl_manager_wayland_gles.cpp"))
for source_file in source_files:
objects.append(env.Object(source_file))
Return("objects")
Return("source_files")

View file

@ -3,36 +3,38 @@ from misc.utility.scons_hints import *
Import("env")
File = env.File
source_files = [
"display_server_x11.cpp",
"key_mapping_x11.cpp",
File("display_server_x11.cpp"),
File("key_mapping_x11.cpp"),
]
if env["use_sowrap"]:
source_files.append(
[
"dynwrappers/xlib-so_wrap.c",
"dynwrappers/xcursor-so_wrap.c",
"dynwrappers/xinerama-so_wrap.c",
"dynwrappers/xinput2-so_wrap.c",
"dynwrappers/xrandr-so_wrap.c",
"dynwrappers/xrender-so_wrap.c",
"dynwrappers/xext-so_wrap.c",
File("dynwrappers/xlib-so_wrap.c"),
File("dynwrappers/xcursor-so_wrap.c"),
File("dynwrappers/xinerama-so_wrap.c"),
File("dynwrappers/xinput2-so_wrap.c"),
File("dynwrappers/xrandr-so_wrap.c"),
File("dynwrappers/xrender-so_wrap.c"),
File("dynwrappers/xext-so_wrap.c"),
]
)
if env["vulkan"]:
source_files.append("rendering_context_driver_vulkan_x11.cpp")
source_files.append(File("rendering_context_driver_vulkan_x11.cpp"))
if env["opengl3"]:
env.Append(CPPDEFINES=["GLAD_GLX_NO_X11"])
source_files.append(
["gl_manager_x11_egl.cpp", "gl_manager_x11.cpp", "detect_prime_x11.cpp", "#thirdparty/glad/glx.c"]
[
File("gl_manager_x11_egl.cpp"),
File("gl_manager_x11.cpp"),
File("detect_prime_x11.cpp"),
File("#thirdparty/glad/glx.c"),
]
)
objects = []
for source_file in source_files:
objects.append(env.Object(source_file))
Return("objects")
Return("source_files")

View file

@ -1917,9 +1917,22 @@ void DisplayServerX11::show_window(WindowID p_id) {
DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id);
// Setup initial minimize/maximize state.
// `_NET_WM_STATE` can be set directly when the window is unmapped.
LocalVector<Atom> hints;
if (wd.maximized) {
hints.push_back(XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False));
hints.push_back(XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False));
}
if (wd.minimized) {
hints.push_back(XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False));
}
XChangeProperty(x11_display, wd.x11_window, XInternAtom(x11_display, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *)hints.ptr(), hints.size());
XMapWindow(x11_display, wd.x11_window);
XSync(x11_display, False);
_validate_mode_on_map(p_id);
_validate_fullscreen_on_map(p_id);
if (p_id == MAIN_WINDOW_ID) {
// Get main window size for boot splash drawing.
@ -2448,6 +2461,52 @@ void DisplayServerX11::_update_actions_hints(WindowID p_window) {
}
}
void DisplayServerX11::_update_wm_state_hints(WindowID p_window) {
WindowData &wd = windows[p_window];
Atom type;
int format;
unsigned long len;
unsigned long remaining;
unsigned char *data = nullptr;
int result = XGetWindowProperty(
x11_display,
wd.x11_window,
XInternAtom(x11_display, "_NET_WM_STATE", False),
0,
1024,
False,
XA_ATOM,
&type,
&format,
&len,
&remaining,
&data);
if (result != Success) {
return;
}
LocalVector<Atom> hints;
if (data) {
hints.resize(len);
Atom *atoms = (Atom *)data;
for (unsigned long i = 0; i < len; i++) {
hints[i] = atoms[i];
}
XFree(data);
}
Atom fullscreen_atom = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
Atom maximized_horz_atom = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
Atom maximized_vert_atom = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
Atom hidden_atom = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
wd.fullscreen = hints.has(fullscreen_atom);
wd.maximized = hints.has(maximized_horz_atom) && hints.has(maximized_vert_atom);
wd.minimized = hints.has(hidden_atom);
}
Point2i DisplayServerX11::window_get_position(WindowID p_window) const {
_THREAD_SAFE_METHOD_
@ -2855,15 +2914,11 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
return retval;
}
void DisplayServerX11::_validate_mode_on_map(WindowID p_window) {
void DisplayServerX11::_validate_fullscreen_on_map(WindowID p_window) {
// Check if we applied any window modes that didn't take effect while unmapped
const WindowData &wd = windows[p_window];
if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
_set_wm_fullscreen(p_window, true, wd.exclusive_fullscreen);
} else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) {
_set_wm_maximized(p_window, true);
} else if (wd.minimized && !_window_minimize_check(p_window)) {
_set_wm_minimized(p_window, true);
}
if (wd.on_top) {
@ -3062,13 +3117,15 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
} break;
case WINDOW_MODE_MAXIMIZED: {
_set_wm_maximized(p_window, false);
// Varies between target modes, so do nothing here.
} break;
}
switch (p_mode) {
case WINDOW_MODE_WINDOWED: {
//do nothing
if (wd.maximized) {
_set_wm_maximized(p_window, false);
}
} break;
case WINDOW_MODE_MINIMIZED: {
_set_wm_minimized(p_window, true);
@ -3102,28 +3159,21 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c
ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
const WindowData &wd = windows[p_window];
if (wd.fullscreen) { //if fullscreen, it's not in another mode
if (wd.exclusive_fullscreen) {
return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
} else {
return WINDOW_MODE_FULLSCREEN;
}
if (_window_minimize_check(p_window)) {
return WINDOW_MODE_MINIMIZED;
}
if (wd.fullscreen) {
if (wd.exclusive_fullscreen) {
return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
}
return WINDOW_MODE_FULLSCREEN;
}
// Test maximized.
// Using EWMH -- Extended Window Manager Hints
if (_window_maximize_check(p_window, "_NET_WM_STATE")) {
return WINDOW_MODE_MAXIMIZED;
}
{
if (_window_minimize_check(p_window)) {
return WINDOW_MODE_MINIMIZED;
}
}
// All other discarded, return windowed.
return WINDOW_MODE_WINDOWED;
}
@ -4402,11 +4452,6 @@ void DisplayServerX11::_window_changed(XEvent *event) {
return;
}
// Query display server about a possible new window state.
wd.fullscreen = _window_fullscreen_check(window_id);
wd.maximized = _window_maximize_check(window_id, "_NET_WM_STATE") && !wd.fullscreen;
wd.minimized = _window_minimize_check(window_id) && !wd.fullscreen && !wd.maximized;
// Readjusting the window position if the window is being reparented by the window manager for decoration
Window root, parent, *children;
unsigned int nchildren;
@ -5037,7 +5082,7 @@ void DisplayServerX11::process_events() {
}
// Have we failed to set fullscreen while the window was unmapped?
_validate_mode_on_map(window_id);
_validate_fullscreen_on_map(window_id);
// On KDE Plasma, when the parent window of an embedded process is restored after being minimized,
// only the embedded window receives the Map notification, causing it to
@ -5058,24 +5103,6 @@ void DisplayServerX11::process_events() {
Main::force_redraw();
} break;
case NoExpose: {
DEBUG_LOG_X11("[%u] NoExpose drawable=%lu (%u) \n", frame, event.xnoexpose.drawable, window_id);
if (ime_window_event) {
break;
}
windows[window_id].minimized = true;
} break;
case VisibilityNotify: {
DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
if (ime_window_event) {
break;
}
windows[window_id].minimized = _window_minimize_check(window_id);
} break;
case LeaveNotify: {
DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
if (ime_window_event) {
@ -5219,6 +5246,12 @@ void DisplayServerX11::process_events() {
_window_changed(&event);
} break;
case PropertyNotify: {
if (event.xproperty.atom == XInternAtom(x11_display, "_NET_WM_STATE", False)) {
_update_wm_state_hints(window_id);
}
} break;
case ButtonPress:
case ButtonRelease: {
if (ime_window_event || ignore_events) {

View file

@ -352,9 +352,10 @@ class DisplayServerX11 : public DisplayServer {
bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const;
bool _window_fullscreen_check(WindowID p_window) const;
bool _window_minimize_check(WindowID p_window) const;
void _validate_mode_on_map(WindowID p_window);
void _validate_fullscreen_on_map(WindowID p_window);
void _update_size_hints(WindowID p_window);
void _update_actions_hints(WindowID p_window);
void _update_wm_state_hints(WindowID p_window);
void _set_wm_fullscreen(WindowID p_window, bool p_enabled, bool p_exclusive);
void _set_wm_maximized(WindowID p_window, bool p_enabled);
void _set_wm_minimized(WindowID p_window, bool p_enabled);

View file

@ -58,6 +58,17 @@ void MissingNode::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
#ifdef DEBUG_ENABLED
Error MissingNode::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) {
if (is_recording_signals()) {
if (!has_signal(p_signal)) {
add_user_signal(MethodInfo(p_signal));
}
}
return Object::connect(p_signal, p_callable, p_flags);
}
#endif
void MissingNode::set_original_class(const String &p_class) {
original_class = p_class;
}
@ -82,6 +93,14 @@ bool MissingNode::is_recording_properties() const {
return recording_properties;
}
void MissingNode::set_recording_signals(bool p_enable) {
recording_signals = p_enable;
}
bool MissingNode::is_recording_signals() const {
return recording_signals;
}
PackedStringArray MissingNode::get_configuration_warnings() const {
// The mere existence of this node is warning.
PackedStringArray warnings = Node::get_configuration_warnings();
@ -107,10 +126,14 @@ void MissingNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_recording_properties", "enable"), &MissingNode::set_recording_properties);
ClassDB::bind_method(D_METHOD("is_recording_properties"), &MissingNode::is_recording_properties);
ClassDB::bind_method(D_METHOD("set_recording_signals", "enable"), &MissingNode::set_recording_signals);
ClassDB::bind_method(D_METHOD("is_recording_signals"), &MissingNode::is_recording_signals);
// Expose, but not save.
ADD_PROPERTY(PropertyInfo(Variant::STRING, "original_class", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_original_class", "get_original_class");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "original_scene", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_original_scene", "get_original_scene");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "recording_properties", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_recording_properties", "is_recording_properties");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "recording_signals", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_recording_signals", "is_recording_signals");
}
MissingNode::MissingNode() {

View file

@ -39,12 +39,17 @@ class MissingNode : public Node {
String original_class;
String original_scene;
bool recording_properties = false;
bool recording_signals = false;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
#ifdef DEBUG_ENABLED
virtual Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0) override;
#endif
static void _bind_methods();
public:
@ -57,6 +62,9 @@ public:
void set_recording_properties(bool p_enable);
bool is_recording_properties() const;
void set_recording_signals(bool p_enable);
bool is_recording_signals() const;
virtual PackedStringArray get_configuration_warnings() const override;
MissingNode();

View file

@ -695,7 +695,7 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_st
// Let users override potential loop points from the WAV.
// We parse the WAV loop points only with "Detect From WAV" (0).
int import_loop_mode = p_options["edit/loop_mode"];
int import_loop_mode = p_options.get("edit/loop_mode", 0);
uint16_t format_bits = 0;
uint16_t format_channels = 0;
@ -933,8 +933,8 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_st
//apply frequency limit
bool limit_rate = p_options["force/max_rate"];
uint32_t limit_rate_hz = p_options["force/max_rate_hz"];
bool limit_rate = p_options.get("force/max_rate", false);
uint32_t limit_rate_hz = p_options.get("force/max_rate_hz", 0);
if (limit_rate && rate > limit_rate_hz && rate > 0 && frames > 0) {
// resample!
int64_t new_data_frames = (int64_t)(frames * (float)limit_rate_hz / (float)rate);
@ -975,7 +975,7 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_st
frames = new_data_frames;
}
bool normalize = p_options["edit/normalize"];
bool normalize = p_options.get("edit/normalize", false);
if (normalize) {
float max = 0.0;
@ -994,7 +994,7 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_st
}
}
bool trim = p_options["edit/trim"];
bool trim = p_options.get("edit/trim", false);
if (trim && (loop_mode == AudioStreamWAV::LOOP_DISABLED) && format_channels > 0) {
int64_t first = 0;
@ -1042,8 +1042,8 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_st
if (import_loop_mode >= 2) {
loop_mode = (AudioStreamWAV::LoopMode)(import_loop_mode - 1);
loop_begin = p_options["edit/loop_begin"];
loop_end = p_options["edit/loop_end"];
loop_begin = p_options.get("edit/loop_begin", 0);
loop_end = p_options.get("edit/loop_end", 0);
// Wrap around to max frames, so `-1` can be used to select the end, etc.
if (loop_begin < 0) {
loop_begin = CLAMP(loop_begin + frames, 0, frames - 1);
@ -1053,8 +1053,8 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_st
}
}
int compression = p_options["compress/mode"];
bool force_mono = p_options["force/mono"];
int compression = p_options.get("compress/mode", 0);
bool force_mono = p_options.get("force/mono", false);
if (force_mono && format_channels == 2) {
Vector<float> new_data;
@ -1067,7 +1067,7 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_st
format_channels = 1;
}
bool force_8_bit = p_options["force/8_bit"];
bool force_8_bit = p_options.get("force/8_bit", false);
if (force_8_bit) {
is16 = false;
}

View file

@ -775,7 +775,7 @@ static int _nm_get_string(const String &p_string, HashMap<StringName, int> &name
return idx;
}
static int _vm_get_variant(const Variant &p_variant, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map) {
static int _vm_get_variant(const Variant &p_variant, HashMap<Variant, int> &variant_map) {
if (variant_map.has(p_variant)) {
return variant_map[p_variant];
}
@ -785,7 +785,7 @@ static int _vm_get_variant(const Variant &p_variant, HashMap<Variant, int, Varia
return idx;
}
Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map, HashSet<int32_t> &ids_saved) {
Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map, HashSet<int32_t> &ids_saved) {
// this function handles all the work related to properly packing scenes, be it
// instantiated or inherited.
// given the complexity of this process, an attempt will be made to properly
@ -1133,7 +1133,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
return OK;
}
Error SceneState::_parse_connections(Node *p_owner, Node *p_node, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map) {
Error SceneState::_parse_connections(Node *p_owner, Node *p_node, HashMap<StringName, int> &name_map, HashMap<Variant, int> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map) {
// Ignore nodes that are within a scene instance.
if (p_node != p_owner && p_node->get_owner() && p_node->get_owner() != p_owner && !p_owner->is_editable_instance(p_node->get_owner())) {
return OK;
@ -1347,7 +1347,7 @@ Error SceneState::pack(Node *p_scene) {
Node *scene = p_scene;
HashMap<StringName, int> name_map;
HashMap<Variant, int, VariantHasher, VariantComparator> variant_map;
HashMap<Variant, int> variant_map;
HashMap<Node *, int> node_map;
HashMap<Node *, int> nodepath_map;
HashSet<int32_t> ids_saved;

View file

@ -90,8 +90,8 @@ class SceneState : public RefCounted {
Vector<ConnectionData> connections;
Error _parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map, HashSet<int32_t> &ids_saved);
Error _parse_connections(Node *p_owner, Node *p_node, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map);
Error _parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map, HashSet<int32_t> &ids_saved);
Error _parse_connections(Node *p_owner, Node *p_node, HashMap<StringName, int> &name_map, HashMap<Variant, int> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map);
String path;

View file

@ -2085,6 +2085,12 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
void VisualShader::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "code") {
p_property.usage = PROPERTY_USAGE_NONE;
}
}
Error VisualShader::_write_node(Type type, StringBuilder *p_global_code, StringBuilder *p_global_code_per_node, HashMap<Type, StringBuilder> *p_global_code_per_func, StringBuilder &r_code, Vector<VisualShader::DefaultTextureParam> &r_def_tex_params, const HashMap<ConnectionKey, const List<Connection>::Element *> &p_input_connections, int p_node, HashSet<int> &r_processed, bool p_for_preview, HashSet<StringName> &r_classes) const {
const Ref<VisualShaderNode> vsnode = graph[type].nodes[p_node].node;

View file

@ -172,6 +172,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
void _validate_property(PropertyInfo &p_property) const;
virtual void reset_state() override;

View file

@ -795,12 +795,12 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
#ifdef REAL_T_IS_DOUBLE
// Split the origin into two components, the float approximation and the missing precision.
// In the shader we will combine these back together to restore the lost precision.
RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[12], &instance_data.model_precision[0]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[13], &instance_data.model_precision[1]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &instance_data.transform[14], &instance_data.model_precision[2]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.x, &instance_data.prev_transform[12], &instance_data.prev_model_precision[0]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.y, &instance_data.prev_transform[13], &instance_data.prev_model_precision[1]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.z, &instance_data.prev_transform[14], &instance_data.prev_model_precision[2]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[3], &instance_data.model_precision[0]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[7], &instance_data.model_precision[1]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &instance_data.transform[11], &instance_data.model_precision[2]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.x, &instance_data.prev_transform[3], &instance_data.prev_model_precision[0]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.y, &instance_data.prev_transform[7], &instance_data.prev_model_precision[1]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.z, &instance_data.prev_transform[11], &instance_data.prev_model_precision[2]);
#endif
} else {
RendererRD::MaterialStorage::store_transform_transposed_3x4(Transform3D(), instance_data.transform);

View file

@ -1946,12 +1946,12 @@ void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint
#ifdef REAL_T_IS_DOUBLE
// Split the origin into two components, the float approximation and the missing precision.
// In the shader we will combine these back together to restore the lost precision.
RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[12], &instance_data.model_precision[0]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[13], &instance_data.model_precision[1]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &instance_data.transform[14], &instance_data.model_precision[2]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.x, &instance_data.prev_transform[12], &instance_data.prev_model_precision[0]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.y, &instance_data.prev_transform[13], &instance_data.prev_model_precision[1]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.z, &instance_data.prev_transform[14], &instance_data.prev_model_precision[2]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[3], &instance_data.model_precision[0]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[7], &instance_data.model_precision[1]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &instance_data.transform[11], &instance_data.model_precision[2]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.x, &instance_data.prev_transform[3], &instance_data.prev_model_precision[0]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.y, &instance_data.prev_transform[7], &instance_data.prev_model_precision[1]);
RendererRD::MaterialStorage::split_double(inst->prev_transform.origin.z, &instance_data.prev_transform[11], &instance_data.prev_model_precision[2]);
#endif
} else {
RendererRD::MaterialStorage::store_transform_transposed_3x4(Transform3D(), instance_data.transform);

View file

@ -91,9 +91,9 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p
RendererRD::MaterialStorage::store_transform_transposed_3x4(cam_transform.affine_inverse(), ubo.view_matrix);
#ifdef REAL_T_IS_DOUBLE
RendererRD::MaterialStorage::split_double(-cam_transform.origin.x, &ubo.inv_view_matrix[12], &ubo.inv_view_precision[0]);
RendererRD::MaterialStorage::split_double(-cam_transform.origin.y, &ubo.inv_view_matrix[13], &ubo.inv_view_precision[1]);
RendererRD::MaterialStorage::split_double(-cam_transform.origin.z, &ubo.inv_view_matrix[14], &ubo.inv_view_precision[2]);
RendererRD::MaterialStorage::split_double(-cam_transform.origin.x, &ubo.inv_view_matrix[3], &ubo.inv_view_precision[0]);
RendererRD::MaterialStorage::split_double(-cam_transform.origin.y, &ubo.inv_view_matrix[7], &ubo.inv_view_precision[1]);
RendererRD::MaterialStorage::split_double(-cam_transform.origin.z, &ubo.inv_view_matrix[11], &ubo.inv_view_precision[2]);
#endif
for (uint32_t v = 0; v < view_count; v++) {
@ -270,9 +270,9 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p
RendererRD::MaterialStorage::store_transform_transposed_3x4(prev_cam_transform.affine_inverse(), prev_ubo.view_matrix);
#ifdef REAL_T_IS_DOUBLE
RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.x, &prev_ubo.inv_view_matrix[12], &prev_ubo.inv_view_precision[0]);
RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.y, &prev_ubo.inv_view_matrix[13], &prev_ubo.inv_view_precision[1]);
RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.z, &prev_ubo.inv_view_matrix[14], &prev_ubo.inv_view_precision[2]);
RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.x, &prev_ubo.inv_view_matrix[3], &prev_ubo.inv_view_precision[0]);
RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.y, &prev_ubo.inv_view_matrix[7], &prev_ubo.inv_view_precision[1]);
RendererRD::MaterialStorage::split_double(-prev_cam_transform.origin.z, &prev_ubo.inv_view_matrix[11], &prev_ubo.inv_view_precision[2]);
#endif
for (uint32_t v = 0; v < view_count; v++) {

View file

@ -75,7 +75,18 @@ TEST_CASE("[JSON] Stringify arrays") {
full_precision_array.push_back(0.12345678901234568);
CHECK(JSON::stringify(full_precision_array, "", true, true) == "[0.12345678901234568]");
Array non_finite_array;
non_finite_array.push_back(Math::INF);
non_finite_array.push_back(-Math::INF);
non_finite_array.push_back(Math::NaN);
CHECK(JSON::stringify(non_finite_array) == "[1e99999,-1e99999,\"NaN\"]");
ERR_PRINT_OFF
Array non_finite_round_trip = JSON::parse_string(JSON::stringify(non_finite_array));
CHECK(non_finite_round_trip[0] == Variant(Math::INF));
CHECK(non_finite_round_trip[1] == Variant(-Math::INF));
CHECK(non_finite_round_trip[2].get_type() == Variant::STRING);
Array self_array;
self_array.push_back(self_array);
CHECK(JSON::stringify(self_array) == "[\"[...]\"]");
@ -113,7 +124,18 @@ TEST_CASE("[JSON] Stringify dictionaries") {
full_precision_dictionary["key"] = 0.12345678901234568;
CHECK(JSON::stringify(full_precision_dictionary, "", true, true) == "{\"key\":0.12345678901234568}");
Dictionary non_finite_dictionary;
non_finite_dictionary["-inf"] = -Math::INF;
non_finite_dictionary["inf"] = Math::INF;
non_finite_dictionary["nan"] = Math::NaN;
CHECK(JSON::stringify(non_finite_dictionary) == "{\"-inf\":-1e99999,\"inf\":1e99999,\"nan\":\"NaN\"}");
ERR_PRINT_OFF
Dictionary non_finite_round_trip = JSON::parse_string(JSON::stringify(non_finite_dictionary));
CHECK(non_finite_round_trip["-inf"] == Variant(-Math::INF));
CHECK(non_finite_round_trip["inf"] == Variant(Math::INF));
CHECK(non_finite_round_trip["nan"].get_type() == Variant::STRING);
Dictionary self_dictionary;
self_dictionary["key"] = self_dictionary;
CHECK(JSON::stringify(self_dictionary) == "{\"key\":\"{...}\"}");

View file

@ -36,6 +36,30 @@
namespace TestFixedVector {
struct MoveOnly {
bool is_alive = true;
MoveOnly() = default;
MoveOnly(const MoveOnly &p) = delete;
MoveOnly &operator=(const MoveOnly &p) = delete;
MoveOnly(MoveOnly &&p) {
is_alive = p.is_alive;
p.is_alive = false;
}
MoveOnly &operator=(MoveOnly &&p) {
if (&p == this) {
return *this;
}
is_alive = p.is_alive;
p.is_alive = false;
return *this;
}
};
static_assert(!std::is_trivially_copyable_v<MoveOnly>);
static_assert(!std::is_trivially_constructible_v<MoveOnly>);
TEST_CASE("[FixedVector] Basic Checks") {
FixedVector<uint16_t, 1> vector;
CHECK_EQ(vector.capacity(), 1);
@ -62,12 +86,6 @@ TEST_CASE("[FixedVector] Basic Checks") {
CHECK_EQ(vector1[0], 1);
CHECK_EQ(vector1[1], 2);
FixedVector<uint16_t, 3> vector2(vector1);
CHECK_EQ(vector2.capacity(), 3);
CHECK_EQ(vector2.size(), 2);
CHECK_EQ(vector2[0], 1);
CHECK_EQ(vector2[1], 2);
FixedVector<Variant, 3> vector_variant;
CHECK_EQ(vector_variant.size(), 0);
CHECK_EQ(vector_variant.capacity(), 3);
@ -79,6 +97,17 @@ TEST_CASE("[FixedVector] Basic Checks") {
CHECK_EQ(vector_variant[0], "Test");
CHECK_EQ(vector_variant[1], Variant(1));
CHECK_EQ(vector_variant[2].get_type(), Variant::NIL);
// Test that move-only types are transferred.
FixedVector<MoveOnly, 1> a;
a.push_back(MoveOnly());
CHECK_EQ(a.size(), 1);
FixedVector<MoveOnly, 1> b(std::move(a));
CHECK_EQ(a.size(), 0);
CHECK_EQ(b.size(), 1);
a = std::move(b);
CHECK_EQ(a.size(), 1);
CHECK_EQ(b.size(), 0);
}
TEST_CASE("[FixedVector] Alignment Checks") {