Pixel-Composer/scripts/node_keyframe/node_keyframe.gml

479 lines
13 KiB
Plaintext
Raw Normal View History

2022-01-13 05:24:03 +01:00
enum CURVE_TYPE {
2023-01-09 03:14:20 +01:00
none,
2022-01-13 05:24:03 +01:00
bezier,
2023-01-25 06:49:00 +01:00
cut,
2022-01-13 05:24:03 +01:00
}
2023-01-09 03:14:20 +01:00
function valueKey(_time, _value, _anim = noone, _in = 0, _ot = 0) constructor {
2022-09-23 13:28:42 +02:00
time = _time;
2023-07-06 19:49:16 +02:00
ratio = time / (PROJECT.animator.frames_total - 1);
2022-09-23 13:28:42 +02:00
value = _value;
anim = _anim;
2022-01-13 05:24:03 +01:00
2023-07-14 20:34:35 +02:00
ease_y_lock = true;
2023-01-09 03:14:20 +01:00
ease_in = is_array(_in)? _in : [_in, 1];
ease_out = is_array(_ot)? _ot : [_ot, 0];
2022-09-23 13:28:42 +02:00
2023-01-09 03:14:20 +01:00
ease_in_type = CURVE_TYPE.none;
ease_out_type = CURVE_TYPE.none;
2022-12-10 05:06:01 +01:00
2023-03-05 07:16:44 +01:00
dopesheet_x = 0;
2022-12-10 05:06:01 +01:00
static setTime = function(time) {
self.time = time;
2023-07-06 19:49:16 +02:00
ratio = time / (PROJECT.animator.frames_total - 1);
2022-12-10 05:06:01 +01:00
}
2023-01-25 06:49:00 +01:00
2023-03-02 07:59:14 +01:00
static clone = function(target = noone) {
2023-01-25 06:49:00 +01:00
var key = new valueKey(time, value, target);
key.ease_in = ease_in;
key.ease_out = ease_out;
key.ease_in_type = ease_in_type;
key.ease_out_type = ease_out_type;
return key;
}
2023-03-02 07:59:14 +01:00
2023-03-05 07:16:44 +01:00
static cloneAnimator = function(shift = 0, anim = noone, removeDup = true) {
if(anim != noone) { //check value compat between animator
if(value_bit(self.anim.prop.type) & value_bit(anim.prop.type) == 0) {
noti_warning("Type incompatible");
return noone;
}
if(typeArray(self.anim.prop.display_type) != typeArray(anim.prop.display_type)) {
noti_warning("Type incompatible");
return noone;
}
}
if(anim == noone) anim = self.anim;
2023-03-02 07:59:14 +01:00
var key = new valueKey(time + shift, value, anim);
key.ease_in = ease_in;
key.ease_out = ease_out;
key.ease_in_type = ease_in_type;
key.ease_out_type = ease_out_type;
ds_list_add(anim.values, key);
2023-03-05 07:16:44 +01:00
anim.setKeyTime(key, time + shift, removeDup);
2023-03-02 07:59:14 +01:00
return key;
}
2022-01-13 05:24:03 +01:00
}
2023-03-21 03:01:53 +01:00
function valueAnimator(_val, _prop, _sep_axis = false) constructor {
suffix = "";
values = ds_list_create();
sep_axis = _sep_axis;
2023-03-28 06:58:28 +02:00
if(_prop.type != VALUE_TYPE.trigger)
ds_list_add(values, new valueKey(0, _val, self));
2023-03-21 03:01:53 +01:00
//print(_prop.name + ": " + string(_val));
2022-01-13 05:24:03 +01:00
2023-03-21 03:01:53 +01:00
index = 0;
2023-01-09 03:14:20 +01:00
prop = _prop;
2023-03-05 07:16:44 +01:00
dopesheet_y = 0;
2022-01-13 05:24:03 +01:00
static interpolate = function(from, to, rat) {
2023-01-25 06:49:00 +01:00
if(prop.type == VALUE_TYPE.boolean)
return 0;
2023-01-09 03:14:20 +01:00
if(to.ease_in_type == CURVE_TYPE.none && from.ease_out_type == CURVE_TYPE.none)
return rat;
2023-01-25 06:49:00 +01:00
if(to.ease_in_type == CURVE_TYPE.cut)
return 0;
if(from.ease_out_type == CURVE_TYPE.cut)
return 1;
2023-01-09 03:14:20 +01:00
if(rat == 0 || rat == 1)
2022-09-23 13:28:42 +02:00
return rat;
2023-01-09 03:14:20 +01:00
var eox = clamp(from.ease_out[0], 0, 0.9);
var eix = clamp(to.ease_in[0], 0, 0.9);
var eoy = from.ease_out[1];
var eiy = to.ease_in[1];
2022-09-23 13:28:42 +02:00
2023-01-09 03:14:20 +01:00
var bz = [0, eox, eoy, 1. - eix, eiy, 1];
2023-02-14 02:51:14 +01:00
return eval_curve_segment_x(bz, rat);
2023-01-09 03:14:20 +01:00
}
static lerpValue = function(from, to, _lrp) {
2023-06-17 14:30:49 +02:00
var _f = from.value;
var _t = to.value;
2023-07-11 14:18:23 +02:00
if(is_struct(_f)) {
if(!struct_has(_f, "lerpTo")) return _f;
return _f.lerpTo(_t, _lrp);
}
2023-01-09 03:14:20 +01:00
2023-06-17 14:30:49 +02:00
if(prop.type == VALUE_TYPE.color) {
2023-07-11 14:18:23 +02:00
if(is_array(_f) && is_array(_t)) {
var _len = ceil(lerp(array_length(_f), array_length(_t), _lrp));
var res = array_create(_len);
for( var i = 0; i < _len; i++ ) {
var rat = i / (_len - 1);
var rf = rat * (array_length(_f) - 1);
var rt = rat * (array_length(_t) - 1);
var cf = array_get_decimal(_f, rf, true);
var ct = array_get_decimal(_t, rt, true);
res[i] = merge_color(cf, ct, _lrp);
}
2023-01-09 03:14:20 +01:00
return res;
}
return processType(merge_color(_f, _t, _lrp));
}
2023-06-17 14:30:49 +02:00
if(is_array(_f)) {
var _vec = array_create(array_length(_f));
2023-01-09 03:14:20 +01:00
for(var i = 0; i < array_length(_vec); i++)
2023-06-17 14:30:49 +02:00
_vec[i] = processType(lerp(_f[i], _t[i], _lrp));
2023-01-09 03:14:20 +01:00
return _vec;
}
if(prop.type == VALUE_TYPE.text)
2023-06-17 14:30:49 +02:00
return processType(_f);
return processType(lerp(_f, _t, _lrp));
2022-01-13 05:24:03 +01:00
}
2023-03-21 03:01:53 +01:00
static getName = function() { return prop.name + suffix; }
2023-07-06 19:49:16 +02:00
static getValue = function(_time = PROJECT.animator.current_frame) {
2023-03-28 06:58:28 +02:00
if(prop.type == VALUE_TYPE.trigger) {
2023-06-13 14:42:06 +02:00
if(ds_list_size(values) == 0)
return false;
if(!prop.is_anim)
return values[| 0].value;
2023-03-28 06:58:28 +02:00
for(var i = 0; i < ds_list_size(values); i++) { //Find trigger
var _key = values[| i];
if(_key.time == _time)
return _key.value;
}
return false;
2023-03-21 03:01:53 +01:00
}
2023-02-14 02:51:14 +01:00
2023-03-28 06:58:28 +02:00
if(ds_list_size(values) == 0)
return processTypeDefault();
if(ds_list_size(values) == 1)
return processType(values[| 0].value);
if(prop.type == VALUE_TYPE.path)
return processType(values[| 0].value);
if(!prop.is_anim)
return processType(values[| 0].value);
2022-01-13 05:24:03 +01:00
2023-07-12 21:00:05 +02:00
var _time_first = prop.loop_range == -1? values[| 0].time : values[| ds_list_size(values) - 1 - prop.loop_range].time;
2023-01-09 03:14:20 +01:00
var _time_last = values[| ds_list_size(values) - 1].time;
var _time_dura = _time_last - _time_first;
2022-01-13 05:24:03 +01:00
2023-03-21 03:01:53 +01:00
if(_time > _time_last) { //loop
2023-01-09 03:14:20 +01:00
switch(prop.on_end) {
case KEYFRAME_END.loop :
_time = _time_first + safe_mod(_time - _time_last, _time_dura + 1);
break;
case KEYFRAME_END.ping :
var time_in_loop = safe_mod(_time - _time_first, _time_dura * 2);
if(time_in_loop < _time_dura)
_time = _time_first + time_in_loop;
else
_time = _time_first + _time_dura * 2 - time_in_loop;
break;
2022-01-13 05:24:03 +01:00
}
}
2023-01-09 03:14:20 +01:00
if(_time < values[| 0].time) { //Wrap begin
if(prop.on_end == KEYFRAME_END.wrap) {
var from = values[| ds_list_size(values) - 1];
var to = values[| 0];
2023-07-06 19:49:16 +02:00
var prog = PROJECT.animator.frames_total - from.time + _time;
var totl = PROJECT.animator.frames_total - from.time + to.time;
2023-01-09 03:14:20 +01:00
var rat = prog / totl;
var _lrp = interpolate(from, to, rat);
return lerpValue(from, to, _lrp);
2022-01-13 05:24:03 +01:00
}
2023-01-09 03:14:20 +01:00
return processType(values[| 0].value); //First frame
2022-01-13 05:24:03 +01:00
}
2023-01-09 03:14:20 +01:00
for(var i = 0; i < ds_list_size(values); i++) { //In between
var _key = values[| i];
if(_key.time <= _time) continue;
var rat = (_time - values[| i - 1].time) / (values[| i].time - values[| i - 1].time);
var from = values[| i - 1];
var to = values[| i];
var _lrp = interpolate(from, to, rat);
return lerpValue(from, to, _lrp);
}
if(prop.on_end == KEYFRAME_END.wrap) { //Wrap end
var from = values[| ds_list_size(values) - 1];
var to = values[| 0];
var prog = _time - from.time;
2023-07-06 19:49:16 +02:00
var totl = PROJECT.animator.frames_total - from.time + to.time;
2023-01-09 03:14:20 +01:00
var rat = prog / totl;
var _lrp = interpolate(from, to, rat);
return lerpValue(from, to, _lrp);
}
return processType(values[| ds_list_size(values) - 1].value); //Last frame
2022-01-13 05:24:03 +01:00
}
2023-02-14 02:51:14 +01:00
static processTypeDefault = function() {
2023-03-21 03:01:53 +01:00
if(!sep_axis && typeArray(prop.display_type)) return [];
2023-02-14 02:51:14 +01:00
return 0;
}
2022-01-13 05:24:03 +01:00
static processType = function(_val) {
2023-03-21 03:01:53 +01:00
if(!sep_axis && typeArray(prop.display_type) && is_array(_val)) {
2022-01-13 05:24:03 +01:00
for(var i = 0; i < array_length(_val); i++)
_val[i] = processValue(_val[i]);
2023-08-01 11:16:23 +02:00
2022-01-13 05:24:03 +01:00
return _val;
}
return processValue(_val);
}
2023-01-17 08:11:55 +01:00
2023-05-16 21:28:16 +02:00
static processValue = function(_val) {
if(is_array(_val)) return _val;
if(is_struct(_val)) return _val;
if(is_undefined(_val)) return 0;
2022-01-13 05:24:03 +01:00
2022-12-27 04:00:50 +01:00
if(prop.type == VALUE_TYPE.integer && prop.unit.mode == VALUE_UNIT.constant)
return round(toNumber(_val));
2023-02-14 02:51:14 +01:00
2022-09-23 13:28:42 +02:00
switch(prop.type) {
2022-12-27 04:00:50 +01:00
case VALUE_TYPE.integer :
2022-09-21 06:09:40 +02:00
case VALUE_TYPE.float : return toNumber(_val);
2023-02-17 04:48:54 +01:00
case VALUE_TYPE.text : return string_real(_val);
2022-09-27 06:37:28 +02:00
case VALUE_TYPE.surface :
if(is_string(_val))
return get_asset(_val);
2023-03-28 06:58:28 +02:00
return _val;
2022-01-13 05:24:03 +01:00
}
return _val;
}
2022-09-23 13:28:42 +02:00
static setKeyTime = function(_key, _time, _replace = true) {
if(!ds_list_exist(values, _key)) return 0;
2023-07-06 19:49:16 +02:00
if(!LOADING) PROJECT.modified = true;
2022-09-23 13:28:42 +02:00
2023-01-25 06:49:00 +01:00
_time = max(_time, 0);
2022-12-10 05:06:01 +01:00
_key.setTime(_time);
2022-09-23 13:28:42 +02:00
ds_list_remove(values, _key);
if(_replace) {
for( var i = 0; i < ds_list_size(values); i++ ) {
if(values[| i].time == _time) {
values[| i] = _key;
return 2;
}
}
}
for( var i = 0; i < ds_list_size(values); i++ ) {
if(values[| i].time > _time) {
ds_list_insert(values, i, _key);
return 1;
}
}
ds_list_add(values, _key);
return 1;
}
2023-07-06 19:49:16 +02:00
static setValue = function(_val = 0, _record = true, _time = PROJECT.animator.current_frame, ease_in = 0, ease_out = 0) {
2023-03-28 06:58:28 +02:00
if(prop.type == VALUE_TYPE.trigger) {
2023-06-13 14:42:06 +02:00
if(!prop.is_anim) {
values[| 0] = new valueKey(0, _val, self);
return true;
}
2023-03-28 06:58:28 +02:00
for(var i = 0; i < ds_list_size(values); i++) { //Find trigger
var _key = values[| i];
if(_key.time == _time) {
2023-05-22 20:31:55 +02:00
if(!global.FLAG.keyframe_override) return false;
2023-03-28 06:58:28 +02:00
_key.value = _val;
return false;
} else if(_key.time > _time) {
ds_list_insert(values, i, new valueKey(_time, _val, self));
return true;
}
}
ds_list_add(values, new valueKey(_time, _val, self));
return true;
}
2023-03-21 03:01:53 +01:00
if(!prop.is_anim) {
2022-11-22 14:25:39 +01:00
if(isEqual(values[| 0].value, _val))
return false;
2023-02-14 02:51:14 +01:00
if(_record) recordAction(ACTION_TYPE.var_modify, values[| 0], [ values[| 0].value, "value", prop.name ]);
2022-11-22 14:25:39 +01:00
values[| 0].value = _val;
return true;
2022-01-13 05:24:03 +01:00
}
if(ds_list_size(values) == 0) {
2022-09-23 13:28:42 +02:00
var k = new valueKey(_time, _val, self, ease_in, ease_out);
2022-01-13 05:24:03 +01:00
ds_list_add(values, k);
2023-02-14 02:51:14 +01:00
if(_record) recordAction(ACTION_TYPE.list_insert, values, [ k, ds_list_size(values) - 1, "add " + string(prop.name) + " keyframe" ]);
2022-01-13 05:24:03 +01:00
return true;
}
for(var i = 0; i < ds_list_size(values); i++) {
var _key = values[| i];
if(_key.time == _time) {
2023-05-22 20:31:55 +02:00
if(!global.FLAG.keyframe_override) return false;
2022-01-13 05:24:03 +01:00
if(_key.value != _val) {
2023-02-14 02:51:14 +01:00
if(_record) recordAction(ACTION_TYPE.var_modify, _key, [ _key.value, "value", prop.name ]);
2022-01-13 05:24:03 +01:00
_key.value = _val;
return true;
}
return false;
} else if(_key.time > _time) {
2022-09-23 13:28:42 +02:00
var k = new valueKey(_time, _val, self, ease_in, ease_out);
2022-01-13 05:24:03 +01:00
ds_list_insert(values, i, k);
2023-02-14 02:51:14 +01:00
if(_record) recordAction(ACTION_TYPE.list_insert, values, [k, i, "add " + string(prop.name) + " keyframe" ]);
2022-01-13 05:24:03 +01:00
return true;
}
}
2022-09-23 13:28:42 +02:00
var k = new valueKey(_time, _val, self, ease_in, ease_out);
2023-02-14 02:51:14 +01:00
if(_record) recordAction(ACTION_TYPE.list_insert, values, [ k, ds_list_size(values), "add " + string(prop.name) + " keyframe" ]);
2022-01-13 05:24:03 +01:00
ds_list_add(values, k);
return true;
}
2022-09-23 13:28:42 +02:00
static removeKey = function(key) {
if(ds_list_size(values) > 1)
ds_list_remove(values, key);
else
2023-03-21 03:01:53 +01:00
prop.is_anim = false;
2022-09-23 13:28:42 +02:00
}
2022-01-13 05:24:03 +01:00
static serialize = function(scale = false) {
2023-06-13 14:42:06 +02:00
var _data = [];
2022-01-13 05:24:03 +01:00
for(var i = 0; i < ds_list_size(values); i++) {
2023-06-13 14:42:06 +02:00
var _value_list = [];
2023-02-14 02:51:14 +01:00
if(scale)
2023-07-06 19:49:16 +02:00
_value_list[0] = values[| i].time / (PROJECT.animator.frames_total - 1);
2022-01-13 05:24:03 +01:00
else
2023-06-13 14:42:06 +02:00
_value_list[0] = values[| i].time;
2022-01-13 05:24:03 +01:00
2023-02-14 02:51:14 +01:00
var val = values[| i].value;
2023-03-11 01:40:17 +01:00
if(prop.type == VALUE_TYPE.struct)
2023-06-13 14:42:06 +02:00
_value_list[1] = json_stringify(val);
2023-03-11 01:40:17 +01:00
else if(is_struct(val))
2023-06-13 14:42:06 +02:00
_value_list[1] = val.serialize();
2023-03-21 03:01:53 +01:00
else if(!sep_axis && typeArray(prop.display_type) && is_array(val)) {
2023-06-13 14:42:06 +02:00
var __v = [];
2023-02-14 02:51:14 +01:00
for(var j = 0; j < array_length(val); j++) {
2023-02-19 13:49:20 +01:00
if(is_struct(val[j]) && struct_has(val[j], "serialize"))
2023-06-13 14:42:06 +02:00
array_push(__v, val[j].serialize());
2023-02-14 02:51:14 +01:00
else
2023-06-13 14:42:06 +02:00
array_push(__v, val[j]);
2023-02-14 02:51:14 +01:00
}
2023-06-13 14:42:06 +02:00
_value_list[1] = __v;
2023-03-11 01:40:17 +01:00
} else
2023-06-13 14:42:06 +02:00
_value_list[1] = values[| i].value;
2022-01-13 05:24:03 +01:00
2023-06-13 14:42:06 +02:00
_value_list[2] = values[| i].ease_in;
_value_list[3] = values[| i].ease_out;
_value_list[4] = values[| i].ease_in_type;
_value_list[5] = values[| i].ease_out_type;
2023-07-14 20:34:35 +02:00
_value_list[6] = values[| i].ease_y_lock;
2022-01-13 05:24:03 +01:00
2023-06-13 14:42:06 +02:00
array_push(_data, _value_list);
2022-01-13 05:24:03 +01:00
}
2023-06-13 14:42:06 +02:00
return _data;
2022-01-13 05:24:03 +01:00
}
2023-06-13 14:42:06 +02:00
static deserialize = function(_data, scale = false) {
2022-01-13 05:24:03 +01:00
ds_list_clear(values);
2022-12-12 09:08:03 +01:00
2023-07-06 19:49:16 +02:00
if(prop.type == VALUE_TYPE.gradient && PROJECT.version < 1340 && !CLONING) { //backward compat: Gradient
2023-02-14 02:51:14 +01:00
var _val = [];
2023-06-13 14:42:06 +02:00
var value = _data[0][1];
2023-02-14 02:51:14 +01:00
2023-06-13 14:42:06 +02:00
if(is_array(value))
for(var i = 0; i < array_length(value); i++) {
var _keyframe = value[i];
var _t = struct_try_get(_keyframe, "time");
var _v = struct_try_get(_keyframe, "value");
2023-02-14 02:51:14 +01:00
2023-03-02 07:59:14 +01:00
array_push(_val, new gradientKey(_t, _v));
2023-02-14 02:51:14 +01:00
}
2023-03-02 07:59:14 +01:00
var grad = new gradientObject();
grad.keys = _val;
ds_list_add(values, new valueKey(0, grad, self));
2023-02-14 02:51:14 +01:00
return;
}
var base = getValue();
2023-06-13 14:42:06 +02:00
for(var i = 0; i < array_length(_data); i++) {
var _keyframe = _data[i];
2023-06-17 18:59:20 +02:00
var _time = array_safe_get(_keyframe, 0);
2023-02-14 02:51:14 +01:00
if(scale && _time <= 1)
2023-07-06 19:49:16 +02:00
_time = round(_time * (PROJECT.animator.frames_total - 1));
2022-01-13 05:24:03 +01:00
2023-06-17 18:59:20 +02:00
var value = array_safe_get(_keyframe, 1);
var ease_in = array_safe_get(_keyframe, 2);
var ease_out = array_safe_get(_keyframe, 3);
var ease_in_type = array_safe_get(_keyframe, 4);
var ease_out_type = array_safe_get(_keyframe, 5);
2023-07-14 20:34:35 +02:00
var ease_y_lock = array_safe_get(_keyframe, 6, true);
2023-01-09 03:14:20 +01:00
2023-02-14 02:51:14 +01:00
var _val = value;
2022-01-13 05:24:03 +01:00
2023-03-11 01:40:17 +01:00
if(prop.type == VALUE_TYPE.struct)
2023-06-17 18:59:20 +02:00
_val = json_try_parse(value);
2023-03-11 01:40:17 +01:00
else if(prop.type == VALUE_TYPE.path && prop.display_type == VALUE_DISPLAY.path_array) {
2023-06-13 14:42:06 +02:00
for(var j = 0; j < array_length(value); j++)
_val[j] = value[j];
2023-05-28 20:00:51 +02:00
} else if(prop.type == VALUE_TYPE.gradient) {
2023-03-02 07:59:14 +01:00
var grad = new gradientObject();
_val = grad.deserialize(value);
2023-03-21 03:01:53 +01:00
} else if(!sep_axis && typeArray(prop.display_type)) {
2023-02-14 02:51:14 +01:00
_val = [];
2023-06-13 14:42:06 +02:00
if(is_array(value))
for(var j = 0; j < array_length(value); j++)
_val[j] = processValue(value[j]);
2022-12-27 13:30:02 +01:00
}
2022-01-13 05:24:03 +01:00
2023-06-10 13:59:45 +02:00
//print($"Deserialize {prop.node.name}:{prop.name} = {_val} ");
2022-09-23 13:28:42 +02:00
var vk = new valueKey(_time, _val, self, ease_in, ease_out);
vk.ease_in_type = ease_in_type;
vk.ease_out_type = ease_out_type;
2023-07-14 20:34:35 +02:00
vk.ease_y_lock = ease_y_lock;
2022-09-23 13:28:42 +02:00
ds_list_add(values, vk);
2022-01-13 05:24:03 +01:00
}
}
2022-01-19 06:11:17 +01:00
static cleanUp = function() {
ds_list_destroy(values);
}
2022-01-13 05:24:03 +01:00
}