feature/blend_tree_editor #1
@ -49,125 +49,6 @@ void BLTAnimationNode::_animation_node_removed(const ObjectID &p_oid, const Stri
|
|||||||
emit_signal(SNAME("animation_node_removed"), p_oid, p_node);
|
emit_signal(SNAME("animation_node_removed"), p_oid, p_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BLTAnimationNodeBlendTree::_bind_methods() {
|
|
||||||
ClassDB::bind_method(D_METHOD("add_node", "animation_node"), &BLTAnimationNodeBlendTree::add_node);
|
|
||||||
ClassDB::bind_method(D_METHOD("remove_node", "animation_node"), &BLTAnimationNodeBlendTree::remove_node);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_node", "node_name"), &BLTAnimationNodeBlendTree::get_node);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_output_node"), &BLTAnimationNodeBlendTree::get_output_node);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_node_names"), &BLTAnimationNodeBlendTree::get_node_names_as_typed_array);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("is_connection_valid", "source_node", "target_node", "target_port_name"), &BLTAnimationNodeBlendTree::is_connection_valid);
|
|
||||||
ClassDB::bind_method(D_METHOD("add_connection", "source_node", "target_node", "target_port_name"), &BLTAnimationNodeBlendTree::add_connection);
|
|
||||||
ClassDB::bind_method(D_METHOD("remove_connection", "source_node", "target_node", "target_port_name"), &BLTAnimationNodeBlendTree::remove_connection);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_connections"), &BLTAnimationNodeBlendTree::get_connections_as_array);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_graph_offset", "graph_offset"), &BLTAnimationNodeBlendTree::set_graph_offset);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_graph_offset"), &BLTAnimationNodeBlendTree::get_graph_offset);
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
|
|
||||||
|
|
||||||
BIND_CONSTANT(CONNECTION_OK);
|
|
||||||
BIND_CONSTANT(CONNECTION_ERROR_GRAPH_ALREADY_INITIALIZED);
|
|
||||||
BIND_CONSTANT(CONNECTION_ERROR_NO_SOURCE_NODE);
|
|
||||||
BIND_CONSTANT(CONNECTION_ERROR_NO_TARGET_NODE);
|
|
||||||
BIND_CONSTANT(CONNECTION_ERROR_PARENT_EXISTS);
|
|
||||||
BIND_CONSTANT(CONNECTION_ERROR_TARGET_PORT_NOT_FOUND);
|
|
||||||
BIND_CONSTANT(CONNECTION_ERROR_TARGET_PORT_ALREADY_CONNECTED);
|
|
||||||
BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_CREATES_LOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BLTAnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
|
|
||||||
for (const Ref<BLTAnimationNode> &node : tree_graph.nodes) {
|
|
||||||
String prop_name = node->get_name();
|
|
||||||
if (prop_name != "Output") {
|
|
||||||
p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
|
|
||||||
}
|
|
||||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + prop_name + "/graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
|
||||||
}
|
|
||||||
|
|
||||||
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BLTAnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_value) const {
|
|
||||||
String prop_name = p_name;
|
|
||||||
if (prop_name.begins_with("nodes/")) {
|
|
||||||
String node_name = prop_name.get_slicec('/', 1);
|
|
||||||
String what = prop_name.get_slicec('/', 2);
|
|
||||||
int node_index = find_node_index_by_name(node_name);
|
|
||||||
|
|
||||||
if (what == "node") {
|
|
||||||
if (node_index != -1) {
|
|
||||||
r_value = tree_graph.nodes[node_index];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (what == "graph_offset") {
|
|
||||||
if (node_index != -1) {
|
|
||||||
r_value = tree_graph.nodes[node_index]->position;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (prop_name == "node_connections") {
|
|
||||||
Array conns;
|
|
||||||
conns.resize(tree_graph.connections.size() * 3);
|
|
||||||
|
|
||||||
int idx = 0;
|
|
||||||
for (const BLTBlendTreeConnection &connection : tree_graph.connections) {
|
|
||||||
conns[idx * 3 + 0] = connection.target_node->get_name();
|
|
||||||
conns[idx * 3 + 1] = connection.target_node->get_input_index(connection.target_port_name);
|
|
||||||
conns[idx * 3 + 2] = connection.source_node->get_name();
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
r_value = conns;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BLTAnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
|
|
||||||
String prop_name = p_name;
|
|
||||||
if (prop_name.begins_with("nodes/")) {
|
|
||||||
String node_name = prop_name.get_slicec('/', 1);
|
|
||||||
String what = prop_name.get_slicec('/', 2);
|
|
||||||
|
|
||||||
if (what == "node") {
|
|
||||||
Ref<BLTAnimationNode> anode = p_value;
|
|
||||||
if (anode.is_valid()) {
|
|
||||||
anode->set_name(node_name);
|
|
||||||
add_node(anode);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (what == "graph_offset") {
|
|
||||||
int node_index = find_node_index_by_name(node_name);
|
|
||||||
if (node_index > -1) {
|
|
||||||
tree_graph.nodes[node_index]->position = p_value;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (prop_name == "node_connections") {
|
|
||||||
Array conns = p_value;
|
|
||||||
ERR_FAIL_COND_V(conns.size() % 3 != 0, false);
|
|
||||||
|
|
||||||
for (int i = 0; i < conns.size(); i += 3) {
|
|
||||||
int target_node_index = find_node_index_by_name(conns[i]);
|
|
||||||
int target_node_port_index = conns[i + 1];
|
|
||||||
int source_node_index = find_node_index_by_name(conns[i + 2]);
|
|
||||||
|
|
||||||
Ref<BLTAnimationNode> target_node = tree_graph.nodes[target_node_index];
|
|
||||||
Vector<StringName> target_input_names = target_node->get_input_names();
|
|
||||||
|
|
||||||
add_connection(tree_graph.nodes[source_node_index], target_node, target_input_names[target_node_port_index]);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationData::sample_from_animation(const Ref<Animation> &animation, const Skeleton3D *skeleton_3d, double p_time) {
|
void AnimationData::sample_from_animation(const Ref<Animation> &animation, const Skeleton3D *skeleton_3d, double p_time) {
|
||||||
GodotProfileZone("AnimationData::sample_from_animation");
|
GodotProfileZone("AnimationData::sample_from_animation");
|
||||||
|
|
||||||
@ -273,6 +154,9 @@ void AnimationDataAllocator::register_track_values(const Ref<Animation> &animati
|
|||||||
default_data.allocate_track_values(animation, skeleton_3d);
|
default_data.allocate_track_values(animation, skeleton_3d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// BLTAnimationNodeSampler
|
||||||
|
//
|
||||||
bool BLTAnimationNodeSampler::initialize(GraphEvaluationContext &context) {
|
bool BLTAnimationNodeSampler::initialize(GraphEvaluationContext &context) {
|
||||||
if (!BLTAnimationNode::initialize(context)) {
|
if (!BLTAnimationNode::initialize(context)) {
|
||||||
return false;
|
return false;
|
||||||
@ -428,6 +312,34 @@ void BLTAnimationNodeSampler::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("get_animations"), &BLTAnimationNodeSampler::get_animations_as_typed_array);
|
ClassDB::bind_method(D_METHOD("get_animations"), &BLTAnimationNodeSampler::get_animations_as_typed_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// BLTAnimationNodeTimeScale
|
||||||
|
//
|
||||||
|
void BLTAnimationNodeTimeScale::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||||
|
p_list->push_back(PropertyInfo(Variant::FLOAT, scale_name, PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BLTAnimationNodeTimeScale::_get(const StringName &p_name, Variant &r_value) const {
|
||||||
|
if (p_name == scale_name) {
|
||||||
|
r_value = scale;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BLTAnimationNodeTimeScale::_set(const StringName &p_name, const Variant &p_value) {
|
||||||
|
if (p_name == scale_name) {
|
||||||
|
scale = p_value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// BLTAnimationNodeBlend2
|
||||||
|
//
|
||||||
void BLTAnimationNodeBlend2::evaluate(GraphEvaluationContext &context, const LocalVector<AnimationData *> &inputs, AnimationData &output) {
|
void BLTAnimationNodeBlend2::evaluate(GraphEvaluationContext &context, const LocalVector<AnimationData *> &inputs, AnimationData &output) {
|
||||||
GodotProfileZone("AnimationBlend2Node::evaluate");
|
GodotProfileZone("AnimationBlend2Node::evaluate");
|
||||||
|
|
||||||
@ -494,6 +406,9 @@ bool BLTAnimationNodeBlend2::_set(const StringName &p_name, const Variant &p_val
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// BLTAnimationNodeBlendTree
|
||||||
|
//
|
||||||
BLTAnimationNodeBlendTree::BLTBlendTreeGraph::BLTBlendTreeGraph() {
|
BLTAnimationNodeBlendTree::BLTBlendTreeGraph::BLTBlendTreeGraph() {
|
||||||
Ref<BLTAnimationNodeOutput> output_node;
|
Ref<BLTAnimationNodeOutput> output_node;
|
||||||
output_node.instantiate();
|
output_node.instantiate();
|
||||||
@ -761,3 +676,122 @@ BLTAnimationNodeBlendTree::ConnectionError BLTAnimationNodeBlendTree::BLTBlendTr
|
|||||||
|
|
||||||
return CONNECTION_OK;
|
return CONNECTION_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BLTAnimationNodeBlendTree::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("add_node", "animation_node"), &BLTAnimationNodeBlendTree::add_node);
|
||||||
|
ClassDB::bind_method(D_METHOD("remove_node", "animation_node"), &BLTAnimationNodeBlendTree::remove_node);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_node", "node_name"), &BLTAnimationNodeBlendTree::get_node);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_output_node"), &BLTAnimationNodeBlendTree::get_output_node);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_node_names"), &BLTAnimationNodeBlendTree::get_node_names_as_typed_array);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("is_connection_valid", "source_node", "target_node", "target_port_name"), &BLTAnimationNodeBlendTree::is_connection_valid);
|
||||||
|
ClassDB::bind_method(D_METHOD("add_connection", "source_node", "target_node", "target_port_name"), &BLTAnimationNodeBlendTree::add_connection);
|
||||||
|
ClassDB::bind_method(D_METHOD("remove_connection", "source_node", "target_node", "target_port_name"), &BLTAnimationNodeBlendTree::remove_connection);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_connections"), &BLTAnimationNodeBlendTree::get_connections_as_array);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_graph_offset", "graph_offset"), &BLTAnimationNodeBlendTree::set_graph_offset);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_graph_offset"), &BLTAnimationNodeBlendTree::get_graph_offset);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
|
||||||
|
|
||||||
|
BIND_CONSTANT(CONNECTION_OK);
|
||||||
|
BIND_CONSTANT(CONNECTION_ERROR_GRAPH_ALREADY_INITIALIZED);
|
||||||
|
BIND_CONSTANT(CONNECTION_ERROR_NO_SOURCE_NODE);
|
||||||
|
BIND_CONSTANT(CONNECTION_ERROR_NO_TARGET_NODE);
|
||||||
|
BIND_CONSTANT(CONNECTION_ERROR_PARENT_EXISTS);
|
||||||
|
BIND_CONSTANT(CONNECTION_ERROR_TARGET_PORT_NOT_FOUND);
|
||||||
|
BIND_CONSTANT(CONNECTION_ERROR_TARGET_PORT_ALREADY_CONNECTED);
|
||||||
|
BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_CREATES_LOOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLTAnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||||
|
for (const Ref<BLTAnimationNode> &node : tree_graph.nodes) {
|
||||||
|
String prop_name = node->get_name();
|
||||||
|
if (prop_name != "Output") {
|
||||||
|
p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
|
||||||
|
}
|
||||||
|
p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + prop_name + "/graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BLTAnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_value) const {
|
||||||
|
String prop_name = p_name;
|
||||||
|
if (prop_name.begins_with("nodes/")) {
|
||||||
|
String node_name = prop_name.get_slicec('/', 1);
|
||||||
|
String what = prop_name.get_slicec('/', 2);
|
||||||
|
int node_index = find_node_index_by_name(node_name);
|
||||||
|
|
||||||
|
if (what == "node") {
|
||||||
|
if (node_index != -1) {
|
||||||
|
r_value = tree_graph.nodes[node_index];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (what == "graph_offset") {
|
||||||
|
if (node_index != -1) {
|
||||||
|
r_value = tree_graph.nodes[node_index]->position;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (prop_name == "node_connections") {
|
||||||
|
Array conns;
|
||||||
|
conns.resize(tree_graph.connections.size() * 3);
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (const BLTBlendTreeConnection &connection : tree_graph.connections) {
|
||||||
|
conns[idx * 3 + 0] = connection.target_node->get_name();
|
||||||
|
conns[idx * 3 + 1] = connection.target_node->get_input_index(connection.target_port_name);
|
||||||
|
conns[idx * 3 + 2] = connection.source_node->get_name();
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
r_value = conns;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BLTAnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
|
||||||
|
String prop_name = p_name;
|
||||||
|
if (prop_name.begins_with("nodes/")) {
|
||||||
|
String node_name = prop_name.get_slicec('/', 1);
|
||||||
|
String what = prop_name.get_slicec('/', 2);
|
||||||
|
|
||||||
|
if (what == "node") {
|
||||||
|
Ref<BLTAnimationNode> anode = p_value;
|
||||||
|
if (anode.is_valid()) {
|
||||||
|
anode->set_name(node_name);
|
||||||
|
add_node(anode);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (what == "graph_offset") {
|
||||||
|
int node_index = find_node_index_by_name(node_name);
|
||||||
|
if (node_index > -1) {
|
||||||
|
tree_graph.nodes[node_index]->position = p_value;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (prop_name == "node_connections") {
|
||||||
|
Array conns = p_value;
|
||||||
|
ERR_FAIL_COND_V(conns.size() % 3 != 0, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < conns.size(); i += 3) {
|
||||||
|
int target_node_index = find_node_index_by_name(conns[i]);
|
||||||
|
int target_node_port_index = conns[i + 1];
|
||||||
|
int source_node_index = find_node_index_by_name(conns[i + 2]);
|
||||||
|
|
||||||
|
Ref<BLTAnimationNode> target_node = tree_graph.nodes[target_node_index];
|
||||||
|
Vector<StringName> target_input_names = target_node->get_input_names();
|
||||||
|
|
||||||
|
add_connection(tree_graph.nodes[source_node_index], target_node, target_input_names[target_node_port_index]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@ -105,7 +105,8 @@ struct AnimationData {
|
|||||||
buffer = other.buffer;
|
buffer = other.buffer;
|
||||||
}
|
}
|
||||||
AnimationData(AnimationData &&other) noexcept :
|
AnimationData(AnimationData &&other) noexcept :
|
||||||
value_buffer_offset(std::exchange(other.value_buffer_offset, AHashMap<Animation::TypeHash, size_t, HashHasher>())),
|
// We skip copying the offset as that should be identical for all nodes within a BLTAnimationGraph.
|
||||||
|
// value_buffer_offset(std::exchange(other.value_buffer_offset, AHashMap<Animation::TypeHash, size_t, HashHasher>())),
|
||||||
buffer(std::exchange(other.buffer, LocalVector<uint8_t>())) {
|
buffer(std::exchange(other.buffer, LocalVector<uint8_t>())) {
|
||||||
}
|
}
|
||||||
AnimationData &operator=(const AnimationData &other) {
|
AnimationData &operator=(const AnimationData &other) {
|
||||||
@ -301,9 +302,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void evaluate(GraphEvaluationContext &context, const LocalVector<AnimationData *> &input_datas, AnimationData &output_data) {
|
virtual void evaluate(GraphEvaluationContext &context, const LocalVector<AnimationData *> &input_datas, AnimationData &output_data) {
|
||||||
|
GodotProfileZone("AnimationNode::evaluate");
|
||||||
// By default, use the AnimationData of the first input.
|
// By default, use the AnimationData of the first input.
|
||||||
if (input_datas.size() > 0) {
|
if (input_datas.size() > 0) {
|
||||||
output_data = *input_datas[0];
|
output_data = std::move(*input_datas[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,6 +367,47 @@ protected:
|
|||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BLTAnimationNodeTimeScale : public BLTAnimationNode {
|
||||||
|
GDCLASS(BLTAnimationNodeTimeScale, BLTAnimationNode);
|
||||||
|
|
||||||
|
public:
|
||||||
|
float scale = 1.0f;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ref<Animation> animation;
|
||||||
|
|
||||||
|
Vector<StringName> get_input_names() const override {
|
||||||
|
return { "Input" };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initialize(GraphEvaluationContext &context) override {
|
||||||
|
node_time_info = {};
|
||||||
|
// TODO: it should not be necessary to force looping here. node_time_info.loop_mode = Animation::LOOP_LINEAR;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void calculate_sync_track(const Vector<Ref<BLTAnimationNode>> &input_nodes) override {
|
||||||
|
if (node_time_info.is_synced) {
|
||||||
|
node_time_info.sync_track = input_nodes[0]->node_time_info.sync_track;
|
||||||
|
node_time_info.sync_track.duration *= scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void update_time(double p_time) override {
|
||||||
|
if (node_time_info.is_synced) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLTAnimationNode::update_time(p_time * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||||
|
bool _get(const StringName &p_name, Variant &r_value) const;
|
||||||
|
bool _set(const StringName &p_name, const Variant &p_value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
StringName scale_name = PNAME("scale");
|
||||||
|
};
|
||||||
|
|
||||||
class BLTAnimationNodeOutput : public BLTAnimationNode {
|
class BLTAnimationNodeOutput : public BLTAnimationNode {
|
||||||
GDCLASS(BLTAnimationNodeOutput, BLTAnimationNode);
|
GDCLASS(BLTAnimationNodeOutput, BLTAnimationNode);
|
||||||
|
|
||||||
@ -413,7 +456,8 @@ public:
|
|||||||
|
|
||||||
void calculate_sync_track(const Vector<Ref<BLTAnimationNode>> &input_nodes) override {
|
void calculate_sync_track(const Vector<Ref<BLTAnimationNode>> &input_nodes) override {
|
||||||
if (node_time_info.is_synced || sync) {
|
if (node_time_info.is_synced || sync) {
|
||||||
assert(input_nodes[0]->node_time_info.loop_mode == input_nodes[1]->node_time_info.loop_mode);
|
// TODO: figure out whether we need to enforce looping mode when syncing is enabled.
|
||||||
|
// assert(input_nodes[0]->node_time_info.loop_mode == input_nodes[1]->node_time_info.loop_mode);
|
||||||
node_time_info.sync_track = SyncTrack::blend(blend_weight, input_nodes[0]->node_time_info.sync_track, input_nodes[1]->node_time_info.sync_track);
|
node_time_info.sync_track = SyncTrack::blend(blend_weight, input_nodes[0]->node_time_info.sync_track, input_nodes[1]->node_time_info.sync_track);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ void initialize_blendalot_animgraph_module(ModuleInitializationLevel p_level) {
|
|||||||
ClassDB::register_class<BLTAnimationNodeOutput>();
|
ClassDB::register_class<BLTAnimationNodeOutput>();
|
||||||
ClassDB::register_class<BLTAnimationNodeBlendTree>();
|
ClassDB::register_class<BLTAnimationNodeBlendTree>();
|
||||||
ClassDB::register_class<BLTAnimationNodeSampler>();
|
ClassDB::register_class<BLTAnimationNodeSampler>();
|
||||||
|
ClassDB::register_class<BLTAnimationNodeTimeScale>();
|
||||||
ClassDB::register_class<BLTAnimationNodeBlend2>();
|
ClassDB::register_class<BLTAnimationNodeBlend2>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user