summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/class_db.cpp4
-rw-r--r--core/image.cpp53
-rw-r--r--core/image.h2
-rw-r--r--core/input_map.cpp10
-rw-r--r--core/input_map.h3
-rw-r--r--core/io/image_loader.cpp2
-rw-r--r--core/io/pck_packer.cpp8
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/math/math_2d.cpp10
-rw-r--r--core/math/math_2d.h2
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/vector3.h6
-rw-r--r--core/node_path.cpp3
-rw-r--r--core/oa_hash_map.h617
-rw-r--r--core/os/input.h3
-rw-r--r--core/os/input_event.cpp8
-rw-r--r--core/os/os.cpp2
-rw-r--r--core/project_settings.cpp7
-rw-r--r--core/ustring.cpp6
-rw-r--r--core/variant.cpp6
-rw-r--r--core/variant.h1
-rw-r--r--core/variant_call.cpp8
-rw-r--r--core/variant_op.cpp18
23 files changed, 292 insertions, 491 deletions
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 92aa131e2d..59b100e282 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -254,11 +254,13 @@ HashMap<StringName, StringName, StringNameHasher> ClassDB::compat_classes;
ClassDB::ClassInfo::ClassInfo() {
+ api = API_NONE;
creation_func = NULL;
inherits_ptr = NULL;
disabled = false;
exposed = false;
}
+
ClassDB::ClassInfo::~ClassInfo() {
}
@@ -355,7 +357,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
ClassInfo *t = classes.getptr(E->get());
ERR_FAIL_COND_V(!t, 0);
- if (t->api != p_api)
+ if (t->api != p_api || !t->exposed)
continue;
hash = hash_djb2_one_64(t->name.hash(), hash);
hash = hash_djb2_one_64(t->inherits.hash(), hash);
diff --git a/core/image.cpp b/core/image.cpp
index 2ac8ffea56..58f49d69e6 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -366,6 +366,8 @@ int Image::get_mipmap_count() const {
template <uint32_t read_bytes, bool read_alpha, uint32_t write_bytes, bool write_alpha, bool read_gray, bool write_gray>
static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p_dst) {
+ uint32_t max_bytes = MAX(read_bytes, write_bytes);
+
for (int y = 0; y < p_height; y++) {
for (int x = 0; x < p_width; x++) {
@@ -379,7 +381,8 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p
rgba[1] = rofs[0];
rgba[2] = rofs[0];
} else {
- for (uint32_t i = 0; i < MAX(read_bytes, write_bytes); i++) {
+
+ for (uint32_t i = 0; i < max_bytes; i++) {
rgba[i] = (i < read_bytes) ? rofs[i] : 0;
}
@@ -937,7 +940,7 @@ bool Image::_can_modify(Format p_format) const {
return p_format <= FORMAT_RGBE9995;
}
-template <int CC>
+template <int CC, bool renormalize>
static void _generate_po2_mipmap(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_width, uint32_t p_height) {
//fast power of 2 mipmap generation
@@ -963,6 +966,19 @@ static void _generate_po2_mipmap(const uint8_t *p_src, uint8_t *p_dst, uint32_t
dst_ptr[j] = val >> 2;
}
+ if (renormalize) {
+ Vector3 n(dst_ptr[0] / 255.0, dst_ptr[1] / 255.0, dst_ptr[2] / 255.0);
+ n *= 2.0;
+ n -= Vector3(1, 1, 1);
+ n.normalize();
+ n += Vector3(1, 1, 1);
+ n *= 0.5;
+ n *= 255;
+ dst_ptr[0] = CLAMP(int(n.x), 0, 255);
+ dst_ptr[1] = CLAMP(int(n.y), 0, 255);
+ dst_ptr[2] = CLAMP(int(n.z), 0, 255);
+ }
+
dst_ptr += CC;
rup_ptr += CC * 2;
rdown_ptr += CC * 2;
@@ -1045,11 +1061,11 @@ void Image::shrink_x2() {
switch (format) {
case FORMAT_L8:
- case FORMAT_R8: _generate_po2_mipmap<1>(r.ptr(), w.ptr(), width, height); break;
- case FORMAT_LA8: _generate_po2_mipmap<2>(r.ptr(), w.ptr(), width, height); break;
- case FORMAT_RG8: _generate_po2_mipmap<2>(r.ptr(), w.ptr(), width, height); break;
- case FORMAT_RGB8: _generate_po2_mipmap<3>(r.ptr(), w.ptr(), width, height); break;
- case FORMAT_RGBA8: _generate_po2_mipmap<4>(r.ptr(), w.ptr(), width, height); break;
+ case FORMAT_R8: _generate_po2_mipmap<1, false>(r.ptr(), w.ptr(), width, height); break;
+ case FORMAT_LA8: _generate_po2_mipmap<2, false>(r.ptr(), w.ptr(), width, height); break;
+ case FORMAT_RG8: _generate_po2_mipmap<2, false>(r.ptr(), w.ptr(), width, height); break;
+ case FORMAT_RGB8: _generate_po2_mipmap<3, false>(r.ptr(), w.ptr(), width, height); break;
+ case FORMAT_RGBA8: _generate_po2_mipmap<4, false>(r.ptr(), w.ptr(), width, height); break;
default: {}
}
}
@@ -1060,7 +1076,7 @@ void Image::shrink_x2() {
}
}
-Error Image::generate_mipmaps() {
+Error Image::generate_mipmaps(bool p_renormalize) {
if (!_can_modify(format)) {
ERR_EXPLAIN("Cannot generate mipmaps in indexed, compressed or custom image formats.");
@@ -1089,11 +1105,22 @@ Error Image::generate_mipmaps() {
switch (format) {
case FORMAT_L8:
- case FORMAT_R8: _generate_po2_mipmap<1>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
+ case FORMAT_R8: _generate_po2_mipmap<1, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
case FORMAT_LA8:
- case FORMAT_RG8: _generate_po2_mipmap<2>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
- case FORMAT_RGB8: _generate_po2_mipmap<3>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
- case FORMAT_RGBA8: _generate_po2_mipmap<4>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
+ case FORMAT_RG8: _generate_po2_mipmap<2, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break;
+ case FORMAT_RGB8:
+ if (p_renormalize)
+ _generate_po2_mipmap<3, true>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
+ else
+ _generate_po2_mipmap<3, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
+
+ break;
+ case FORMAT_RGBA8:
+ if (p_renormalize)
+ _generate_po2_mipmap<4, true>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
+ else
+ _generate_po2_mipmap<4, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h);
+ break;
default: {}
}
@@ -2217,7 +2244,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("crop", "width", "height"), &Image::crop);
ClassDB::bind_method(D_METHOD("flip_x"), &Image::flip_x);
ClassDB::bind_method(D_METHOD("flip_y"), &Image::flip_y);
- ClassDB::bind_method(D_METHOD("generate_mipmaps"), &Image::generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::_create_empty);
diff --git a/core/image.h b/core/image.h
index 17477d88ea..3c43e49950 100644
--- a/core/image.h
+++ b/core/image.h
@@ -217,7 +217,7 @@ public:
/**
* Generate a mipmap to an image (creates an image 1/4 the size, with averaging of 4->1)
*/
- Error generate_mipmaps();
+ Error generate_mipmaps(bool p_renormalize = false);
void clear_mipmaps();
diff --git a/core/input_map.cpp b/core/input_map.cpp
index 973edcb5b5..d33f40cbcf 100644
--- a/core/input_map.cpp
+++ b/core/input_map.cpp
@@ -48,6 +48,7 @@ void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event);
ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
+ ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events);
ClassDB::bind_method(D_METHOD("get_action_list", "action"), &InputMap::_get_action_list);
ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action);
ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals);
@@ -98,7 +99,7 @@ List<StringName> InputMap::get_actions() const {
return actions;
}
-List<Ref<InputEvent> >::Element *InputMap::_find_event(Action p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength) const {
+List<Ref<InputEvent> >::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength) const {
for (List<Ref<InputEvent> >::Element *E = p_action.inputs.front(); E; E = E->next()) {
@@ -155,6 +156,13 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve
input_map[p_action].inputs.erase(E);
}
+void InputMap::action_erase_events(const StringName &p_action) {
+
+ ERR_FAIL_COND(!input_map.has(p_action));
+
+ input_map[p_action].inputs.clear();
+}
+
Array InputMap::_get_action_list(const StringName &p_action) {
Array ret;
diff --git a/core/input_map.h b/core/input_map.h
index a00be8c859..bdec75c65b 100644
--- a/core/input_map.h
+++ b/core/input_map.h
@@ -55,7 +55,7 @@ private:
mutable Map<StringName, Action> input_map;
- List<Ref<InputEvent> >::Element *_find_event(Action p_action, const Ref<InputEvent> &p_event, bool *p_pressed = NULL, float *p_strength = NULL) const;
+ List<Ref<InputEvent> >::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = NULL, float *p_strength = NULL) const;
Array _get_action_list(const StringName &p_action);
Array _get_actions();
@@ -75,6 +75,7 @@ public:
void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);
void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event);
+ void action_erase_events(const StringName &p_action);
const List<Ref<InputEvent> > *get_action_list(const StringName &p_action);
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const;
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 999c9a8ca2..8ebd9d6cd9 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -37,7 +37,7 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
get_recognized_extensions(&extensions);
for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- if (E->get().nocasecmp_to(p_extension.get_extension()) == 0)
+ if (E->get().nocasecmp_to(p_extension) == 0)
return true;
}
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index 596060221e..b6377662de 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "pck_packer.h"
-
#include "core/os/file_access.h"
+#include "version.h"
static uint64_t _align(uint64_t p_n, int p_alignment) {
@@ -70,9 +70,9 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment) {
alignment = p_alignment;
file->store_32(0x43504447); // MAGIC
- file->store_32(0); // # version
- file->store_32(0); // # major
- file->store_32(0); // # minor
+ file->store_32(1); // # version
+ file->store_32(VERSION_MAJOR); // # major
+ file->store_32(VERSION_MINOR); // # minor
file->store_32(0); // # revision
for (int i = 0; i < 16; i++) {
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 609dd7e93c..3dcd94880a 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -56,7 +56,7 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t
for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- if (E->get().nocasecmp_to(extension.get_extension()) == 0)
+ if (E->get().nocasecmp_to(extension) == 0)
recognized = true;
}
diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp
index 3767d298a1..a053ffbd93 100644
--- a/core/math/math_2d.cpp
+++ b/core/math/math_2d.cpp
@@ -103,6 +103,16 @@ Vector2 Vector2::floor() const {
return Vector2(Math::floor(x), Math::floor(y));
}
+Vector2 Vector2::ceil() const {
+
+ return Vector2(Math::ceil(x), Math::ceil(y));
+}
+
+Vector2 Vector2::round() const {
+
+ return Vector2(Math::round(x), Math::round(y));
+}
+
Vector2 Vector2::rotated(real_t p_by) const {
Vector2 v;
diff --git a/core/math/math_2d.h b/core/math/math_2d.h
index e7188da85b..611d47e3ff 100644
--- a/core/math/math_2d.h
+++ b/core/math/math_2d.h
@@ -162,6 +162,8 @@ struct Vector2 {
}
Vector2 floor() const;
+ Vector2 ceil() const;
+ Vector2 round() const;
Vector2 snapped(const Vector2 &p_by) const;
real_t aspect() const { return width / height; }
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 102e454e02..fc90417413 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -74,7 +74,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me
int longest_axis = aabb.get_longest_axis_index();
//first two vertices are the most distant
- int simplex[4];
+ int simplex[4] = { 0 };
{
real_t max = 0, min = 0;
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 10ec4f5641..3bbfd7627c 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -103,6 +103,7 @@ struct Vector3 {
_FORCE_INLINE_ Vector3 floor() const;
_FORCE_INLINE_ Vector3 sign() const;
_FORCE_INLINE_ Vector3 ceil() const;
+ _FORCE_INLINE_ Vector3 round() const;
_FORCE_INLINE_ real_t distance_to(const Vector3 &p_b) const;
_FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_b) const;
@@ -204,6 +205,11 @@ Vector3 Vector3::ceil() const {
return Vector3(Math::ceil(x), Math::ceil(y), Math::ceil(z));
}
+Vector3 Vector3::round() const {
+
+ return Vector3(Math::round(x), Math::round(y), Math::round(z));
+}
+
Vector3 Vector3::linear_interpolate(const Vector3 &p_b, real_t p_t) const {
return Vector3(
diff --git a/core/node_path.cpp b/core/node_path.cpp
index cd7ad77534..64983fc091 100644
--- a/core/node_path.cpp
+++ b/core/node_path.cpp
@@ -264,8 +264,9 @@ NodePath NodePath::get_as_property_path() const {
Vector<StringName> new_path = data->subpath;
String initial_subname = data->path[0];
+
for (size_t i = 1; i < data->path.size(); i++) {
- initial_subname += i == 0 ? data->path[i].operator String() : "/" + data->path[i];
+ initial_subname += "/" + data->path[i];
}
new_path.insert(0, initial_subname);
diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h
index 280aea6a14..0b3b40f30c 100644
--- a/core/oa_hash_map.h
+++ b/core/oa_hash_map.h
@@ -36,176 +36,181 @@
#include "os/copymem.h"
#include "os/memory.h"
-// uncomment this to disable initial local storage.
-#define OA_HASH_MAP_INITIAL_LOCAL_STORAGE
-
/**
- * This class implements a hash map datastructure that uses open addressing with
- * local probing.
- *
- * It can give huge performance improvements over a chained HashMap because of
- * the increased data locality.
- *
- * Because of that locality property it's important to not use "large" value
- * types as the "TData" type. If TData values are too big it can cause more
- * cache misses then chaining. If larger values are needed then storing those
- * in a separate array and using pointers or indices to reference them is the
- * better solution.
- *
- * This hash map also implements real-time incremental rehashing.
+ * A HashMap implementation that uses open addressing with robinhood hashing.
+ * Robinhood hashing swaps out entries that have a smaller probing distance
+ * than the to-be-inserted entry, that evens out the average probing distance
+ * and enables faster lookups.
*
+ * The entries are stored inplace, so huge keys or values might fill cache lines
+ * a lot faster.
*/
-template <class TKey, class TData,
- uint16_t INITIAL_NUM_ELEMENTS = 64,
+template <class TKey, class TValue,
class Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey> >
class OAHashMap {
private:
-#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE
- TData local_data[INITIAL_NUM_ELEMENTS];
- TKey local_keys[INITIAL_NUM_ELEMENTS];
- uint32_t local_hashes[INITIAL_NUM_ELEMENTS];
- uint8_t local_flags[INITIAL_NUM_ELEMENTS / 4 + (INITIAL_NUM_ELEMENTS % 4 != 0 ? 1 : 0)];
-#endif
+ TValue *values;
+ TKey *keys;
+ uint32_t *hashes;
- struct {
- TData *data;
- TKey *keys;
- uint32_t *hashes;
+ uint32_t capacity;
- // This is actually an array of bits, 4 bit pairs per octet.
- // | ba ba ba ba | ba ba ba ba | ....
- //
- // if a is set it means that there is an element present.
- // if b is set it means that an element was deleted. This is needed for
- // the local probing to work without relocating any succeeding and
- // colliding entries.
- uint8_t *flags;
+ uint32_t num_elements;
- uint32_t capacity;
- } table, old_table;
+ static const uint32_t EMPTY_HASH = 0;
+ static const uint32_t DELETED_HASH_BIT = 1 << 31;
- bool is_rehashing;
- uint32_t rehash_position;
- uint32_t rehash_amount;
+ _FORCE_INLINE_ uint32_t _hash(const TKey &p_key) {
+ uint32_t hash = Hasher::hash(p_key);
- uint32_t elements;
+ if (hash == EMPTY_HASH) {
+ hash = EMPTY_HASH + 1;
+ } else if (hash & DELETED_HASH_BIT) {
+ hash &= ~DELETED_HASH_BIT;
+ }
- /* Methods */
+ return hash;
+ }
- // returns true if the value already existed, false if it's a new entry
- bool _raw_set_with_hash(uint32_t p_hash, const TKey &p_key, const TData &p_data) {
- for (int i = 0; i < table.capacity; i++) {
+ _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash) {
+ p_hash = p_hash & ~DELETED_HASH_BIT; // we don't care if it was deleted or not
- int pos = (p_hash + i) % table.capacity;
+ uint32_t original_pos = p_hash % capacity;
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
+ return p_pos - original_pos;
+ }
- bool is_filled_flag = table.flags[flags_pos] & (1 << (2 * flags_pos_offset));
- bool is_deleted_flag = table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1));
+ _FORCE_INLINE_ void _construct(uint32_t p_pos, uint32_t p_hash, const TKey &p_key, const TValue &p_value) {
+ memnew_placement(&keys[p_pos], TKey(p_key));
+ memnew_placement(&values[p_pos], TValue(p_value));
+ hashes[p_pos] = p_hash;
- if (is_filled_flag) {
- if (table.hashes[pos] == p_hash && Comparator::compare(table.keys[pos], p_key)) {
- table.data[pos] = p_data;
- return true;
- }
- continue;
+ num_elements++;
+ }
+
+ bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) {
+ uint32_t hash = _hash(p_key);
+ uint32_t pos = hash % capacity;
+ uint32_t distance = 0;
+
+ while (42) {
+ if (hashes[pos] == EMPTY_HASH) {
+ return false;
}
- table.keys[pos] = p_key;
- table.data[pos] = p_data;
- table.hashes[pos] = p_hash;
+ if (distance > _get_probe_length(pos, hashes[pos])) {
+ return false;
+ }
- table.flags[flags_pos] |= (1 << (2 * flags_pos_offset));
- table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset + 1));
+ if (hashes[pos] == hash && Comparator::compare(keys[pos], p_key)) {
+ r_pos = pos;
+ return true;
+ }
- return false;
+ pos = (pos + 1) % capacity;
+ distance++;
}
- return false;
}
-public:
- _FORCE_INLINE_ uint32_t get_capacity() const { return table.capacity; }
- _FORCE_INLINE_ uint32_t get_num_elements() const { return elements; }
+ void _insert_with_hash(uint32_t p_hash, const TKey &p_key, const TValue &p_value) {
- void set(const TKey &p_key, const TData &p_data) {
+ uint32_t hash = p_hash;
+ uint32_t distance = 0;
+ uint32_t pos = hash % capacity;
- uint32_t hash = Hasher::hash(p_key);
+ TKey key = p_key;
+ TValue value = p_value;
- // We don't progress the rehashing if the table just got resized
- // to keep the cost of this function low.
- if (is_rehashing) {
+ while (42) {
+ if (hashes[pos] == EMPTY_HASH) {
+ _construct(pos, hash, p_key, p_value);
- // rehash progress
+ return;
+ }
- for (int i = 0; i <= rehash_amount && rehash_position < old_table.capacity; rehash_position++) {
+ // not an empty slot, let's check the probing length of the existing one
+ uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos]);
+ if (existing_probe_len < distance) {
- int flags_pos = rehash_position / 4;
- int flags_pos_offset = rehash_position % 4;
+ if (hashes[pos] & DELETED_HASH_BIT) {
+ // we found a place where we can fit in!
+ _construct(pos, hash, p_key, p_value);
- bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
- bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0;
+ return;
+ }
- if (is_filled_flag) {
- _raw_set_with_hash(old_table.hashes[rehash_position], old_table.keys[rehash_position], old_table.data[rehash_position]);
+ SWAP(hash, hashes[pos]);
+ SWAP(key, keys[pos]);
+ SWAP(value, values[pos]);
+ distance = existing_probe_len;
+ }
- old_table.keys[rehash_position].~TKey();
- old_table.data[rehash_position].~TData();
+ pos = (pos + 1) % capacity;
+ distance++;
+ }
+ }
+ void _resize_and_rehash() {
- memnew_placement(&old_table.keys[rehash_position], TKey);
- memnew_placement(&old_table.data[rehash_position], TData);
+ TKey *old_keys = keys;
+ TValue *old_values = values;
+ uint32_t *old_hashes = hashes;
- old_table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset));
- old_table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1));
- }
- }
+ uint32_t old_capacity = capacity;
- if (rehash_position >= old_table.capacity) {
+ capacity = old_capacity * 2;
+ num_elements = 0;
- // wohooo, we can get rid of the old table.
- is_rehashing = false;
+ keys = memnew_arr(TKey, capacity);
+ values = memnew_arr(TValue, capacity);
+ hashes = memnew_arr(uint32_t, capacity);
-#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE
- if (old_table.data == local_data) {
- // Everything is local, so no cleanup :P
- } else
-#endif
- {
- memdelete_arr(old_table.data);
- memdelete_arr(old_table.keys);
- memdelete_arr(old_table.hashes);
- memdelete_arr(old_table.flags);
- }
- }
+ for (int i = 0; i < capacity; i++) {
+ hashes[i] = 0;
}
- // Table is almost full, resize and start rehashing process.
- if (elements >= table.capacity * 0.7) {
+ for (uint32_t i = 0; i < old_capacity; i++) {
+ if (old_hashes[i] == EMPTY_HASH) {
+ continue;
+ }
+ if (old_hashes[i] & DELETED_HASH_BIT) {
+ continue;
+ }
- old_table.capacity = table.capacity;
- old_table.data = table.data;
- old_table.flags = table.flags;
- old_table.hashes = table.hashes;
- old_table.keys = table.keys;
+ _insert_with_hash(old_hashes[i], old_keys[i], old_values[i]);
+ }
- table.capacity = old_table.capacity * 2;
+ memdelete_arr(old_keys);
+ memdelete_arr(old_values);
+ memdelete_arr(old_hashes);
+ }
- table.data = memnew_arr(TData, table.capacity);
- table.flags = memnew_arr(uint8_t, table.capacity / 4 + (table.capacity % 4 != 0 ? 1 : 0));
- table.hashes = memnew_arr(uint32_t, table.capacity);
- table.keys = memnew_arr(TKey, table.capacity);
+public:
+ _FORCE_INLINE_ uint32_t get_capacity() const { return capacity; }
+ _FORCE_INLINE_ uint32_t get_num_elements() const { return num_elements; }
- zeromem(table.flags, table.capacity / 4 + (table.capacity % 4 != 0 ? 1 : 0));
+ void insert(const TKey &p_key, const TValue &p_value) {
- is_rehashing = true;
- rehash_position = 0;
- rehash_amount = (elements * 2) / (table.capacity * 0.7 - old_table.capacity);
+ if ((float)num_elements / (float)capacity > 0.9) {
+ _resize_and_rehash();
}
- if (!_raw_set_with_hash(hash, p_key, p_data))
- elements++;
+ uint32_t hash = _hash(p_key);
+
+ _insert_with_hash(hash, p_key, p_value);
+ }
+
+ void set(const TKey &p_key, const TValue &p_data) {
+ uint32_t pos = 0;
+ bool exists = _lookup_pos(p_key, pos);
+
+ if (exists) {
+ values[pos].~TValue();
+ memnew_placement(&values[pos], TValue(p_data));
+ } else {
+ insert(p_key, p_data);
+ }
}
/**
@@ -214,380 +219,108 @@ public:
* if r_data is not NULL then the value will be written to the object
* it points to.
*/
- bool lookup(const TKey &p_key, TData *r_data) {
-
- uint32_t hash = Hasher::hash(p_key);
-
- bool check_old_table = is_rehashing;
- bool check_new_table = true;
-
- // search for the key and return the value associated with it
- //
- // if we're rehashing we need to check both the old and the
- // current table. If we find a value in the old table we still
- // need to continue searching in the new table as it might have
- // been added after
-
- TData *value = NULL;
-
- for (int i = 0; i < table.capacity; i++) {
-
- if (!check_new_table && !check_old_table) {
-
- break;
- }
-
- // if we're rehashing check the old table
- if (check_old_table && i < old_table.capacity) {
-
- int pos = (hash + i) % old_table.capacity;
-
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
-
- bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
- bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0;
-
- if (is_filled_flag) {
- // found our entry?
- if (old_table.hashes[pos] == hash && Comparator::compare(old_table.keys[pos], p_key)) {
- value = &old_table.data[pos];
- check_old_table = false;
- }
- } else if (!is_deleted_flag) {
-
- // we hit an empty field here, we don't
- // need to further check this old table
- // because we know it's not in here.
+ bool lookup(const TKey &p_key, TValue &r_data) {
+ uint32_t pos = 0;
+ bool exists = _lookup_pos(p_key, pos);
- check_old_table = false;
- }
- }
-
- if (check_new_table) {
-
- int pos = (hash + i) % table.capacity;
-
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
-
- bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
- bool is_deleted_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0;
-
- if (is_filled_flag) {
- // found our entry?
- if (table.hashes[pos] == hash && Comparator::compare(table.keys[pos], p_key)) {
- if (r_data != NULL)
- *r_data = table.data[pos];
- return true;
- }
- continue;
- } else if (is_deleted_flag) {
- continue;
- } else if (value != NULL) {
-
- // We found a value in the old table
- if (r_data != NULL)
- *r_data = *value;
- return true;
- } else {
- check_new_table = false;
- }
- }
- }
-
- if (value != NULL) {
- if (r_data != NULL)
- *r_data = *value;
+ if (exists) {
+ r_data.~TValue();
+ memnew_placement(&r_data, TValue(values[pos]));
return true;
}
+
return false;
}
_FORCE_INLINE_ bool has(const TKey &p_key) {
- return lookup(p_key, NULL);
+ uint32_t _pos = 0;
+ return _lookup_pos(p_key, _pos);
}
void remove(const TKey &p_key) {
- uint32_t hash = Hasher::hash(p_key);
-
- bool check_old_table = is_rehashing;
- bool check_new_table = true;
-
- for (int i = 0; i < table.capacity; i++) {
-
- if (!check_new_table && !check_old_table) {
- return;
- }
-
- // if we're rehashing check the old table
- if (check_old_table && i < old_table.capacity) {
-
- int pos = (hash + i) % old_table.capacity;
-
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
-
- bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
- bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0;
-
- if (is_filled_flag) {
- // found our entry?
- if (old_table.hashes[pos] == hash && Comparator::compare(old_table.keys[pos], p_key)) {
- old_table.keys[pos].~TKey();
- old_table.data[pos].~TData();
+ uint32_t pos = 0;
+ bool exists = _lookup_pos(p_key, pos);
- memnew_placement(&old_table.keys[pos], TKey);
- memnew_placement(&old_table.data[pos], TData);
-
- old_table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset));
- old_table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1));
-
- elements--;
- return;
- }
- } else if (!is_deleted_flag) {
-
- // we hit an empty field here, we don't
- // need to further check this old table
- // because we know it's not in here.
-
- check_old_table = false;
- }
- }
-
- if (check_new_table) {
-
- int pos = (hash + i) % table.capacity;
-
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
-
- bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
- bool is_deleted_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0;
-
- if (is_filled_flag) {
- // found our entry?
- if (table.hashes[pos] == hash && Comparator::compare(table.keys[pos], p_key)) {
- table.keys[pos].~TKey();
- table.data[pos].~TData();
-
- memnew_placement(&table.keys[pos], TKey);
- memnew_placement(&table.data[pos], TData);
-
- table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset));
- table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1));
-
- // don't return here, this value might still be in the old table
- // if it was already relocated.
-
- elements--;
- return;
- }
- continue;
- } else if (is_deleted_flag) {
- continue;
- } else {
- check_new_table = false;
- }
- }
+ if (!exists) {
+ return;
}
+
+ hashes[pos] |= DELETED_HASH_BIT;
+ values[pos].~TValue();
+ keys[pos].~TKey();
+ num_elements--;
}
struct Iterator {
bool valid;
- uint32_t hash;
-
const TKey *key;
- const TData *data;
+ const TValue *value;
private:
+ uint32_t pos;
friend class OAHashMap;
- bool was_from_old_table;
};
Iterator iter() const {
Iterator it;
- it.valid = false;
- it.was_from_old_table = false;
-
- bool check_old_table = is_rehashing;
-
- for (int i = 0; i < table.capacity; i++) {
-
- // if we're rehashing check the old table first
- if (check_old_table && i < old_table.capacity) {
-
- int pos = i;
-
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
-
- bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
-
- if (is_filled_flag) {
- it.valid = true;
- it.hash = old_table.hashes[pos];
- it.data = &old_table.data[pos];
- it.key = &old_table.keys[pos];
-
- it.was_from_old_table = true;
-
- return it;
- }
- }
-
- {
-
- int pos = i;
-
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
-
- bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
-
- if (is_filled_flag) {
- it.valid = true;
- it.hash = table.hashes[pos];
- it.data = &table.data[pos];
- it.key = &table.keys[pos];
-
- return it;
- }
- }
- }
+ it.valid = true;
+ it.pos = 0;
- return it;
+ return next_iter(it);
}
Iterator next_iter(const Iterator &p_iter) const {
+
if (!p_iter.valid) {
return p_iter;
}
Iterator it;
-
it.valid = false;
- it.was_from_old_table = false;
-
- bool check_old_table = is_rehashing;
-
- // we use this to skip the first check or not
- bool was_from_old_table = p_iter.was_from_old_table;
-
- int prev_index = (p_iter.data - (p_iter.was_from_old_table ? old_table.data : table.data));
-
- if (!was_from_old_table) {
- prev_index++;
- }
+ it.pos = p_iter.pos;
+ it.key = NULL;
+ it.value = NULL;
- for (int i = prev_index; i < table.capacity; i++) {
+ for (uint32_t i = it.pos; i < capacity; i++) {
+ it.pos = i + 1;
- // if we're rehashing check the old table first
- if (check_old_table && i < old_table.capacity && !was_from_old_table) {
-
- int pos = i;
-
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
-
- bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
-
- if (is_filled_flag) {
- it.valid = true;
- it.hash = old_table.hashes[pos];
- it.data = &old_table.data[pos];
- it.key = &old_table.keys[pos];
-
- it.was_from_old_table = true;
-
- return it;
- }
+ if (hashes[i] == EMPTY_HASH) {
+ continue;
}
-
- was_from_old_table = false;
-
- {
- int pos = i;
-
- int flags_pos = pos / 4;
- int flags_pos_offset = pos % 4;
-
- bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0;
-
- if (is_filled_flag) {
- it.valid = true;
- it.hash = table.hashes[pos];
- it.data = &table.data[pos];
- it.key = &table.keys[pos];
-
- return it;
- }
+ if (hashes[i] & DELETED_HASH_BIT) {
+ continue;
}
+
+ it.valid = true;
+ it.key = &keys[i];
+ it.value = &values[i];
+ return it;
}
return it;
}
- OAHashMap(uint32_t p_initial_capacity = INITIAL_NUM_ELEMENTS) {
+ OAHashMap(uint32_t p_initial_capacity = 64) {
-#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE
+ capacity = p_initial_capacity;
+ num_elements = 0;
- if (p_initial_capacity <= INITIAL_NUM_ELEMENTS) {
- table.data = local_data;
- table.keys = local_keys;
- table.hashes = local_hashes;
- table.flags = local_flags;
+ keys = memnew_arr(TKey, p_initial_capacity);
+ values = memnew_arr(TValue, p_initial_capacity);
+ hashes = memnew_arr(uint32_t, p_initial_capacity);
- zeromem(table.flags, INITIAL_NUM_ELEMENTS / 4 + (INITIAL_NUM_ELEMENTS % 4 != 0 ? 1 : 0));
-
- table.capacity = INITIAL_NUM_ELEMENTS;
- elements = 0;
- } else
-#endif
- {
- table.data = memnew_arr(TData, p_initial_capacity);
- table.keys = memnew_arr(TKey, p_initial_capacity);
- table.hashes = memnew_arr(uint32_t, p_initial_capacity);
- table.flags = memnew_arr(uint8_t, p_initial_capacity / 4 + (p_initial_capacity % 4 != 0 ? 1 : 0));
-
- zeromem(table.flags, p_initial_capacity / 4 + (p_initial_capacity % 4 != 0 ? 1 : 0));
-
- table.capacity = p_initial_capacity;
- elements = 0;
+ for (int i = 0; i < p_initial_capacity; i++) {
+ hashes[i] = 0;
}
-
- is_rehashing = false;
- rehash_position = 0;
}
~OAHashMap() {
-#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE
- if (table.capacity <= INITIAL_NUM_ELEMENTS) {
- return; // Everything is local, so no cleanup :P
- }
-#endif
- if (is_rehashing) {
-
-#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE
- if (old_table.data == local_data) {
- // Everything is local, so no cleanup :P
- } else
-#endif
- {
- memdelete_arr(old_table.data);
- memdelete_arr(old_table.keys);
- memdelete_arr(old_table.hashes);
- memdelete_arr(old_table.flags);
- }
- }
- memdelete_arr(table.data);
- memdelete_arr(table.keys);
- memdelete_arr(table.hashes);
- memdelete_arr(table.flags);
+ memdelete_arr(keys);
+ memdelete_arr(values);
+ memdelete(hashes);
}
};
diff --git a/core/os/input.h b/core/os/input.h
index 027147b987..001871c5dc 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -118,7 +118,8 @@ public:
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
- virtual bool is_emulating_touchscreen() const = 0;
+ virtual bool is_emulating_touch_from_mouse() const = 0;
+ virtual bool is_emulating_mouse_from_touch() const = 0;
virtual CursorShape get_default_cursor_shape() = 0;
virtual void set_default_cursor_shape(CursorShape p_shape) = 0;
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index 5003be77ab..4ebb821a2f 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -656,12 +656,14 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *
if (jm.is_null())
return false;
- bool match = (axis == jm->axis && (((axis_value < 0) == (jm->axis_value < 0)) || jm->axis_value == 0));
+ bool match = (axis == jm->axis); // Matches even if not in the same direction, but returns a "not pressed" event.
if (match) {
+ bool same_direction = (((axis_value < 0) == (jm->axis_value < 0)) || jm->axis_value == 0);
+ bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false;
if (p_pressed != NULL)
- *p_pressed = Math::abs(jm->get_axis_value()) >= p_deadzone;
+ *p_pressed = pressed;
if (p_strength != NULL)
- *p_strength = (*p_pressed) ? Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())) : 0.0f;
+ *p_strength = pressed ? CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f) : 0.0f;
}
return match;
}
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 618a4bbac3..854d554b10 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -411,7 +411,7 @@ Error OS::set_cwd(const String &p_cwd) {
bool OS::has_touchscreen_ui_hint() const {
//return false;
- return Input::get_singleton() && Input::get_singleton()->is_emulating_touchscreen();
+ return Input::get_singleton() && Input::get_singleton()->is_emulating_touch_from_mouse();
}
int OS::get_free_static_memory() const {
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index d3a62263ac..ac4a4b7d15 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -816,12 +816,11 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default) {
Variant ret;
- if (ProjectSettings::get_singleton()->has_setting(p_var)) {
- ret = ProjectSettings::get_singleton()->get(p_var);
- } else {
+ if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
ProjectSettings::get_singleton()->set(p_var, p_default);
- ret = p_default;
}
+ ret = ProjectSettings::get_singleton()->get(p_var);
+
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
ProjectSettings::get_singleton()->set_builtin_order(p_var);
return ret;
diff --git a/core/ustring.cpp b/core/ustring.cpp
index b98e202175..921d20a6fd 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -3755,8 +3755,8 @@ String String::get_file() const {
String String::get_extension() const {
int pos = find_last(".");
- if (pos < 0)
- return *this;
+ if (pos < 0 || pos < MAX(find_last("/"), find_last("\\")))
+ return "";
return substr(pos + 1, length());
}
@@ -3834,7 +3834,7 @@ String String::percent_decode() const {
String String::get_basename() const {
int pos = find_last(".");
- if (pos < 0)
+ if (pos < 0 || pos < MAX(find_last("/"), find_last("\\")))
return *this;
return substr(0, pos);
diff --git a/core/variant.cpp b/core/variant.cpp
index 5d48c8785e..a6df95e310 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -3167,7 +3167,11 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
if (ce.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
int errorarg = ce.argument;
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + ".";
+ if (p_argptrs) {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + ".";
+ } else {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(ce.expected) + ".";
+ }
} else if (ce.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
} else if (ce.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
diff --git a/core/variant.h b/core/variant.h
index 2cdb5c9ab6..f227e4bfdb 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -140,7 +140,6 @@ private:
::AABB *_aabb;
Basis *_basis;
Transform *_transform;
- RefPtr *_resource;
void *_ptr; //generic pointer
uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)];
} _data;
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index d05c7b174c..bd1cde5a82 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -153,9 +153,9 @@ struct _VariantCall {
funcdata.func = p_func;
funcdata.default_args = p_defaultarg;
funcdata._const = p_const;
+ funcdata.returns = p_has_return;
#ifdef DEBUG_ENABLED
funcdata.return_type = p_return;
- funcdata.returns = p_has_return;
#endif
if (p_argtype1.name) {
@@ -344,6 +344,8 @@ struct _VariantCall {
VCALL_LOCALMEM1R(Vector2, rotated);
VCALL_LOCALMEM0R(Vector2, tangent);
VCALL_LOCALMEM0R(Vector2, floor);
+ VCALL_LOCALMEM0R(Vector2, ceil);
+ VCALL_LOCALMEM0R(Vector2, round);
VCALL_LOCALMEM1R(Vector2, snapped);
VCALL_LOCALMEM0R(Vector2, aspect);
VCALL_LOCALMEM1R(Vector2, dot);
@@ -386,6 +388,7 @@ struct _VariantCall {
VCALL_LOCALMEM0R(Vector3, abs);
VCALL_LOCALMEM0R(Vector3, floor);
VCALL_LOCALMEM0R(Vector3, ceil);
+ VCALL_LOCALMEM0R(Vector3, round);
VCALL_LOCALMEM1R(Vector3, distance_to);
VCALL_LOCALMEM1R(Vector3, distance_squared_to);
VCALL_LOCALMEM1R(Vector3, angle_to);
@@ -1519,6 +1522,8 @@ void register_variant_methods() {
ADDFUNC1R(VECTOR2, VECTOR2, Vector2, rotated, REAL, "phi", varray());
ADDFUNC0R(VECTOR2, VECTOR2, Vector2, tangent, varray());
ADDFUNC0R(VECTOR2, VECTOR2, Vector2, floor, varray());
+ ADDFUNC0R(VECTOR2, VECTOR2, Vector2, ceil, varray());
+ ADDFUNC0R(VECTOR2, VECTOR2, Vector2, round, varray());
ADDFUNC1R(VECTOR2, VECTOR2, Vector2, snapped, VECTOR2, "by", varray());
ADDFUNC0R(VECTOR2, REAL, Vector2, aspect, varray());
ADDFUNC1R(VECTOR2, REAL, Vector2, dot, VECTOR2, "with", varray());
@@ -1560,6 +1565,7 @@ void register_variant_methods() {
ADDFUNC0R(VECTOR3, VECTOR3, Vector3, abs, varray());
ADDFUNC0R(VECTOR3, VECTOR3, Vector3, floor, varray());
ADDFUNC0R(VECTOR3, VECTOR3, Vector3, ceil, varray());
+ ADDFUNC0R(VECTOR3, VECTOR3, Vector3, round, varray());
ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray());
ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray());
ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray());
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index 4e37593915..621af2dfb7 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -1459,13 +1459,13 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool
v->a = p_value._data._int / 255.0;
valid = true;
} else if (p_index == CoreStringNames::singleton->h) {
- v->set_hsv(p_value._data._int, v->get_s(), v->get_v());
+ v->set_hsv(p_value._data._int, v->get_s(), v->get_v(), v->a);
valid = true;
} else if (p_index == CoreStringNames::singleton->s) {
- v->set_hsv(v->get_h(), p_value._data._int, v->get_v());
+ v->set_hsv(v->get_h(), p_value._data._int, v->get_v(), v->a);
valid = true;
} else if (p_index == CoreStringNames::singleton->v) {
- v->set_hsv(v->get_h(), v->get_v(), p_value._data._int);
+ v->set_hsv(v->get_h(), v->get_v(), p_value._data._int, v->a);
valid = true;
}
} else if (p_value.type == Variant::REAL) {
@@ -1495,13 +1495,13 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool
v->a = p_value._data._real / 255.0;
valid = true;
} else if (p_index == CoreStringNames::singleton->h) {
- v->set_hsv(p_value._data._real, v->get_s(), v->get_v());
+ v->set_hsv(p_value._data._real, v->get_s(), v->get_v(), v->a);
valid = true;
} else if (p_index == CoreStringNames::singleton->s) {
- v->set_hsv(v->get_h(), p_value._data._real, v->get_v());
+ v->set_hsv(v->get_h(), p_value._data._real, v->get_v(), v->a);
valid = true;
} else if (p_index == CoreStringNames::singleton->v) {
- v->set_hsv(v->get_h(), v->get_s(), p_value._data._real);
+ v->set_hsv(v->get_h(), v->get_s(), p_value._data._real, v->a);
valid = true;
}
}
@@ -2117,15 +2117,15 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid)
return;
} else if (*str == "h") {
valid = true;
- v->set_hsv(p_value, v->get_s(), v->get_v());
+ v->set_hsv(p_value, v->get_s(), v->get_v(), v->a);
return;
} else if (*str == "s") {
valid = true;
- v->set_hsv(v->get_h(), p_value, v->get_v());
+ v->set_hsv(v->get_h(), p_value, v->get_v(), v->a);
return;
} else if (*str == "v") {
valid = true;
- v->set_hsv(v->get_h(), v->get_s(), p_value);
+ v->set_hsv(v->get_h(), v->get_s(), p_value, v->a);
return;
} else if (*str == "r8") {
valid = true;