diff options
33 files changed, 624 insertions, 606 deletions
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/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 5bca3ee548..d7e679f596 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -1297,6 +1297,10 @@ Transform2D RasterizerStorageGLES2::skeleton_bone_get_transform_2d(RID p_skeleto return Transform2D(); } +void RasterizerStorageGLES2::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { + +} + void RasterizerStorageGLES2::update_dirty_skeletons() { } diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 9f8d8d100b..748bff9b65 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -555,6 +555,7 @@ public: virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const; virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; + virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); /* Light API */ diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c33fdaa355..12da7351bd 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -160,6 +160,7 @@ void RasterizerCanvasGLES3::canvas_begin() { state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_NINEPATCH, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false); state.canvas_shader.set_custom_shader(0); state.canvas_shader.bind(); @@ -180,6 +181,7 @@ void RasterizerCanvasGLES3::canvas_begin() { glBindVertexArray(data.canvas_quad_array); state.using_texture_rect = true; state.using_ninepatch = false; + state.using_skeleton = false; } void RasterizerCanvasGLES3::canvas_end() { @@ -284,6 +286,9 @@ void RasterizerCanvasGLES3::_set_texture_rect_mode(bool p_enable, bool p_ninepat state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.canvas_item_modulate); state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix); + if (state.using_skeleton) { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TO_OBJECT_LOCAL_MATRIX, state.skeleton_transform); + } if (storage->frame.current_rt) { state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); } else { @@ -293,7 +298,7 @@ void RasterizerCanvasGLES3::_set_texture_rect_mode(bool p_enable, bool p_ninepat state.using_ninepatch = p_ninepatch; } -void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { +void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const int *p_bones, const float *p_weights) { glBindVertexArray(data.polygon_buffer_pointer_array); glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); @@ -333,6 +338,23 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun glDisableVertexAttribArray(VS::ARRAY_TEX_UV); } + if (p_bones && p_weights) { + + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones); + glEnableVertexAttribArray(VS::ARRAY_BONES); + glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, false, sizeof(int) * 4, ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(int) * 4 * p_vertex_count; + + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights); + glEnableVertexAttribArray(VS::ARRAY_WEIGHTS); + glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, false, sizeof(float) * 4, ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(float) * 4 * p_vertex_count; + + } else if (state.using_skeleton) { + glVertexAttribI4ui(VS::ARRAY_BONES, 0, 0, 0, 0); + glVertexAttrib4f(VS::ARRAY_WEIGHTS, 0, 0, 0, 0); + } + //bind the indices buffer. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); @@ -342,6 +364,12 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun storage->frame.canvas_draw_commands++; + if (p_bones && p_weights) { + //not used so often, so disable when used + glDisableVertexAttribArray(VS::ARRAY_BONES); + glDisableVertexAttribArray(VS::ARRAY_WEIGHTS); + } + glBindVertexArray(0); } @@ -735,7 +763,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); } - _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); + + _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->bones.ptr(), polygon->weights.ptr()); #ifdef GLES_OVER_GL if (polygon->antialiased) { glEnable(GL_LINE_SMOOTH); @@ -921,7 +950,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } _bind_canvas_texture(RID(), RID()); - _draw_polygon(indices, numpoints * 3, numpoints + 1, points, NULL, &circle->color, true); + _draw_polygon(indices, numpoints * 3, numpoints + 1, points, NULL, &circle->color, true, NULL, NULL); //_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); @@ -1068,6 +1097,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons RID canvas_last_material; bool prev_distance_field = false; + bool prev_use_skeleton = false; while (p_item_list) { @@ -1106,6 +1136,35 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons } } + RasterizerStorageGLES3::Skeleton *skeleton = NULL; + + { + //skeleton handling + if (ci->skeleton.is_valid()) { + skeleton = storage->skeleton_owner.getornull(ci->skeleton); + if (!skeleton->use_2d) { + skeleton = NULL; + } else { + state.skeleton_transform = ci->final_transform.affine_inverse() * (p_transform * skeleton->base_transform_2d); + } + } + + bool use_skeleton = skeleton != NULL; + if (prev_use_skeleton != use_skeleton) { + rebind_shader = true; + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, use_skeleton); + prev_use_skeleton = use_skeleton; + } + + if (skeleton) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); + glBindTexture(GL_TEXTURE_2D, skeleton->texture); + state.using_skeleton = true; + } else { + state.using_skeleton = false; + } + } + //begin rect Item *material_owner = ci->material_owner ? ci->material_owner : ci; diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index 1dc17f98d5..73a0f85bc9 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -84,6 +84,8 @@ public: Color canvas_item_modulate; Transform2D extra_matrix; Transform2D final_transform; + bool using_skeleton; + Transform2D skeleton_transform; } state; @@ -123,7 +125,7 @@ public: _FORCE_INLINE_ RasterizerStorageGLES3::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map); _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs); - _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); + _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const int *p_bones, const float *p_weights); _FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index f91ed35331..77ac962e37 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1912,7 +1912,7 @@ void RasterizerStorageGLES3::material_set_param(RID p_material, const StringName Variant RasterizerStorageGLES3::material_get_param(RID p_material, const StringName &p_param) const { const Material *material = material_owner.get(p_material); - ERR_FAIL_COND_V(!material, RID()); + ERR_FAIL_COND_V(!material, Variant()); if (material->params.has(p_param)) return material->params[p_param]; @@ -4496,6 +4496,15 @@ Transform2D RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleto return ret; } +void RasterizerStorageGLES3::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + + ERR_FAIL_COND(!skeleton->use_2d); + + skeleton->base_transform_2d = p_base_transform; +} + void RasterizerStorageGLES3::update_dirty_skeletons() { glActiveTexture(GL_TEXTURE0); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index ef2b247266..def6eaa167 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -868,6 +868,7 @@ public: GLuint texture; SelfList<Skeleton> update_list; Set<RasterizerScene::InstanceBase *> instances; //instances using skeleton + Transform2D base_transform_2d; Skeleton() : update_list(this) { @@ -891,6 +892,7 @@ public: virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const; virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; + virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); /* Light API */ diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 3bbeb1149d..910867c9b1 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -4,6 +4,11 @@ layout(location=0) in highp vec2 vertex; layout(location=3) in vec4 color_attrib; +#ifdef USE_SKELETON +layout(location=6) in uvec4 bone_indices; // attrib:6 +layout(location=7) in vec4 bone_weights; // attrib:7 +#endif + #ifdef USE_TEXTURE_RECT uniform vec4 dst_rect; @@ -51,6 +56,11 @@ out highp vec2 pixel_size_interp; #endif +#ifdef USE_SKELETON +uniform mediump sampler2D skeleton_texture; // texunit:-1 +uniform mat4 skeleton_to_object_local_matrix; +#endif + #ifdef USE_LIGHTING layout(std140) uniform LightData { //ubo:1 @@ -75,7 +85,6 @@ out vec4 light_uv_interp; out vec4 local_rot; - #ifdef USE_SHADOWS out highp vec2 pos; #endif @@ -101,6 +110,7 @@ MATERIAL_UNIFORMS #endif + VERTEX_SHADER_GLOBALS void main() { @@ -146,6 +156,49 @@ void main() { #endif +#ifdef USE_SKELETON + + if (bone_weights!=vec4(0.0)){ //must be a valid bone + //skeleton transform + + ivec4 bone_indicesi = ivec4(bone_indices); + + ivec2 tex_ofs = ivec2( bone_indicesi.x%256, (bone_indicesi.x/256)*2 ); + + highp mat2x4 m = mat2x4( + texelFetch(skeleton_texture,tex_ofs,0), + texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0) + ) * bone_weights.x; + + tex_ofs = ivec2( bone_indicesi.y%256, (bone_indicesi.y/256)*2 ); + + m+= mat2x4( + texelFetch(skeleton_texture,tex_ofs,0), + texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0) + ) * bone_weights.y; + + tex_ofs = ivec2( bone_indicesi.z%256, (bone_indicesi.z/256)*2 ); + + m+= mat2x4( + texelFetch(skeleton_texture,tex_ofs,0), + texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0) + ) * bone_weights.z; + + + tex_ofs = ivec2( bone_indicesi.w%256, (bone_indicesi.w/256)*2 ); + + m+= mat2x4( + texelFetch(skeleton_texture,tex_ofs,0), + texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0) + ) * bone_weights.w; + + mat4 bone_matrix = /*skeleton_to_object_local_matrix */ transpose(mat4(m[0],m[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))); + + outvec = bone_matrix * outvec; + } + +#endif + #define extra_matrix extra_matrix2 { @@ -207,6 +260,7 @@ uniform mediump sampler2D color_texture; // texunit:0 uniform highp vec2 color_texpixel_size; uniform mediump sampler2D normal_texture; // texunit:1 + in highp vec2 uv_interp; in mediump vec4 color_interp; diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 2815fa6406..14d2550000 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -314,6 +314,9 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->commit_action(); } break; + case UVEDIT_GRID_SETTINGS: { + grid_settings->popup_centered_minsize(); + } break; default: { AbstractPolygon2DEditor::_menu_option(p_option); } break; @@ -809,6 +812,8 @@ void Polygon2DEditor::_uv_draw() { if (base_tex.is_null()) return; + String warning; + Transform2D mtx; mtx.elements[2] = -uv_draw_ofs; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); @@ -911,6 +916,50 @@ void Polygon2DEditor::_uv_draw() { if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) { + NodePath bone_path; + for (int i = 0; i < bone_scroll_vb->get_child_count(); i++) { + CheckBox *c = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(i)); + if (c && c->is_pressed()) { + bone_path = node->get_bone_path(i); + break; + } + } + + //draw skeleton + NodePath skeleton_path = node->get_skeleton(); + if (node->has_node(skeleton_path)) { + Skeleton2D *skeleton = Object::cast_to<Skeleton2D>(node->get_node(skeleton_path)); + if (skeleton) { + for (int i = 0; i < skeleton->get_bone_count(); i++) { + + Bone2D *bone = skeleton->get_bone(i); + if (bone->get_rest() == Transform2D(0, 0, 0, 0, 0, 0)) + continue; //not set + + bool current = bone_path == skeleton->get_path_to(bone); + + for (int j = 0; j < bone->get_child_count(); j++) { + + Node2D *n = Object::cast_to<Node2D>(bone->get_child(j)); + if (!n) + continue; + + bool edit_bone = n->has_meta("_edit_bone_") && n->get_meta("_edit_bone_"); + if (edit_bone) { + + Transform2D bone_xform = node->get_global_transform().affine_inverse() * (skeleton->get_global_transform() * bone->get_skeleton_rest()); + Transform2D endpoint_xform = bone_xform * n->get_transform(); + + Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), current ? 5 : 4); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), color, current ? 3 : 2); + } + } + } + } + } + + //draw paint circle uv_edit_draw->draw_circle(bone_paint_pos, bone_paint_radius->get_value() * EDSCALE, Color(1, 1, 1, 0.1)); } @@ -1075,6 +1124,8 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_menu->get_popup()->add_item(TTR("UV->Polygon"), UVEDIT_UV_TO_POLYGON); uv_menu->get_popup()->add_separator(); uv_menu->get_popup()->add_item(TTR("Clear UV"), UVEDIT_UV_CLEAR); + uv_menu->get_popup()->add_separator(); + uv_menu->get_popup()->add_item(TTR("Grid Settings"), UVEDIT_GRID_SETTINGS); uv_menu->get_popup()->connect("id_pressed", this, "_menu_option"); uv_mode_hb->add_child(memnew(VSeparator)); @@ -1097,8 +1148,11 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : b_snap_grid->set_tooltip(TTR("Show Grid")); b_snap_grid->connect("toggled", this, "_set_show_grid"); - uv_mode_hb->add_child(memnew(VSeparator)); - uv_mode_hb->add_child(memnew(Label(TTR("Grid Offset:")))); + grid_settings = memnew(AcceptDialog); + grid_settings->set_title(TTR("Configure Grid:")); + add_child(grid_settings); + VBoxContainer *grid_settings_vb = memnew(VBoxContainer); + grid_settings->add_child(grid_settings_vb); SpinBox *sb_off_x = memnew(SpinBox); sb_off_x->set_min(-256); @@ -1107,7 +1161,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_off_x->set_value(snap_offset.x); sb_off_x->set_suffix("px"); sb_off_x->connect("value_changed", this, "_set_snap_off_x"); - uv_mode_hb->add_child(sb_off_x); + grid_settings_vb->add_margin_child(TTR("Grid Offset X:"), sb_off_x); SpinBox *sb_off_y = memnew(SpinBox); sb_off_y->set_min(-256); @@ -1116,10 +1170,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_off_y->set_value(snap_offset.y); sb_off_y->set_suffix("px"); sb_off_y->connect("value_changed", this, "_set_snap_off_y"); - uv_mode_hb->add_child(sb_off_y); - - uv_mode_hb->add_child(memnew(VSeparator)); - uv_mode_hb->add_child(memnew(Label(TTR("Grid Step:")))); + grid_settings_vb->add_margin_child(TTR("Grid Offset Y:"), sb_off_y); SpinBox *sb_step_x = memnew(SpinBox); sb_step_x->set_min(-256); @@ -1128,7 +1179,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_step_x->set_value(snap_step.x); sb_step_x->set_suffix("px"); sb_step_x->connect("value_changed", this, "_set_snap_step_x"); - uv_mode_hb->add_child(sb_step_x); + grid_settings_vb->add_margin_child(TTR("Grid Step X:"), sb_step_x); SpinBox *sb_step_y = memnew(SpinBox); sb_step_y->set_min(-256); @@ -1137,7 +1188,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_step_y->set_value(snap_step.y); sb_step_y->set_suffix("px"); sb_step_y->connect("value_changed", this, "_set_snap_step_y"); - uv_mode_hb->add_child(sb_step_y); + grid_settings_vb->add_margin_child(TTR("Grid Step Y:"), sb_step_y); uv_mode_hb->add_child(memnew(VSeparator)); uv_icon_zoom = memnew(TextureRect); @@ -1150,7 +1201,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_zoom->set_v_size_flags(SIZE_SHRINK_CENTER); uv_mode_hb->add_child(uv_zoom); - uv_zoom->set_custom_minimum_size(Size2(200, 0)); + uv_zoom->set_custom_minimum_size(Size2(80 * EDSCALE, 0)); uv_zoom_value = memnew(SpinBox); uv_zoom->share(uv_zoom_value); uv_zoom_value->set_custom_minimum_size(Size2(50, 0)); @@ -1166,7 +1217,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : bone_scroll_main_vb = memnew(VBoxContainer); bone_scroll_main_vb->hide(); - sync_bones = memnew(Button(TTR("Sync Bones"))); + sync_bones = memnew(Button(TTR("Sync Bones to Polygon"))); bone_scroll_main_vb->add_child(sync_bones); uv_main_hb->add_child(bone_scroll_main_vb); bone_scroll = memnew(ScrollContainer); diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index b18ead4d98..cf529b39f7 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -45,7 +45,8 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { MODE_EDIT_UV = MODE_CONT, UVEDIT_POLYGON_TO_UV, UVEDIT_UV_TO_POLYGON, - UVEDIT_UV_CLEAR + UVEDIT_UV_CLEAR, + UVEDIT_GRID_SETTINGS }; @@ -91,6 +92,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { int bone_painting_bone; PoolVector<float> prev_weights; Vector2 bone_paint_pos; + AcceptDialog *grid_settings; void _sync_bones(); void _update_bone_list(); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index bda83929fd..1443f22c8f 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -5082,8 +5082,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Tool Rotate"), KEY_E); ED_SHORTCUT("spatial_editor/tool_scale", TTR("Tool Scale"), KEY_R); - ED_SHORTCUT("spatial_editor/display_wireframe", TTR("Display Wireframe"), KEY_Z); - ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F); PopupMenu *p; diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 2427cd966b..92b95963f9 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -744,7 +744,7 @@ ThemeEditor::ThemeEditor() { item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); item->set_editable(0, true); - item->set_text(0, "check"); + item->set_text(0, "Check"); item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); item->set_editable(0, true); @@ -753,7 +753,7 @@ ThemeEditor::ThemeEditor() { item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); item->set_editable(0, true); - item->set_text(0, TTR("Have,Many,Several,Options!")); + item->set_text(0, TTR("Has,Many,Options")); item->set_range(0, 2); VBoxContainer *third_vb = memnew(VBoxContainer); @@ -784,58 +784,6 @@ ThemeEditor::ThemeEditor() { main_hb->add_constant_override("separation", 20 * EDSCALE); - /* - test_h_scroll = memnew( HScrollBar ); - test_h_scroll->set_position( Point2( 25, 225 ) ); - test_h_scroll->set_size( Point2( 150, 5 ) ); - panel->add_child(test_h_scroll); - - line_edit = memnew( LineEdit ); - line_edit->set_position( Point2( 25, 275 ) ); - line_edit->set_size( Point2( 150, 5 ) ); - line_edit->set_text("Line Edit"); - panel->add_child(line_edit); - - test_v_scroll = memnew( VScrollBar ); - test_v_scroll->set_position( Point2( 200, 25 ) ); - test_v_scroll->set_size( Point2( 5, 150 ) ); - panel->add_child(test_v_scroll); - - test_tree = memnew(Tree); - test_tree->set_position( Point2( 300, 25 ) ); - test_tree->set_size( Point2( 200, 200 ) ); - panel->add_child(test_tree); - - - TreeItem *item = test_tree->create_item(); - item->set_editable(0,true); - item->set_text(0,"root"); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - item->set_editable(0,true); - item->set_text(0,"check"); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0,true); - item->set_range_config(0,0,20,0.1); - item->set_range(0,2); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0,true); - item->set_text(0,"Have,Many,Several,Options!")); - item->set_range(0,2); - - Button *fd_button= memnew( Button ); - fd_button->set_position(Point2(300,275)); - fd_button->set_text("Open File Dialog"); - panel->add_child(fd_button); - - test_file_dialog = memnew( EditorFileDialog ); - panel->add_child(test_file_dialog); - - fd_button->connect("pressed", this,"_open_file_dialog"); -*/ - add_del_dialog = memnew(ConfirmationDialog); add_del_dialog->hide(); add_child(add_del_dialog); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 05c3d7529b..21f5e596be 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -160,7 +160,7 @@ void ProjectSettingsEditor::_action_edited() { ti->set_text(0, old_name); add_at = "input/" + old_name; - message->set_text(TTR("Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or '\"'")); + message->set_text(TTR("Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\', or '\"'.")); message->popup_centered(Size2(300, 100) * EDSCALE); return; } diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index ac478c11e3..e0063925b1 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -3273,22 +3273,34 @@ void PropertyEditor::update_tree() { while (hint.begins_with(itos(Variant::ARRAY) + ":")) { type_name += "<Array"; type_name_suffix += ">"; - hint = hint.substr(2, hint.size() - 2); + hint = hint.right(2); } if (hint.find(":") >= 0) { - hint = hint.substr(0, hint.find(":")); + int colon_pos = hint.find(":"); + String hint_string = hint.right(colon_pos + 1); + hint = hint.left(colon_pos); + + PropertyHint property_hint = PROPERTY_HINT_NONE; + if (hint.find("/") >= 0) { - hint = hint.substr(0, hint.find("/")); + int slash_pos = hint.find("/"); + property_hint = PropertyHint(hint.right(slash_pos + 1).to_int()); + hint = hint.left(slash_pos); + } + + if (property_hint == PROPERTY_HINT_RESOURCE_TYPE) { + type_name += "<" + hint_string; + } else { + type_name += "<" + Variant::get_type_name(Variant::Type(hint.to_int())); } - type_name += "<" + Variant::get_type_name(Variant::Type(hint.to_int())); type_name_suffix += ">"; } type_name += type_name_suffix; if (v.is_array()) - item->set_text(1, type_name + "[" + itos(v.call("size")) + "]"); + item->set_text(1, type_name + "(" + itos(v.call("size")) + ")"); else - item->set_text(1, type_name + "[]"); + item->set_text(1, type_name + "()"); if (show_type_icons) item->set_icon(0, get_icon("PoolByteArray", "EditorIcons")); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index a3c4b73ae4..c7654d0e69 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -299,13 +299,24 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi } } -void EditorSpatialGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size) { +void EditorSpatialGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position) { ERR_FAIL_COND(!spatial_node); CubeMesh cubem; cubem.set_size(p_size); + + Array arrays = cubem.surface_get_arrays(0); + PoolVector3Array vertex = arrays[VS::ARRAY_VERTEX]; + PoolVector3Array::Write w = vertex.write(); + + for (int i = 0; i < vertex.size(); ++i) { + w[i] += p_position; + } + + arrays[VS::ARRAY_VERTEX] = vertex; + Ref<ArrayMesh> m = memnew(ArrayMesh); - m->add_surface_from_arrays(cubem.surface_get_primitive_type(0), cubem.surface_get_arrays(0)); + m->add_surface_from_arrays(cubem.surface_get_primitive_type(0), arrays); m->surface_set_material(0, p_material); add_mesh(m); } @@ -2411,7 +2422,7 @@ void ParticlesGizmo::redraw() { gizmo_color.a = 0.1; Ref<Material> solid_material = create_material("particles_solid_material", gizmo_color); - add_solid_box(solid_material, aabb.get_size()); + add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0); } //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index eedab7fdef..b96c75e0c6 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -105,7 +105,7 @@ protected: void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh, const AABB &p_bounds = AABB()); void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1); void add_handles(const Vector<Vector3> &p_handles, bool p_billboard = false, bool p_secondary = false); - void add_solid_box(Ref<Material> &p_material, Vector3 p_size); + void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3()); void set_spatial_node(Spatial *p_node); const Spatial *get_spatial_node() const { return spatial_node; } diff --git a/main/tests/test_oa_hash_map.cpp b/main/tests/test_oa_hash_map.cpp index ac65fdf19c..0e34faace7 100644 --- a/main/tests/test_oa_hash_map.cpp +++ b/main/tests/test_oa_hash_map.cpp @@ -49,7 +49,7 @@ MainLoop *test() { map.set(42, 11880); int value; - map.lookup(42, &value); + map.lookup(42, value); OS::get_singleton()->print("capacity %d\n", map.get_capacity()); OS::get_singleton()->print("elements %d\n", map.get_num_elements()); @@ -72,7 +72,7 @@ MainLoop *test() { uint32_t num_elems = 0; for (int i = 0; i < 500; i++) { int tmp; - if (map.lookup(i, &tmp)) + if (map.lookup(i, tmp) && tmp == i * 2) num_elems++; } @@ -88,7 +88,7 @@ MainLoop *test() { map.set("Godot rocks", 42); for (OAHashMap<String, int>::Iterator it = map.iter(); it.valid; it = map.next_iter(it)) { - OS::get_singleton()->print("map[\"%s\"] = %d\n", it.key->utf8().get_data(), *it.data); + OS::get_singleton()->print("map[\"%s\"] = %d\n", it.key->utf8().get_data(), *it.value); } } diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 9752defa79..c1fe11d6aa 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -1255,7 +1255,7 @@ void CSGBrushOperation::MeshMerge::add_face(const Vector3 &p_a, const Vector3 &p vk.z = int((double(src_points[i].z) + double(vertex_snap) * 0.31234) / double(vertex_snap)); int res; - if (snap_cache.lookup(vk, &res)) { + if (snap_cache.lookup(vk, res)) { indices[i] = res; } else { indices[i] = points.size(); diff --git a/modules/csg/csg.h b/modules/csg/csg.h index d89e542b5e..bb67e1fb36 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -108,7 +108,7 @@ struct CSGBrushOperation { } }; - OAHashMap<VertexKey, int, 64, VertexKeyHash> snap_cache; + OAHashMap<VertexKey, int, VertexKeyHash> snap_cache; Vector<Vector3> points; diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 279edbcec5..1f2f12f54d 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -157,7 +157,7 @@ void CSGShape::_update_shape() { for (int j = 0; j < 3; j++) { Vector3 v = n->faces[i].vertices[j]; Vector3 add; - if (vec_map.lookup(v, &add)) { + if (vec_map.lookup(v, add)) { add += p.normal; } else { add = p.normal; @@ -233,7 +233,7 @@ void CSGShape::_update_shape() { Vector3 normal = p.normal; - if (n->faces[i].smooth && vec_map.lookup(v, &normal)) { + if (n->faces[i].smooth && vec_map.lookup(v, normal)) { normal.normalize(); } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 774e9e62ee..e7b0700e76 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3440,6 +3440,22 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) { tokenizer->advance(); + + String hint_prefix = ""; + bool is_arrayed = false; + + while (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_TYPE && + tokenizer->get_token_type() == Variant::ARRAY && + tokenizer->get_token(1) == GDScriptTokenizer::TK_COMMA) { + tokenizer->advance(); // Array + tokenizer->advance(); // Comma + if (is_arrayed) { + hint_prefix += itos(Variant::ARRAY) + ":"; + } else { + is_arrayed = true; + } + } + if (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_TYPE) { Variant::Type type = tokenizer->get_token_type(); @@ -3455,28 +3471,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; tokenizer->advance(); - String hint_prefix = ""; - - if (type == Variant::ARRAY && tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - tokenizer->advance(); - - while (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_TYPE) { - type = tokenizer->get_token_type(); - - tokenizer->advance(); - - if (type == Variant::ARRAY) { - hint_prefix += itos(Variant::ARRAY) + ":"; - if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - tokenizer->advance(); - } - } else { - hint_prefix += itos(type); - break; - } - } - } - if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { // hint expected next! tokenizer->advance(); @@ -3830,13 +3824,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } break; } } - if (current_export.type == Variant::ARRAY && !hint_prefix.empty()) { - if (current_export.hint) { - hint_prefix += "/" + itos(current_export.hint); - } - current_export.hint_string = hint_prefix + ":" + current_export.hint_string; - current_export.hint = PROPERTY_HINT_NONE; - } } else { @@ -3923,6 +3910,16 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } + if (is_arrayed) { + hint_prefix += itos(current_export.type); + if (current_export.hint) { + hint_prefix += "/" + itos(current_export.hint); + } + current_export.hint_string = hint_prefix + ":" + current_export.hint_string; + current_export.hint = PROPERTY_HINT_TYPE_STRING; + current_export.type = Variant::ARRAY; + } + tokenizer->advance(); } @@ -4090,7 +4087,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { member._export.type=Variant::DICTIONARY; - } else*/ { + } else*/ + { if (subexpr->type != Node::TYPE_CONSTANT) { diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 229c2c6fe8..3e61dd05f4 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -270,7 +270,8 @@ void Line2D::_draw() { lb.indices, lb.vertices, lb.colors, - lb.uvs, + lb.uvs, Vector<int>(), Vector<float>(), + texture_rid); // DEBUG diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index eed26f5399..4d6ebc81c3 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -30,7 +30,7 @@ #include "polygon_2d.h" #include "core/math/geometry.h" - +#include "skeleton_2d.h" Dictionary Polygon2D::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); state["offset"] = offset; @@ -91,8 +91,20 @@ void Polygon2D::_notification(int p_what) { if (polygon.size() < 3) return; + Skeleton2D *skeleton_node = NULL; + if (has_node(skeleton)) { + skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton)); + } + + if (skeleton_node) + VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton()); + else + VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID()); + Vector<Vector2> points; Vector<Vector2> uvs; + Vector<int> bones; + Vector<float> weights; points.resize(polygon.size()); @@ -180,6 +192,70 @@ void Polygon2D::_notification(int p_what) { } } + if (!invert && bone_weights.size()) { + //a skeleton is set! fill indices and weights + int vc = points.size(); + bones.resize(vc * 4); + weights.resize(vc * 4); + + int *bonesw = bones.ptrw(); + float *weightsw = weights.ptrw(); + + for (int i = 0; i < vc * 4; i++) { + bonesw[i] = 0; + weightsw[i] = 0; + } + + for (int i = 0; i < bone_weights.size(); i++) { + if (bone_weights[i].weights.size() != points.size()) { + continue; //different number of vertices, sorry not using. + } + if (!skeleton_node->has_node(bone_weights[i].path)) { + continue; //node does not exist + } + Bone2D *bone = Object::cast_to<Bone2D>(skeleton_node->get_node(bone_weights[i].path)); + if (!bone) { + continue; + } + + int bone_index = bone->get_index_in_skeleton(); + PoolVector<float>::Read r = bone_weights[i].weights.read(); + for (int j = 0; j < vc; j++) { + if (r[j] == 0.0) + continue; //weight is unpainted, skip + //find an index with a weight + for (int k = 0; k < 4; k++) { + if (weightsw[j * 4 + k] < r[j]) { + //this is less than this weight, insert weight! + for (int l = 3; l > k; l--) { + weightsw[j * 4 + l] = weightsw[j * 4 + l - 1]; + bonesw[j * 4 + l] = bonesw[j * 4 + l - 1]; + } + weightsw[j * 4 + k] = r[j]; + bonesw[j * 4 + k] = bone_index; + break; + } + } + } + } + + //normalize the weights + for (int i = 0; i < vc; i++) { + float tw = 0; + for (int j = 0; j < 4; j++) { + tw += weightsw[i * 4 + j]; + } + if (tw == 0) + continue; //unpainted, do nothing + + //normalize + for (int j = 0; j < 4; j++) { + weightsw[i * 4 + j] /= tw; + // print_line("point " + itos(i) + " idx " + itos(j) + " index: " + itos(bonesw[i * 4 + j]) + " weight: " + rtos(weightsw[i * 4 + j])); + } + } + } + Vector<Color> colors; int color_len = vertex_colors.size(); colors.resize(len); @@ -197,7 +273,8 @@ void Polygon2D::_notification(int p_what) { // VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); if (invert || splits.size() == 0) { - VS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID(), RID(), antialiased); + Vector<int> indices = Geometry::triangulate_polygon(points); + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } else { //use splits Vector<int> loop; @@ -268,7 +345,7 @@ void Polygon2D::_notification(int p_what) { //print_line("loops: " + itos(loops.size()) + " indices: " + itos(indices.size())); - VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } } break; @@ -488,9 +565,12 @@ void Polygon2D::_set_bones(const Array &p_bones) { } void Polygon2D::set_skeleton(const NodePath &p_skeleton) { + if (skeleton == p_skeleton) + return; skeleton = p_skeleton; update(); } + NodePath Polygon2D::get_skeleton() const { return skeleton; } diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 3b3561bc1c..9197127235 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -28,6 +28,11 @@ void Bone2D::_notification(int p_what) { skeleton->_make_transform_dirty(); } } + if (p_what == NOTIFICATION_MOVED_IN_PARENT) { + if (skeleton) { + skeleton->_make_bone_setup_dirty(); + } + } if (p_what == NOTIFICATION_EXIT_TREE) { if (skeleton) { @@ -48,12 +53,18 @@ void Bone2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest); ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest); ClassDB::bind_method(D_METHOD("apply_rest"), &Bone2D::apply_rest); + ClassDB::bind_method(D_METHOD("get_skeleton_rest"), &Bone2D::get_skeleton_rest); + ClassDB::bind_method(D_METHOD("get_index_in_skeleton"), &Bone2D::get_index_in_skeleton); + + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D,"rest"),"set_rest","get_rest"); } void Bone2D::set_rest(const Transform2D &p_rest) { rest = p_rest; if (skeleton) skeleton->_make_bone_setup_dirty(); + + update_configuration_warning(); } Transform2D Bone2D::get_rest() const { @@ -73,22 +84,45 @@ void Bone2D::apply_rest() { set_transform(rest); } +int Bone2D::get_index_in_skeleton() const { + ERR_FAIL_COND_V(!skeleton,-1); + skeleton->_update_bone_setup(); + return skeleton_index; +} String Bone2D::get_configuration_warning() const { + + String warning = Node2D::get_configuration_warning(); if (!skeleton) { + if (warning!=String()) { + warning+="\n"; + } if (parent_bone) { - return TTR("This Bone2D chain should end at a Skeleton2D node."); + warning+=TTR("This Bone2D chain should end at a Skeleton2D node."); } else { - return TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."); + warning+=TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."); + } + } + + if (rest==Transform2D(0,0,0,0,0,0)) { + if (warning!=String()) { + warning+="\n"; } + warning+=TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."); + } - return Node2D::get_configuration_warning(); + return warning; } Bone2D::Bone2D() { skeleton = NULL; parent_bone = NULL; + skeleton_index=-1; set_notify_local_transform(true); + //this is a clever hack so the bone knows no rest has been set yet, allowing to show an error. + for(int i=0;i<3;i++) { + rest[i]=Vector2(0,0); + } } ////////////////////////////////////// @@ -114,7 +148,14 @@ void Skeleton2D::_update_bone_setup() { bones.sort(); //sorty so they are always in the same order/index for (int i = 0; i < bones.size(); i++) { - bones[i].rest_inverse = bones[i].bone->get_skeleton_rest(); //bind pose + bones[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose + bones[i].bone->skeleton_index=i; + Bone2D *parent_bone = Object::cast_to<Bone2D>(bones[i].bone->get_parent()); + if (parent_bone) { + bones[i].parent_index=parent_bone->skeleton_index; + } else { + bones[i].parent_index=-1; + } } transform_dirty = true; @@ -142,13 +183,20 @@ void Skeleton2D::_update_transform() { transform_dirty = false; - Transform2D global_xform = get_global_transform(); - Transform2D global_xform_inverse = global_xform.affine_inverse(); + for (int i = 0; i < bones.size(); i++) { + + ERR_CONTINUE(bones[i].parent_index>=i); + if (bones[i].parent_index>=0) { + bones[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform(); + } else { + bones[i].accum_transform = bones[i].bone->get_transform(); + } + } for (int i = 0; i < bones.size(); i++) { - Transform2D final_xform = bones[i].rest_inverse * bones[i].bone->get_relative_transform_to_parent(this); - VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, global_xform * (final_xform * global_xform_inverse)); + Transform2D final_xform = bones[i].accum_transform * bones[i].rest_inverse; + VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform); } } @@ -179,10 +227,12 @@ void Skeleton2D::_notification(int p_what) { _update_bone_setup(); if (transform_dirty) _update_transform(); + + request_ready(); } if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - _make_transform_dirty(); + VS::get_singleton()->skeleton_set_base_transform_2d(skeleton,get_global_transform()); } } @@ -203,6 +253,7 @@ void Skeleton2D::_bind_methods() { Skeleton2D::Skeleton2D() { bone_setup_dirty = true; transform_dirty = true; + skeleton = VS::get_singleton()->skeleton_create(); } diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 49199f684f..9ae74b56d3 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -12,6 +12,9 @@ class Bone2D : public Node2D { Skeleton2D *skeleton; Transform2D rest; +friend class Skeleton2D; + int skeleton_index; + protected: void _notification(int p_what); static void _bind_methods(); @@ -24,6 +27,8 @@ public: String get_configuration_warning() const; + int get_index_in_skeleton() const; + Bone2D(); }; @@ -37,6 +42,8 @@ class Skeleton2D : public Node2D { return p_bone.bone->is_greater_than(bone); } Bone2D *bone; + int parent_index; + Transform2D accum_transform; Transform2D rest_inverse; }; diff --git a/scene/3d/camera.h b/scene/3d/camera.h index 109bf3adc6..1b506e0c4f 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -132,9 +132,9 @@ public: virtual Transform get_camera_transform() const; - Vector3 project_ray_normal(const Point2 &p_pos) const; + virtual Vector3 project_ray_normal(const Point2 &p_pos) const; virtual Vector3 project_ray_origin(const Point2 &p_pos) const; - Vector3 project_local_ray_normal(const Point2 &p_pos) const; + virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; bool is_position_behind(const Vector3 &p_pos) const; virtual Vector3 project_position(const Point2 &p_point) const; diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index d1bd059b63..a39ac5a8f5 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -1227,28 +1227,19 @@ void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) { emission_point_texture = p_points; - RID texture; - if (p_points.is_valid()) - texture = p_points->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points); } void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normals) { emission_normal_texture = p_normals; - RID texture; - if (p_normals.is_valid()) - texture = p_normals->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals); } void ParticlesMaterial::set_emission_color_texture(const Ref<Texture> &p_colors) { emission_color_texture = p_colors; - RID texture; - if (p_colors.is_valid()) - texture = p_colors->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors); _queue_shader_change(); } @@ -1310,10 +1301,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail curve->ensure_default_setup(); } - RID texture; - if (p_trail_size_modifier.is_valid()) - texture = p_trail_size_modifier->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve); _queue_shader_change(); } @@ -1325,10 +1313,7 @@ Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const { void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) { trail_color_modifier = p_trail_color_modifier; - RID texture; - if (p_trail_color_modifier.is_valid()) - texture = p_trail_color_modifier->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier); _queue_shader_change(); } diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 8bf112b0de..c49388436b 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -325,6 +325,7 @@ public: virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; + virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; /* Light API */ @@ -735,6 +736,8 @@ public: Vector<Point2> points; Vector<Point2> uvs; Vector<Color> colors; + Vector<int> bones; + Vector<float> weights; RID texture; RID normal_map; int count; @@ -812,6 +815,8 @@ public: mutable bool rect_dirty; mutable Rect2 rect; RID material; + RID skeleton; + Item *next; struct CopyBackBuffer { diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index dd8d07f00d..6439ba8509 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -694,7 +694,7 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2 canvas_item->commands.push_back(polygon); } -void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, int p_count, RID p_normal_map) { +void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count, RID p_normal_map) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -702,6 +702,8 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector int ps = p_points.size(); ERR_FAIL_COND(!p_colors.empty() && p_colors.size() != ps && p_colors.size() != 1); ERR_FAIL_COND(!p_uvs.empty() && p_uvs.size() != ps); + ERR_FAIL_COND(!p_bones.empty() && p_bones.size() != ps * 4); + ERR_FAIL_COND(!p_weights.empty() && p_weights.size() != ps * 4); Vector<int> indices = p_indices; @@ -726,6 +728,8 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector polygon->points = p_points; polygon->uvs = p_uvs; polygon->colors = p_colors; + polygon->bones = p_bones; + polygon->weights = p_weights; polygon->indices = indices; polygon->count = count; polygon->antialiased = false; diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 6a5a7623b6..4d9398a17e 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -51,8 +51,6 @@ public: Vector<Item *> child_items; - RID skeleton; - Item() { children_order_dirty = true; E = NULL; @@ -183,7 +181,7 @@ public: void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, VS::NinePatchAxisMode p_x_axis_mode = VS::NINE_PATCH_STRETCH, VS::NinePatchAxisMode p_y_axis_mode = VS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID()); void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID()); void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false); - void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()); + void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()); void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()); void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()); void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index a94e110b5d..5b7ea34cfe 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -285,6 +285,7 @@ public: BIND2RC(Transform, skeleton_bone_get_transform, RID, int) BIND3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &) BIND2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int) + BIND2(skeleton_set_base_transform_2d, RID, const Transform2D &) /* Light API */ @@ -580,7 +581,7 @@ public: BIND11(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID) BIND7(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID) BIND7(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, bool) - BIND8(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, int, RID) + BIND10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID) BIND4(canvas_item_add_mesh, RID, const RID &, RID, RID) BIND4(canvas_item_add_multimesh, RID, RID, RID, RID) BIND6(canvas_item_add_particles, RID, RID, RID, RID, int, int) diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index b91f80d137..5b163e4ac9 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -221,6 +221,7 @@ public: FUNC2RC(Transform, skeleton_bone_get_transform, RID, int) FUNC3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &) FUNC2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int) + FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &) /* Light API */ @@ -498,7 +499,7 @@ public: FUNC11(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID) FUNC7(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID) FUNC7(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, bool) - FUNC8(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, int, RID) + FUNC10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID) FUNC4(canvas_item_add_mesh, RID, const RID &, RID, RID) FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID) FUNC6(canvas_item_add_particles, RID, RID, RID, RID, int, int) diff --git a/servers/visual_server.h b/servers/visual_server.h index 537588fd6f..a92480f81b 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -351,6 +351,7 @@ public: virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; + virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; /* Light API */ @@ -845,7 +846,7 @@ public: virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID()) = 0; virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID()) = 0; virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false) = 0; - virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0; + virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0; virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0; virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0; virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, int p_h_frames, int p_v_frames) = 0; |