2022-03-15 13:29:32 +01:00
|
|
|
/*
|
|
|
|
Copyright (c) 2019-2022 Péter Magyar
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "character_skeleton_2d.h"
|
|
|
|
|
|
|
|
#include "../singletons/ess.h"
|
|
|
|
|
|
|
|
#include "../data/items/model_visual.h"
|
|
|
|
|
|
|
|
#include "../defines.h"
|
|
|
|
|
|
|
|
int CharacterSkeleton2D::get_entity_type() const {
|
|
|
|
return _entity_type;
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::set_entity_type(const int value) {
|
|
|
|
_entity_type = value;
|
|
|
|
|
2022-03-18 10:18:54 +01:00
|
|
|
if (ESS::get_singleton()) {
|
|
|
|
int bones_size = ESS::get_singleton()->skeletons_bones_index_get(_entity_type).get_slice_count(",");
|
|
|
|
int attachment_size = ESS::get_singleton()->skeletons_bone_attachment_index_get(_entity_type).get_slice_count(",");
|
2022-03-15 13:29:32 +01:00
|
|
|
|
2022-03-18 10:18:54 +01:00
|
|
|
_attach_point_nodes.resize(attachment_size);
|
|
|
|
_entries.resize(bones_size);
|
|
|
|
}
|
2022-03-15 13:29:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int CharacterSkeleton2D::get_model_index() {
|
|
|
|
return _model_index;
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::set_model_index(int value) {
|
|
|
|
_model_index = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CharacterSkeleton2D::get_model_dirty() const {
|
|
|
|
return _model_dirty;
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::set_model_dirty(bool value) {
|
|
|
|
_model_dirty = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
NodePath CharacterSkeleton2D::attach_point_path_get(const int index) const {
|
|
|
|
ERR_FAIL_INDEX_V(index, _attach_point_nodes.size(), NodePath());
|
|
|
|
|
|
|
|
return _attach_point_nodes[index].path;
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::attach_point_path_set(const int index, const NodePath &path) {
|
|
|
|
ERR_FAIL_INDEX(index, _attach_point_nodes.size());
|
|
|
|
|
|
|
|
_attach_point_nodes.write[index].path = path;
|
|
|
|
_attach_point_nodes.write[index].node = get_node_or_null(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
Node *CharacterSkeleton2D::attach_point_node_get(const int index) {
|
|
|
|
ERR_FAIL_INDEX_V(index, _attach_point_nodes.size(), NULL);
|
|
|
|
|
|
|
|
return _attach_point_nodes[index].node;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CharacterSkeleton2D::attach_point_count() const {
|
|
|
|
return _attach_point_nodes.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
Node *CharacterSkeleton2D::common_attach_point_node_get(const EntityEnums::CommonCharacterSkeletonPoints index) {
|
|
|
|
ERR_FAIL_INDEX_V(common_attach_point_index_get(index), _attach_point_nodes.size(), NULL);
|
|
|
|
|
|
|
|
return _attach_point_nodes[common_attach_point_index_get(index)].node;
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::common_attach_point_add(const EntityEnums::CommonCharacterSkeletonPoints point, const Ref<PackedScene> &scene) {
|
|
|
|
int index = common_attach_point_index_get(point);
|
|
|
|
|
|
|
|
ERR_FAIL_INDEX(index, _attach_point_nodes.size());
|
|
|
|
|
|
|
|
Node *n = _attach_point_nodes[index].node;
|
|
|
|
|
2022-03-18 04:10:09 +01:00
|
|
|
if (ObjectDB::instance_validate(n) && n->has_method("add")) {
|
2022-03-15 13:29:32 +01:00
|
|
|
n->call("add", scene);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::common_attach_point_add_timed(const EntityEnums::CommonCharacterSkeletonPoints point, const Ref<PackedScene> &scene, const float time) {
|
|
|
|
int index = common_attach_point_index_get(point);
|
|
|
|
|
|
|
|
ERR_FAIL_INDEX(index, _attach_point_nodes.size());
|
|
|
|
|
|
|
|
Node *n = _attach_point_nodes[index].node;
|
|
|
|
|
2022-03-18 04:10:09 +01:00
|
|
|
if (ObjectDB::instance_validate(n) && n->has_method("add_timed")) {
|
2022-03-15 13:29:32 +01:00
|
|
|
n->call("add_timed", scene, time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::common_attach_point_remove(const EntityEnums::CommonCharacterSkeletonPoints point, const Ref<PackedScene> &scene) {
|
|
|
|
int index = common_attach_point_index_get(point);
|
|
|
|
|
|
|
|
ERR_FAIL_INDEX(index, _attach_point_nodes.size());
|
|
|
|
|
|
|
|
Node *n = _attach_point_nodes[index].node;
|
|
|
|
|
2022-03-18 04:10:09 +01:00
|
|
|
if (ObjectDB::instance_validate(n) && n->has_method("remove")) {
|
2022-03-15 13:29:32 +01:00
|
|
|
n->call("remove", scene);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int CharacterSkeleton2D::common_attach_point_index_get(const EntityEnums::CommonCharacterSkeletonPoints point) {
|
|
|
|
return call("_common_attach_point_index_get", point);
|
|
|
|
}
|
|
|
|
int CharacterSkeleton2D::_common_attach_point_index_get(const EntityEnums::CommonCharacterSkeletonPoints point) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NodePath CharacterSkeleton2D::get_animation_player_path() {
|
|
|
|
return _animation_player_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::set_animation_player_path(NodePath path) {
|
|
|
|
_animation_player_path = path;
|
|
|
|
|
|
|
|
Node *node = get_node_or_null(_animation_player_path);
|
|
|
|
|
|
|
|
if (node != NULL) {
|
|
|
|
_animation_player = Object::cast_to<AnimationPlayer>(node);
|
|
|
|
} else {
|
|
|
|
_animation_player = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationPlayer *CharacterSkeleton2D::get_animation_player() {
|
|
|
|
return _animation_player;
|
|
|
|
}
|
|
|
|
|
|
|
|
NodePath CharacterSkeleton2D::get_animation_tree_path() {
|
|
|
|
return _animation_tree_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::set_animation_tree_path(NodePath path) {
|
|
|
|
_animation_tree_path = path;
|
|
|
|
|
|
|
|
Node *node = get_node_or_null(_animation_tree_path);
|
|
|
|
|
|
|
|
if (node != NULL) {
|
|
|
|
_animation_tree = Object::cast_to<AnimationTree>(node);
|
|
|
|
} else {
|
|
|
|
_animation_tree = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationTree *CharacterSkeleton2D::get_animation_tree() {
|
|
|
|
return _animation_tree;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::update_nodes() {
|
|
|
|
for (int i = 0; i < _attach_point_nodes.size(); ++i) {
|
|
|
|
_attach_point_nodes.write[i].node = get_node_or_null(_attach_point_nodes[i].path);
|
|
|
|
}
|
|
|
|
|
|
|
|
set_animation_player_path(_animation_player_path);
|
|
|
|
set_animation_tree_path(_animation_tree_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::add_model_visual(Ref<ModelVisual> vis) {
|
|
|
|
ERR_FAIL_COND(!vis.is_valid());
|
|
|
|
|
|
|
|
for (int i = 0; i < vis->get_visual_entry_count(); ++i) {
|
|
|
|
Ref<ModelVisualEntry> e = vis->get_visual_entry(i);
|
|
|
|
|
|
|
|
if (e.is_valid())
|
|
|
|
add_model_visual_entry(vis, e);
|
|
|
|
}
|
|
|
|
|
|
|
|
_model_visuals.push_back(vis);
|
|
|
|
|
|
|
|
set_process(true);
|
|
|
|
_model_dirty = true;
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::remove_model_visual(Ref<ModelVisual> vis) {
|
|
|
|
ERR_FAIL_COND(!vis.is_valid());
|
|
|
|
|
|
|
|
int index = _model_visuals.find(vis);
|
|
|
|
|
|
|
|
if (index == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (int i = 0; i < _entries.size(); ++i) {
|
|
|
|
Ref<ModelVisualEntry> e = vis->get_visual_entry(i);
|
|
|
|
|
|
|
|
if (e.is_valid())
|
|
|
|
remove_model_visual_entry(vis, e);
|
|
|
|
}
|
|
|
|
|
|
|
|
_model_visuals.remove(index);
|
|
|
|
|
|
|
|
set_process(true);
|
|
|
|
_model_dirty = true;
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::remove_model_visual_index(int index) {
|
|
|
|
ERR_FAIL_INDEX(index, _model_visuals.size());
|
|
|
|
|
|
|
|
set_process(true);
|
|
|
|
_model_dirty = true;
|
|
|
|
|
|
|
|
_model_visuals.remove(index);
|
|
|
|
}
|
|
|
|
Ref<ModelVisual> CharacterSkeleton2D::get_model_visual(int index) {
|
|
|
|
ERR_FAIL_INDEX_V(index, _model_visuals.size(), Ref<ModelVisual>());
|
|
|
|
|
|
|
|
set_process(true);
|
|
|
|
_model_dirty = true;
|
|
|
|
|
|
|
|
return _model_visuals.get(index);
|
|
|
|
}
|
|
|
|
int CharacterSkeleton2D::get_model_visual_count() {
|
|
|
|
return _model_visuals.size();
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::clear_model_visuals() {
|
|
|
|
_model_visuals.clear();
|
|
|
|
|
|
|
|
for (int i = 0; i < _entries.size(); ++i) {
|
|
|
|
_entries.write[i].clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
_model_dirty = true;
|
|
|
|
set_process(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::add_model_visual_entry(Ref<ModelVisual> vis, Ref<ModelVisualEntry> ive) {
|
|
|
|
ERR_FAIL_COND(!vis.is_valid());
|
|
|
|
ERR_FAIL_COND(!ive.is_valid());
|
|
|
|
|
|
|
|
if (ive->get_type() == ModelVisualEntry::MODEL_VISUAL_ENTRY_TYPE_ATTACHMENT) {
|
|
|
|
EntityEnums::CommonCharacterSkeletonPoints target_bone = static_cast<EntityEnums::CommonCharacterSkeletonPoints>(ive->get_bone());
|
|
|
|
|
|
|
|
for (int i = 0; i < ive->get_size(); ++i) {
|
|
|
|
Ref<PackedScene> ps = ive->get_attachment(i);
|
|
|
|
|
|
|
|
if (ps.is_valid()) {
|
|
|
|
common_attach_point_add(target_bone, ps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int target_bone_idx = ive->get_bone();
|
|
|
|
|
2022-03-18 17:19:59 +01:00
|
|
|
ERR_FAIL_INDEX(target_bone_idx, _entries.size());
|
|
|
|
|
2022-03-18 10:18:54 +01:00
|
|
|
Vector<Ref<SkeletonModelEntry>> &entries = _entries.write[target_bone_idx];
|
2022-03-15 13:29:32 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < entries.size(); ++i) {
|
|
|
|
Ref<SkeletonModelEntry> e = entries.get(i);
|
|
|
|
|
|
|
|
if (e->get_entry() == ive) {
|
|
|
|
e->set_count(e->get_count() + 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ref<SkeletonModelEntry> e;
|
|
|
|
e.instance();
|
|
|
|
|
|
|
|
e->set_priority(vis->get_layer());
|
|
|
|
//e->set_color(ive->get_color());
|
|
|
|
e->set_entry(ive);
|
|
|
|
|
|
|
|
entries.push_back(e);
|
|
|
|
_model_dirty = true;
|
|
|
|
set_process(true);
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::remove_model_visual_entry(Ref<ModelVisual> vis, Ref<ModelVisualEntry> ive) {
|
|
|
|
ERR_FAIL_COND(!vis.is_valid());
|
|
|
|
ERR_FAIL_COND(!ive.is_valid());
|
|
|
|
|
|
|
|
if (ive->get_type() == ModelVisualEntry::MODEL_VISUAL_ENTRY_TYPE_ATTACHMENT) {
|
|
|
|
EntityEnums::CommonCharacterSkeletonPoints target_bone = static_cast<EntityEnums::CommonCharacterSkeletonPoints>(ive->get_bone());
|
|
|
|
|
|
|
|
for (int i = 0; i < ive->get_size(); ++i) {
|
|
|
|
Ref<PackedScene> ps = ive->get_attachment(i);
|
|
|
|
|
|
|
|
if (ps.is_valid()) {
|
|
|
|
common_attach_point_remove(target_bone, ps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int target_bone_idx = ive->get_bone();
|
|
|
|
|
2022-03-19 13:52:08 +01:00
|
|
|
ERR_FAIL_INDEX(target_bone_idx, _entries.size());
|
|
|
|
|
2022-03-18 10:18:54 +01:00
|
|
|
Vector<Ref<SkeletonModelEntry>> &entries = _entries.write[target_bone_idx];
|
2022-03-15 13:29:32 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < entries.size(); ++i) {
|
|
|
|
Ref<SkeletonModelEntry> e = entries.get(i);
|
|
|
|
|
|
|
|
if (e->get_entry() == ive) {
|
|
|
|
e->set_count(e->get_count() - 1);
|
|
|
|
|
|
|
|
if (e->get_count() <= 0) {
|
|
|
|
entries.remove(i);
|
|
|
|
|
|
|
|
_model_dirty = true;
|
|
|
|
set_process(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ref<SkeletonModelEntry> CharacterSkeleton2D::get_model_entry(const int bone_index, const int index) {
|
|
|
|
ERR_FAIL_INDEX_V(bone_index, _entries.size(), Ref<SkeletonModelEntry>());
|
|
|
|
ERR_FAIL_INDEX_V(index, _entries[bone_index].size(), Ref<SkeletonModelEntry>());
|
|
|
|
|
|
|
|
return _entries[bone_index].get(index);
|
|
|
|
}
|
|
|
|
int CharacterSkeleton2D::get_model_entry_count(const int bone_index) {
|
|
|
|
ERR_FAIL_INDEX_V(bone_index, _entries.size(), 0);
|
|
|
|
|
|
|
|
return _entries[bone_index].size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::sort_layers() {
|
|
|
|
for (int i = 0; i < _entries.size(); ++i) {
|
2022-03-18 10:18:54 +01:00
|
|
|
Vector<Ref<SkeletonModelEntry>> &entries = _entries.write[i];
|
2022-03-15 13:29:32 +01:00
|
|
|
|
|
|
|
entries.sort_custom<_ModelEntryComparator>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::build_model() {
|
|
|
|
call("_build_model");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::_build_model() {
|
|
|
|
set_process(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
Array CharacterSkeleton2D::merge_mesh_array(Array arr) const {
|
2022-08-19 20:50:20 +02:00
|
|
|
ERR_FAIL_COND_V(arr.size() != RenderingServer::ARRAY_MAX, arr);
|
2022-03-15 13:29:32 +01:00
|
|
|
|
2022-08-19 20:50:20 +02:00
|
|
|
PoolVector3Array verts = arr[RenderingServer::ARRAY_VERTEX];
|
|
|
|
PoolVector3Array normals = arr[RenderingServer::ARRAY_NORMAL];
|
|
|
|
PoolVector2Array uvs = arr[RenderingServer::ARRAY_TEX_UV];
|
|
|
|
PoolColorArray colors = arr[RenderingServer::ARRAY_COLOR];
|
|
|
|
PoolIntArray indices = arr[RenderingServer::ARRAY_INDEX];
|
|
|
|
PoolIntArray bones = arr[RenderingServer::ARRAY_BONES];
|
|
|
|
PoolRealArray weights = arr[RenderingServer::ARRAY_WEIGHTS];
|
2022-03-15 13:29:32 +01:00
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
while (i < verts.size()) {
|
|
|
|
Vector3 v = verts[i];
|
|
|
|
|
|
|
|
Array equals;
|
|
|
|
for (int j = i + 1; j < verts.size(); ++j) {
|
|
|
|
Vector3 vc = verts[j];
|
|
|
|
|
|
|
|
if (Math::is_equal_approx(v.x, vc.x) && Math::is_equal_approx(v.y, vc.y) && Math::is_equal_approx(v.z, vc.z))
|
|
|
|
equals.push_back(j);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int k = 0; k < equals.size(); ++k) {
|
|
|
|
int rem = equals[k];
|
|
|
|
int remk = rem - k;
|
|
|
|
|
|
|
|
verts.remove(remk);
|
|
|
|
normals.remove(remk);
|
|
|
|
uvs.remove(remk);
|
|
|
|
colors.remove(remk);
|
|
|
|
|
|
|
|
int bindex = remk * 4;
|
|
|
|
for (int l = 0; l < 4; ++l) {
|
|
|
|
bones.remove(bindex);
|
|
|
|
weights.remove(bindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = 0; j < indices.size(); ++j) {
|
|
|
|
int indx = indices[j];
|
|
|
|
|
|
|
|
if (indx == remk)
|
|
|
|
indices.set(j, i);
|
|
|
|
else if (indx > remk)
|
|
|
|
indices.set(j, indx - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
2022-08-19 20:50:20 +02:00
|
|
|
arr[RenderingServer::ARRAY_VERTEX] = verts;
|
|
|
|
arr[RenderingServer::ARRAY_NORMAL] = normals;
|
|
|
|
arr[RenderingServer::ARRAY_TEX_UV] = uvs;
|
|
|
|
arr[RenderingServer::ARRAY_COLOR] = colors;
|
|
|
|
arr[RenderingServer::ARRAY_INDEX] = indices;
|
|
|
|
arr[RenderingServer::ARRAY_BONES] = bones;
|
|
|
|
arr[RenderingServer::ARRAY_WEIGHTS] = weights;
|
2022-03-15 13:29:32 +01:00
|
|
|
|
|
|
|
return arr;
|
|
|
|
}
|
|
|
|
Array CharacterSkeleton2D::bake_mesh_array_uv(Array arr, Ref<Texture> tex, float mul_color) const {
|
2022-08-19 20:50:20 +02:00
|
|
|
ERR_FAIL_COND_V(arr.size() != RenderingServer::ARRAY_MAX, arr);
|
2022-03-15 13:29:32 +01:00
|
|
|
ERR_FAIL_COND_V(!tex.is_valid(), arr);
|
|
|
|
|
|
|
|
Ref<Image> img = tex->get_data();
|
|
|
|
|
|
|
|
ERR_FAIL_COND_V(!img.is_valid(), arr);
|
|
|
|
|
|
|
|
Vector2 imgsize = img->get_size();
|
|
|
|
|
2022-08-19 20:50:20 +02:00
|
|
|
PoolVector2Array uvs = arr[RenderingServer::ARRAY_TEX_UV];
|
|
|
|
PoolColorArray colors = arr[RenderingServer::ARRAY_COLOR];
|
2022-03-15 13:29:32 +01:00
|
|
|
|
|
|
|
img->lock();
|
|
|
|
|
|
|
|
for (int i = 0; i < uvs.size(); ++i) {
|
|
|
|
Vector2 uv = uvs[i];
|
|
|
|
uv *= imgsize;
|
|
|
|
|
|
|
|
Color c = img->get_pixelv(uv);
|
|
|
|
|
|
|
|
colors.set(i, colors[i] * c * mul_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
img->unlock();
|
|
|
|
|
2022-08-19 20:50:20 +02:00
|
|
|
arr[RenderingServer::ARRAY_COLOR] = colors;
|
2022-03-15 13:29:32 +01:00
|
|
|
|
|
|
|
return arr;
|
|
|
|
}
|
|
|
|
|
|
|
|
CharacterSkeleton2D::CharacterSkeleton2D() {
|
|
|
|
_model_dirty = false;
|
|
|
|
_model_index = 0;
|
|
|
|
_entity_type = 0;
|
|
|
|
|
|
|
|
_animation_player = NULL;
|
|
|
|
_animation_tree = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CharacterSkeleton2D::~CharacterSkeleton2D() {
|
|
|
|
_attach_point_nodes.clear();
|
|
|
|
|
|
|
|
for (int i = 0; i < _entries.size(); ++i) {
|
|
|
|
_entries.write[i].clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
_entries.clear();
|
|
|
|
|
|
|
|
_model_visuals.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::_notification(int p_what) {
|
|
|
|
switch (p_what) {
|
|
|
|
case NOTIFICATION_ENTER_TREE: {
|
|
|
|
update_nodes();
|
|
|
|
} break;
|
|
|
|
case NOTIFICATION_PROCESS: {
|
|
|
|
if (_model_dirty)
|
|
|
|
build_model();
|
|
|
|
} break;
|
|
|
|
case NOTIFICATION_EXIT_TREE: {
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CharacterSkeleton2D::_set(const StringName &p_name, const Variant &p_value) {
|
|
|
|
String name = p_name;
|
|
|
|
|
|
|
|
if (name.begins_with("attach_point_paths")) {
|
|
|
|
int index = name.get_slicec('/', 1).get_slicec('_', 0).to_int();
|
|
|
|
|
|
|
|
if (index >= _attach_point_nodes.size()) {
|
|
|
|
_attach_point_nodes.resize(index + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
NodePath np = p_value;
|
|
|
|
|
|
|
|
_attach_point_nodes.write[index].path = np;
|
|
|
|
|
|
|
|
if (is_inside_tree())
|
|
|
|
_attach_point_nodes.write[index].node = get_node_or_null(p_value);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool CharacterSkeleton2D::_get(const StringName &p_name, Variant &r_ret) const {
|
|
|
|
String name = p_name;
|
|
|
|
|
|
|
|
if (name.begins_with("attach_point_paths")) {
|
|
|
|
int index = name.get_slicec('/', 1).get_slicec('_', 0).to_int();
|
|
|
|
|
|
|
|
if (index >= _attach_point_nodes.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
r_ret = _attach_point_nodes[index].path;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
void CharacterSkeleton2D::_get_property_list(List<PropertyInfo> *p_list) const {
|
|
|
|
if (ESS::get_singleton()->skeletons_bone_attachments_count() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
String bones = ESS::get_singleton()->skeletons_bone_attachment_index_get(_entity_type);
|
|
|
|
int slicec = bones.get_slice_count(",");
|
|
|
|
|
|
|
|
for (int i = 0; i < slicec; ++i) {
|
|
|
|
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attach_point_paths/" + itos(i) + "_" + bones.get_slicec(',', i)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::_validate_property(PropertyInfo &property) const {
|
|
|
|
if (property.name == "entity_type") {
|
|
|
|
property.hint_string = ESS::get_singleton()->entity_types_get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CharacterSkeleton2D::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("get_entity_type"), &CharacterSkeleton2D::get_entity_type);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_entity_type", "value"), &CharacterSkeleton2D::set_entity_type);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "entity_type", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_entity_type", "get_entity_type");
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("get_model_index"), &CharacterSkeleton2D::get_model_index);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_model_index", "value"), &CharacterSkeleton2D::set_model_index);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "model_index"), "set_model_index", "get_model_index");
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("add_model_visual", "vis"), &CharacterSkeleton2D::add_model_visual);
|
|
|
|
ClassDB::bind_method(D_METHOD("remove_model_visual", "vis"), &CharacterSkeleton2D::remove_model_visual);
|
|
|
|
ClassDB::bind_method(D_METHOD("remove_model_visual_index", "index"), &CharacterSkeleton2D::remove_model_visual_index);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_model_visual", "index"), &CharacterSkeleton2D::get_model_visual);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_model_visual_count"), &CharacterSkeleton2D::get_model_visual_count);
|
|
|
|
ClassDB::bind_method(D_METHOD("clear_model_visuals"), &CharacterSkeleton2D::clear_model_visuals);
|
|
|
|
|
|
|
|
BIND_VMETHOD(MethodInfo("_build_model"));
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("get_model_dirty"), &CharacterSkeleton2D::get_model_dirty);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_model_dirty", "value"), &CharacterSkeleton2D::set_model_dirty);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "model_dirty"), "set_model_dirty", "get_model_dirty");
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("get_animation_player_path"), &CharacterSkeleton2D::get_animation_player_path);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_animation_player_path", "path"), &CharacterSkeleton2D::set_animation_player_path);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "animation_player_path"), "set_animation_player_path", "get_animation_player_path");
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("get_animation_tree_path"), &CharacterSkeleton2D::get_animation_tree_path);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_animation_tree_path", "path"), &CharacterSkeleton2D::set_animation_tree_path);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "animation_tree_path"), "set_animation_tree_path", "get_animation_tree_path");
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("add_model_visual_entry", "vis", "ive"), &CharacterSkeleton2D::add_model_visual_entry);
|
|
|
|
ClassDB::bind_method(D_METHOD("remove_model_visual_entry", "vis", "ive"), &CharacterSkeleton2D::remove_model_visual_entry);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_model_entry", "bone_index", "index"), &CharacterSkeleton2D::get_model_entry);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_model_entry_count", "bone_index"), &CharacterSkeleton2D::get_model_entry_count);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("sort_layers"), &CharacterSkeleton2D::sort_layers);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("build_model"), &CharacterSkeleton2D::build_model);
|
|
|
|
ClassDB::bind_method(D_METHOD("_build_model"), &CharacterSkeleton2D::_build_model);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("merge_mesh_array", "arr"), &CharacterSkeleton2D::merge_mesh_array);
|
|
|
|
ClassDB::bind_method(D_METHOD("bake_mesh_array_uv", "arr", "tex", "mul_color"), &CharacterSkeleton2D::bake_mesh_array_uv, DEFVAL(0.7));
|
|
|
|
|
|
|
|
//Bone Paths
|
|
|
|
ClassDB::bind_method(D_METHOD("attach_point_path_get", "index"), &CharacterSkeleton2D::attach_point_path_get);
|
|
|
|
ClassDB::bind_method(D_METHOD("attach_point_path_set", "index", "path"), &CharacterSkeleton2D::attach_point_path_set);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("attach_point_node_get", "index"), &CharacterSkeleton2D::attach_point_node_get);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("attach_point_count"), &CharacterSkeleton2D::attach_point_count);
|
|
|
|
|
|
|
|
BIND_VMETHOD(MethodInfo("_common_attach_point_index_get", PropertyInfo(Variant::INT, "point", PROPERTY_HINT_NONE, EntityEnums::BINDING_STRING_COMMON_CHARCATER_SKELETON_POINTS)));
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("common_attach_point_node_get", "point"), &CharacterSkeleton2D::common_attach_point_node_get);
|
|
|
|
ClassDB::bind_method(D_METHOD("common_attach_point_add", "point", "scene"), &CharacterSkeleton2D::common_attach_point_add);
|
|
|
|
ClassDB::bind_method(D_METHOD("common_attach_point_add_timed", "point", "scene", "time"), &CharacterSkeleton2D::common_attach_point_add_timed);
|
|
|
|
ClassDB::bind_method(D_METHOD("common_attach_point_remove", "point", "scene"), &CharacterSkeleton2D::common_attach_point_remove);
|
|
|
|
ClassDB::bind_method(D_METHOD("common_attach_point_index_get", "point"), &CharacterSkeleton2D::common_attach_point_index_get);
|
|
|
|
ClassDB::bind_method(D_METHOD("_common_attach_point_index_get", "point"), &CharacterSkeleton2D::_common_attach_point_index_get);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("get_animation_player"), &CharacterSkeleton2D::get_animation_player);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_animation_tree"), &CharacterSkeleton2D::get_animation_tree);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("update_nodes"), &CharacterSkeleton2D::update_nodes);
|
|
|
|
}
|