Keyframe map, processor cache

This commit is contained in:
Tanasart 2023-11-29 09:04:28 +07:00
parent c5a6bb3aee
commit 7fb8cacd22
19 changed files with 135 additions and 59 deletions

Binary file not shown.

View file

@ -9,7 +9,11 @@ if(PROJECT.active && !PROJECT.safeMode) { #region
try {
if(PANEL_MAIN != 0) PANEL_MAIN.step();
array_foreach(PROJECT.nodeArray, function(_node) { if(!_node.active) return; _node.triggerCheck(); _node.step(); });
array_foreach(PROJECT.nodeArray, function(_node) {
if(!_node.active) return;
_node.triggerCheck();
_node.step();
});
} catch(e) {
noti_warning("Step error: " + exception_print(e));
}

View file

@ -197,6 +197,8 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) : __Node_Base(_x
passiveDynamic = false;
topoSorted = false;
temp_surface = [];
is_group_io = false;
#endregion
#region ---- timeline ----

View file

@ -1,6 +1,7 @@
function Node_Feedback_Input(_x, _y, _group = noone) : Node_Group_Input(_x, _y, _group) constructor {
name = "Feedback Input";
color = COLORS.node_blend_feedback;
is_group_io = true;
w = 96;
h = 32 + 24 * 2;

View file

@ -1,6 +1,7 @@
function Node_Feedback_Output(_x, _y, _group = noone) : Node_Group_Output(_x, _y, _group) constructor {
name = "Feedback Output";
color = COLORS.node_blend_feedback;
is_group_io = true;
w = 96;
h = 32 + 24 * 2;

View file

@ -1,8 +1,9 @@
function Node_Group_Input(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Group Input";
destroy_when_upgroup = true;
color = COLORS.node_blend_collection;
previewable = false;
is_group_io = true;
destroy_when_upgroup = true;
inParent = undefined;

View file

@ -2,6 +2,7 @@ function Node_Group_Output(_x, _y, _group = noone) : Node(_x, _y, _group) constr
name = "Group Output";
color = COLORS.node_blend_collection;
previewable = false;
is_group_io = true;
destroy_when_upgroup = true;

View file

@ -1,6 +1,7 @@
function Node_Iterator_Each_Input(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Loop Input";
color = COLORS.node_blend_loop;
is_group_io = true;
manual_deletable = false;

View file

@ -1,6 +1,7 @@
function Node_Iterator_Each_Output(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Loop Output";
color = COLORS.node_blend_loop;
is_group_io = true;
manual_deletable = false;

View file

@ -1,6 +1,7 @@
function Node_Iterator_Filter_Input(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Value";
color = COLORS.node_blend_loop;
is_group_io = true;
manual_deletable = false;

View file

@ -1,6 +1,7 @@
function Node_Iterator_Filter_Output(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Filter Output";
color = COLORS.node_blend_loop;
is_group_io = true;
manual_deletable = false;

View file

@ -1,6 +1,7 @@
function Node_Iterator_Input(_x, _y, _group = noone) : Node_Group_Input(_x, _y, _group) constructor {
name = "Loop Input";
color = COLORS.node_blend_loop;
is_group_io = true;
local_output = noone;

View file

@ -1,6 +1,7 @@
function Node_Iterator_Output(_x, _y, _group = noone) : Node_Group_Output(_x, _y, _group) constructor {
name = "Loop Output";
color = COLORS.node_blend_loop;
is_group_io = true;
w = 96;
h = 32 + 24 * 2;

View file

@ -75,11 +75,16 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
index = 0;
prop = _prop;
y = 0;
key_map = array_create(TOTAL_FRAMES);
animate_frames = [];
if(_prop.type != VALUE_TYPE.trigger)
ds_list_add(values, new valueKey(0, _val, self));
process_cache = {};
process_cache_type = -1;
process_cache_disp = -1;
#endregion
static refreshAnimation = function() { #region
@ -106,6 +111,32 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
if(_fr) array_fill(animate_frames, _fr.time, TOTAL_FRAMES, 0);
} #endregion
static updateKeyMap = function() { #region
if(!prop.is_anim && !LOADING && !APPENDING) return;
if(array_length(key_map) != TOTAL_FRAMES)
array_resize(key_map, TOTAL_FRAMES);
if(ds_list_size(values) < 2) {
array_fill(key_map, 0, TOTAL_FRAMES, 0);
return;
}
//print($"Update key map {prop.node.name} - {prop.name}");
var _firstKey = values[| 0].time;
array_fill(key_map, 0, _firstKey, -1);
var _keyIndex = _firstKey;
for( var i = 1, n = ds_list_size(values); i < n; i++ ) {
var _k1 = values[| i].time;
array_fill(key_map, _keyIndex, _k1, i - 1);
_keyIndex = _k1;
}
array_fill(key_map, _keyIndex, TOTAL_FRAMES, 999_999);
} #endregion
static interpolate = function(from, to, rat) { #region
if(prop.type == VALUE_TYPE.boolean)
return 0;
@ -207,12 +238,15 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
if(!prop.is_anim)
return values[| 0].value;
for(var i = 0; i < ds_list_size(values); i++) { //Find trigger
var _key = values[| i];
if(_key.time == _time)
return _key.value;
}
if(array_length(key_map) != TOTAL_FRAMES) updateKeyMap();
var _keyIndex = key_map[_time];
if(_keyIndex == -1 || _keyIndex == 999_999)
return false;
var _key = values[| _keyIndex];
return _key.time == _time? _key.value : false;
}
if(ds_list_size(values) == 0) return processTypeDefault();
@ -220,12 +254,13 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
if(prop.type == VALUE_TYPE.path) return processType(values[| 0].value);
if(!prop.is_anim) return processType(values[| 0].value);
if(array_length(key_map) != TOTAL_FRAMES) updateKeyMap();
var _time_first = prop.loop_range == -1? values[| 0].time : values[| ds_list_size(values) - 1 - prop.loop_range].time;
var _time_last = values[| ds_list_size(values) - 1].time;
var _time_dura = _time_last - _time_first;
if(_time > _time_last) { //loop
if(_time > _time_last) { #region //loop
switch(prop.on_end) {
case KEYFRAME_END.loop :
_time = _time_first + safe_mod(_time - _time_last, _time_dura + 1);
@ -238,9 +273,12 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
_time = _time_first + _time_dura * 2 - time_in_loop;
break;
}
}
} #endregion
if(_time < values[| 0].time) { //Wrap begin
var _keyIndex = key_map[_time];
//print(_keyIndex);
if(_keyIndex == -1) { #region Before first key
if(prop.on_end == KEYFRAME_END.wrap) {
var from = values[| ds_list_size(values) - 1];
var to = values[| 0];
@ -258,21 +296,10 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
}
return processType(values[| 0].value); //First frame
}
} #endregion
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
if(_keyIndex == 999_999) { #region After last key
if(_keyIndex == KEYFRAME_END.wrap) {
var from = values[| ds_list_size(values) - 1];
var to = values[| 0];
var prog = _time - from.time;
@ -284,7 +311,17 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
return lerpValue(from, to, _lrp);
}
return processType(values[| ds_list_size(values) - 1].value); //Last frame
return processType(values[| ds_list_size(values) - 1].value); //First frame
} #endregion
#region In between
var from = values[| _keyIndex];
var to = values[| _keyIndex + 1];
var rat = (_time - from.time) / (to.time - from.time);
var _lrp = interpolate(from, to, rat);
return lerpValue(from, to, _lrp);
#endregion
} #endregion
static processTypeDefault = function() { #region
@ -292,13 +329,27 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
return 0;
} #endregion
static clearProcessCache = function(_val) { process_cache = {}; }
static processType = function(_val) { #region
if(process_cache_type != prop.type || process_cache_disp != prop.display_type) {
clearProcessCache();
process_cache_type = prop.type;
process_cache_disp = prop.display_type;
}
if(struct_has(process_cache, _val))
return process_cache[$ _val];
var _res = _val;
if(!sep_axis && typeArray(prop.display_type) && is_array(_val)) {
for(var i = 0; i < array_length(_val); i++)
_val[i] = processValue(_val[i]);
return _val;
}
return processValue(_val);
_res[i] = processValue(_val[i]);
} else
_res = processValue(_val);
process_cache[$ _val] = _res;
return _res;
} #endregion
static processValue = function(_val) { #region
@ -348,6 +399,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
}
values[| i] = _key;
updateKeyMap();
return 2;
}
@ -361,6 +413,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
}, { key : _key, time : _prevTime });
ds_list_insert(values, i, _key);
if(_replace) updateKeyMap();
return 1;
}
@ -371,6 +424,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
}, { key : _key, time : _prevTime });
ds_list_add(values, _key);
if(_replace) updateKeyMap();
return 1;
} #endregion
@ -378,6 +432,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
if(prop.type == VALUE_TYPE.trigger) {
if(!prop.is_anim) {
values[| 0] = new valueKey(0, _val, self);
updateKeyMap();
return true;
}
@ -390,11 +445,13 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
return false;
} else if(_key.time > _time) {
ds_list_insert(values, i, new valueKey(_time, _val, self));
updateKeyMap();
return true;
}
}
ds_list_add(values, new valueKey(_time, _val, self));
updateKeyMap();
return true;
}
@ -430,6 +487,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
var k = new valueKey(_time, _val, self, ease_in, ease_out);
ds_list_insert(values, i, k);
if(_record) recordAction(ACTION_TYPE.list_insert, values, [k, i, $"add {prop.name} keyframe" ]);
updateKeyMap();
return true;
}
}
@ -437,6 +495,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
var k = new valueKey(_time, _val, self, ease_in, ease_out);
if(_record) recordAction(ACTION_TYPE.list_insert, values, [ k, ds_list_size(values), $"add {prop.name} keyframe" ]);
ds_list_add(values, k);
updateKeyMap();
return true;
} #endregion
@ -445,6 +504,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
ds_list_remove(values, key);
else
prop.is_anim = false;
updateKeyMap();
} #endregion
static serialize = function(scale = false) { #region
@ -506,6 +566,8 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
var grad = new gradientObject();
grad.keys = _val;
ds_list_add(values, new valueKey(0, grad, self));
updateKeyMap();
return;
}
@ -554,6 +616,8 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
vk.ease_y_lock = ease_y_lock;
ds_list_add(values, vk);
}
updateKeyMap();
} #endregion
static cleanUp = function() { #region

View file

@ -2,6 +2,7 @@ function Node_Tunnel_In(_x, _y, _group = noone) : Node(_x, _y, _group) construct
name = "Tunnel In";
previewable = false;
color = COLORS.node_blend_tunnel;
is_group_io = true;
w = 96;

View file

@ -1,7 +1,8 @@
function Node_Tunnel_Out(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Tunnel Out";
previewable = false;
color = COLORS.node_blend_tunnel;
previewable = false;
is_group_io = true;
w = 96;

View file

@ -1638,21 +1638,25 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru
if(ds_list_empty(animator.values))
ds_list_add(animator.values, new valueKey(CURRENT_FRAME, animator.getValue(), animator));
animator.values[| 0].time = CURRENT_FRAME;
animator.updateKeyMap();
for( var i = 0, n = array_length(animators); i < n; i++ ) {
if(ds_list_empty(animators[i].values))
ds_list_add(animators[i].values, new valueKey(CURRENT_FRAME, animators[i].getValue(), animators[i]));
animators[i].values[| 0].time = CURRENT_FRAME;
animators[i].updateKeyMap();
}
} else {
var _val = animator.getValue();
ds_list_clear(animator.values);
animator.values[| 0] = new valueKey(0, _val, animator);
animator.updateKeyMap();
for( var i = 0, n = array_length(animators); i < n; i++ ) {
var _val = animators[i].getValue();
ds_list_clear(animators[i].values);
animators[i].values[| 0] = new valueKey(0, _val, animators[i]);
animators[i].updateKeyMap();
}
}

View file

@ -32,7 +32,7 @@ function Node_Wiggler(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c
var step = TOTAL_FRAMES / 64;
for( var i = 0; i < 64; i++ )
random_value[i] = getWiggle(ran[0], ran[1], TOTAL_FRAMES / fre, step * i, sed, 0, TOTAL_FRAMES);
random_value[i] = getWiggle(array_safe_get(ran, 0), array_safe_get(ran, 1), TOTAL_FRAMES / fre, step * i, sed, 0, TOTAL_FRAMES);
}
static processData = function(_output, _data, _output_index, _array_index = 0) {
@ -41,7 +41,7 @@ function Node_Wiggler(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c
var sed = _data[2];
var time = CURRENT_FRAME;
return getWiggle(ran[0], ran[1], TOTAL_FRAMES / fre, time, sed, 0, TOTAL_FRAMES);
return getWiggle(array_safe_get(ran, 0), array_safe_get(ran, 1), TOTAL_FRAMES / fre, time, sed, 0, TOTAL_FRAMES);
}
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {
@ -52,6 +52,8 @@ function Node_Wiggler(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c
var time = CURRENT_FRAME;
var total_time = TOTAL_FRAMES;
if(!is_array(ran)) return;
switch(disp) {
case 0 :
w = 96;

View file

@ -10,15 +10,6 @@ enum RENDER_TYPE {
global.FLAG.render = 0;
global.FLAG.renderTime = false;
global.group_io = [
"Node_Group_Input", "Node_Group_Output",
"Node_Feedback_Input", "Node_Feedback_Output",
"Node_Iterator_Input", "Node_Iterator_Output",
"Node_Iterator_Each_Input", "Node_Iterator_Each_Output",
"Node_Iterator_Filter_Input", "Node_Iterator_Filter_Output",
"Node_Tunnel_In", "Node_Tunnel_Out"
];
#macro RENDER_ALL_REORDER UPDATE_RENDER_ORDER = true; UPDATE |= RENDER_TYPE.full;
#macro RENDER_ALL UPDATE |= RENDER_TYPE.full;
#macro RENDER_PARTIAL UPDATE |= RENDER_TYPE.partial;
@ -133,7 +124,7 @@ function __nodeIsRenderLeaf(_node) { #region
if(is_undefined(_node)) { LOG_IF(global.FLAG.render == 1, $"Skip undefiend [{_node}]"); return false; }
if(!is_instanceof(_node, Node)) { LOG_IF(global.FLAG.render == 1, $"Skip non-node [{_node}]"); return false; }
if(array_exists(global.group_io, instanceof(_node))) { LOG_IF(global.FLAG.render == 1, $"Skip group IO [{_node.internalName}]"); return false; }
if(_node.is_group_io) { LOG_IF(global.FLAG.render == 1, $"Skip group IO [{_node.internalName}]"); return false; }
if(!_node.active) { LOG_IF(global.FLAG.render == 1, $"Skip inactive [{_node.internalName}]"); return false; }
if(!_node.isRenderActive()) { LOG_IF(global.FLAG.render == 1, $"Skip render inactive [{_node.internalName}]"); return false; }
@ -282,10 +273,7 @@ function RenderList(list, skipInLoop = true) { #region
if(!is_instanceof(_node, Node)) { LOG_IF(global.FLAG.render == 1, $"Skip non-node {_node}"); continue; }
_node.render_time = 0;
if(array_exists(global.group_io, instanceof(_node))) {
LOG_IF(global.FLAG.render == 1, $"Skip group IO {_node.internalName}");
continue;
}
if(_node.is_group_io) { LOG_IF(global.FLAG.render == 1, $"Skip group IO {_node.internalName}"); continue; }
if(!_node.active) { LOG_IF(global.FLAG.render == 1, $"Skip inactive {_node.internalName}"); continue; }
if(!_node.isRenderActive()) { LOG_IF(global.FLAG.render == 1, $"Skip non-renderActive {_node.internalName}"); continue; }