- [Feedback] Fix inline feedback not working.

This commit is contained in:
Tanasart 2024-04-26 18:21:25 +07:00
parent 796573b3c6
commit 3cfbd33d62
23 changed files with 1729 additions and 65 deletions

View file

@ -1,4 +1,4 @@
// 2024-04-26 09:58:54
// 2024-04-26 16:29:55
function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Spawner";
update_on_frame = true;
@ -356,8 +356,18 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
if(array_empty(surfs)) return;
for( var i = 0, n = array_length(surfs); i < n; i++ ) {
if(is_surface(surface_cache[$ surfs[i]])) continue;
surface_cache[$ surfs[i]] = surface_clone(surfs[i]);
var _s = surfs[i];
if(is_surface(surface_cache[$ _s]))
continue;
if(is_instanceof(_s, SurfaceAtlas))
_s = _s.surface.get();
if(!surface_exists(_s))
continue;
surface_cache[$ surfs[i]] = surface_clone(_s);
}
} #endregion

View file

@ -1,4 +1,4 @@
// 2024-04-26 09:57:25
// 2024-04-26 16:29:54
function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Spawner";
update_on_frame = true;
@ -100,9 +100,7 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
inputs[| 30] = nodeValue("Distribution map", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone)
.rejectArray()
inputs[| 31] = nodeValue("Atlas", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, [] )
.setArrayDepth(1)
.rejectArray();
inputs[| 31] = nodeValue("Atlas", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, [] );
inputs[| 32] = nodeValue("Seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, irandom_range(100000, 999999))
.rejectArray();
@ -358,8 +356,18 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
if(array_empty(surfs)) return;
for( var i = 0, n = array_length(surfs); i < n; i++ ) {
if(is_surface(surface_cache[$ surfs[i]])) continue;
surface_cache[$ surfs[i]] = surface_clone(surfs[i]);
var _s = surfs[i];
if(is_surface(surface_cache[$ _s]))
continue;
if(is_instanceof(_s, SurfaceAtlas))
_s = _s.surface.get();
if(!surface_exists(_s))
continue;
surface_cache[$ surfs[i]] = surface_clone(_s);
}
} #endregion

View file

@ -0,0 +1,301 @@
// 2024-04-26 15:43:17
#region create
global.node_blend_keys = [
"normal", "add", "subtract", "multiply", "screen",
"overlay", "hue", "saturation", "luminosity", "maximum",
"minimum", "replace", "difference"
];
function Node_create_Blend(_x, _y, _group = noone, _param = {}) {
var node = new Node_Blend(_x, _y, _group);
var query = struct_try_get(_param, "query", "");
var ind = array_find(global.node_blend_keys, query);
if(ind >= 0) node.inputs[| 2].setValue(ind);
return node;
}
enum NODE_BLEND_OUTPUT {
background,
foreground,
mask,
maximum,
constant
}
enum NODE_BLEND_FILL {
none,
stretch,
tile
}
#endregion
function Node_Blend(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor {
name = "Blend";
manage_atlas = false;
inputs[| 0] = nodeValue("Background", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 1] = nodeValue("Foreground", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 2] = nodeValue("Blend mode", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, BLEND_TYPES );
inputs[| 3] = nodeValue("Opacity", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
.setDisplay(VALUE_DISPLAY.slider);
inputs[| 4] = nodeValue("Mask", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 5] = nodeValue("Fill mode", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "None", "Stretch", "Tile" ]);
inputs[| 6] = nodeValue("Output dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Background", "Forground", "Mask", "Maximum", "Constant" ])
.rejectArray();
inputs[| 7] = nodeValue("Constant dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF)
.setDisplay(VALUE_DISPLAY.vector);
inputs[| 8] = nodeValue("Active", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
active_index = 8;
inputs[| 9] = nodeValue("Preserve alpha", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
inputs[| 10] = nodeValue("Horizontal Align", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_button, [ THEME.inspector_surface_halign, THEME.inspector_surface_halign, THEME.inspector_surface_halign]);
inputs[| 11] = nodeValue("Vertical Align", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_button, [ THEME.inspector_surface_valign, THEME.inspector_surface_valign, THEME.inspector_surface_valign]);
inputs[| 12] = nodeValue("Invert mask", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
inputs[| 13] = nodeValue("Mask feather", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
.setDisplay(VALUE_DISPLAY.slider, { range: [1, 16, 0.1] });
inputs[| 14] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0.5, 0.5 ])
.setDisplay(VALUE_DISPLAY.vector);
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
input_display_list = [ 8,
["Surfaces", true], 0, 1, 4, 12, 13, 6, 7,
["Blend", false], 2, 3, 9,
["Transform", false], 5, 14,
]
attribute_surface_depth();
temp_surface = [ surface_create(1, 1), surface_create(1, 1) ];
blend_temp_surface = temp_surface[1];
dragging = false;
drag_sx = 0;
drag_sy = 0;
drag_mx = 0;
drag_my = 0;
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
var _surf = outputs[| 0].getValue();
if(is_array(_surf)) _surf = array_safe_get_fast(_surf, preview_index);
if(is_struct(_surf)) return;
if(!surface_exists(_surf)) return;
var _fore = getSingleValue( 1);
var _fill = getSingleValue( 5);
var _posi = getSingleValue(14);
if(_fill) return;
var sw = surface_get_width_safe( _surf);
var sh = surface_get_height_safe(_surf);
var fw = surface_get_width_safe( _fore);
var fh = surface_get_height_safe(_fore);
var _rx = _posi[0] * sw - fw / 2;
var _ry = _posi[1] * sh - fh / 2;
_rx = _x + _rx * _s;
_ry = _y + _ry * _s;
var _rw = fw * _s;
var _rh = fh * _s;
if(dragging) {
var px = drag_sx + (_mx - drag_mx) / _s;
var py = drag_sy + (_my - drag_my) / _s;
px /= sw;
py /= sh;
if(inputs[| 14].setValue([ px, py ]))
UNDO_HOLDING = true;
if(mouse_release(mb_left)) {
UNDO_HOLDING = false;
dragging = false;
}
}
draw_set_color(COLORS._main_accent);
if(dragging || (active && point_in_rectangle(_mx, _my, _rx, _ry, _rx + _rw, _ry + _rh))) {
draw_rectangle_width(_rx, _ry, _rx + _rw, _ry + _rh, 2);
if(mouse_press(mb_left)) {
dragging = true;
drag_sx = _posi[0] * sw;
drag_sy = _posi[1] * sh;
drag_mx = _mx;
drag_my = _my;
}
} else
draw_rectangle(_rx, _ry, _rx + _rw, _ry + _rh, true);
} #endregion
static step = function() { #region
var _back = getSingleValue(0);
var _fore = getSingleValue(1);
var _fill = getSingleValue(5);
var _outp = getSingleValue(6);
var _atlas = is_instanceof(_fore, SurfaceAtlas);
inputs[| 5].setVisible(!_atlas);
inputs[| 6].editWidget.data_list = _atlas? [ "Background", "Forground" ] : [ "Background", "Forground", "Mask", "Maximum", "Constant" ];
inputs[| 7].setVisible(_outp == 4);
inputs[| 14].setVisible(_fill == 0 && !_atlas);
} #endregion
static processData = function(_outSurf, _data, _output_index, _array_index) { #region
var _back = _data[0];
var _fore = _data[1];
var _type = _data[2];
var _opacity = _data[3];
var _mask = _data[4];
var _fill = _data[5];
var _outp = _data[6];
var _out_dim = _data[7];
var _pre_alp = _data[9];
var _halign = _data[10];
var _valign = _data[11];
var _posit = _data[14];
var _mskInv = _data[12];
var _mskFea = _data[13];
var cDep = attrDepth();
#region dimension
var ww = 1;
var hh = 1;
var _atlas = is_instanceof(_fore, SurfaceAtlas);
switch(_outp) {
case NODE_BLEND_OUTPUT.background :
ww = surface_get_width_safe(_back);
hh = surface_get_height_safe(_back);
break;
case NODE_BLEND_OUTPUT.foreground :
ww = surface_get_width_safe(_fore);
hh = surface_get_height_safe(_fore);
break;
case NODE_BLEND_OUTPUT.mask :
ww = surface_get_width_safe(_mask);
hh = surface_get_height_safe(_mask);
break;
case NODE_BLEND_OUTPUT.maximum :
ww = max(surface_get_width_safe(_back), surface_get_width_safe(_fore), surface_get_width_safe(_mask));
hh = max(surface_get_height_safe(_back), surface_get_height_safe(_fore), surface_get_height_safe(_mask));
break;
case NODE_BLEND_OUTPUT.constant :
ww = _out_dim[0];
hh = _out_dim[1];
break;
}
#endregion
for( var i = 0; i < 2; i++ ) temp_surface[i] = surface_verify(temp_surface[i], ww, hh, cDep);
var _backDraw = temp_surface[0];
var _foreDraw = temp_surface[1];
surface_set_shader(_backDraw, noone,, BLEND.over);
draw_surface_safe(_back);
surface_reset_shader();
if(_fill == NODE_BLEND_FILL.none || _atlas) {
if(_atlas) {
if(_outp == NODE_BLEND_OUTPUT.background) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_safe(_fore.getSurface(), _fore.x, _fore.y);
surface_reset_shader();
_backDraw = _back;
} else if(_outp == NODE_BLEND_OUTPUT.foreground) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_safe(_fore, 0, 0);
surface_reset_shader();
surface_set_shader(_backDraw, noone,, BLEND.over);
draw_surface_safe(_back, -_fore.x, -_fore.y);
surface_reset_shader();
}
} else if(is_surface(_fore)) {
var sx = 0;
var sy = 0;
var fw = surface_get_width_safe(_fore);
var fh = surface_get_height_safe(_fore);
var px = _posit[0] * ww;
var py = _posit[1] * hh;
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_safe(_fore, px - fw / 2, py - fh / 2);
surface_reset_shader();
_backDraw = _back;
}
} else if(_fill == NODE_BLEND_FILL.stretch) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_stretched(_fore, 0, 0, ww, hh);
surface_reset_shader();
} else if(_fill == NODE_BLEND_FILL.tile) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_tiled(_fore, 0, 0);
surface_reset_shader();
}
var _osurf = is_instanceof(_outSurf, SurfaceAtlas)? _outSurf.surface.surface : _outSurf;
var _output = surface_verify(_osurf, ww, hh, cDep);
_mask = mask_modify(_mask, _mskInv, _mskFea);
surface_set_shader(_output, noone);
if(is_surface(_fore)) draw_surface_blend(_backDraw, _foreDraw, _type, _opacity, _pre_alp, _mask);
else draw_surface_safe(_backDraw);
surface_reset_shader();
if(_atlas) {
var _newAtl = _fore.clone();
if(_outp == NODE_BLEND_OUTPUT.background) {
_newAtl.x = 0;
_newAtl.y = 0;
}
_newAtl.setSurface(_output);
return _newAtl;
}
return _outSurf;
} #endregion
}

View file

@ -0,0 +1,301 @@
// 2024-04-26 15:41:59
#region create
global.node_blend_keys = [
"normal", "add", "subtract", "multiply", "screen",
"overlay", "hue", "saturation", "luminosity", "maximum",
"minimum", "replace", "difference"
];
function Node_create_Blend(_x, _y, _group = noone, _param = {}) {
var node = new Node_Blend(_x, _y, _group);
var query = struct_try_get(_param, "query", "");
var ind = array_find(global.node_blend_keys, query);
if(ind >= 0) node.inputs[| 2].setValue(ind);
return node;
}
enum NODE_BLEND_OUTPUT {
background,
foreground,
mask,
maximum,
constant
}
enum NODE_BLEND_FILL {
none,
stretch,
tile
}
#endregion
function Node_Blend(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor {
name = "Blend";
manage_atlas = false;
inputs[| 0] = nodeValue("Background", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 1] = nodeValue("Foreground", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 2] = nodeValue("Blend mode", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, BLEND_TYPES );
inputs[| 3] = nodeValue("Opacity", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
.setDisplay(VALUE_DISPLAY.slider);
inputs[| 4] = nodeValue("Mask", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 5] = nodeValue("Fill mode", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "None", "Stretch", "Tile" ]);
inputs[| 6] = nodeValue("Output dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Background", "Forground", "Mask", "Maximum", "Constant" ])
.rejectArray();
inputs[| 7] = nodeValue("Constant dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF)
.setDisplay(VALUE_DISPLAY.vector);
inputs[| 8] = nodeValue("Active", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
active_index = 8;
inputs[| 9] = nodeValue("Preserve alpha", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
inputs[| 10] = nodeValue("Horizontal Align", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_button, [ THEME.inspector_surface_halign, THEME.inspector_surface_halign, THEME.inspector_surface_halign]);
inputs[| 11] = nodeValue("Vertical Align", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_button, [ THEME.inspector_surface_valign, THEME.inspector_surface_valign, THEME.inspector_surface_valign]);
inputs[| 12] = nodeValue("Invert mask", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
inputs[| 13] = nodeValue("Mask feather", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
.setDisplay(VALUE_DISPLAY.slider, { range: [1, 16, 0.1] });
inputs[| 14] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0.5, 0.5 ])
.setDisplay(VALUE_DISPLAY.vector);
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
input_display_list = [ 8,
["Surfaces", true], 0, 1, 4, 12, 13, 6, 7,
["Blend", false], 2, 3, 9,
["Transform", false], 5, 14,
]
attribute_surface_depth();
temp_surface = [ surface_create(1, 1), surface_create(1, 1) ];
blend_temp_surface = temp_surface[1];
dragging = false;
drag_sx = 0;
drag_sy = 0;
drag_mx = 0;
drag_my = 0;
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
var _surf = outputs[| 0].getValue();
if(is_array(_surf)) _surf = array_safe_get_fast(_surf, preview_index);
if(is_struct(_surf)) return;
if(!surface_exists(_surf)) return;
var _fore = getSingleValue( 1);
var _fill = getSingleValue( 5);
var _posi = getSingleValue(14);
if(_fill) return;
var sw = surface_get_width_safe( _surf);
var sh = surface_get_height_safe(_surf);
var fw = surface_get_width_safe( _fore);
var fh = surface_get_height_safe(_fore);
var _rx = _posi[0] * sw - fw / 2;
var _ry = _posi[1] * sh - fh / 2;
_rx = _x + _rx * _s;
_ry = _y + _ry * _s;
var _rw = fw * _s;
var _rh = fh * _s;
if(dragging) {
var px = drag_sx + (_mx - drag_mx) / _s;
var py = drag_sy + (_my - drag_my) / _s;
px /= sw;
py /= sh;
if(inputs[| 14].setValue([ px, py ]))
UNDO_HOLDING = true;
if(mouse_release(mb_left)) {
UNDO_HOLDING = false;
dragging = false;
}
}
draw_set_color(COLORS._main_accent);
if(dragging || (active && point_in_rectangle(_mx, _my, _rx, _ry, _rx + _rw, _ry + _rh))) {
draw_rectangle_width(_rx, _ry, _rx + _rw, _ry + _rh, 2);
if(mouse_press(mb_left)) {
dragging = true;
drag_sx = _posi[0] * sw;
drag_sy = _posi[1] * sh;
drag_mx = _mx;
drag_my = _my;
}
} else
draw_rectangle(_rx, _ry, _rx + _rw, _ry + _rh, true);
} #endregion
static step = function() { #region
var _back = getSingleValue(0);
var _fore = getSingleValue(1);
var _fill = getSingleValue(5);
var _outp = getSingleValue(6);
var _atlas = is_instanceof(_fore, SurfaceAtlas);
inputs[| 5].setVisible(!_atlas);
inputs[| 6].editWidget.data_list = _atlas? [ "Background", "Forground" ] : [ "Background", "Forground", "Mask", "Maximum", "Constant" ];
inputs[| 7].setVisible(_outp == 4);
inputs[| 14].setVisible(_fill == 0 && !_atlas);
} #endregion
static processData = function(_outSurf, _data, _output_index, _array_index) { #region
var _back = _data[0];
var _fore = _data[1];
var _type = _data[2];
var _opacity = _data[3];
var _mask = _data[4];
var _fill = _data[5];
var _outp = _data[6];
var _out_dim = _data[7];
var _pre_alp = _data[9];
var _halign = _data[10];
var _valign = _data[11];
var _posit = _data[14];
var _mskInv = _data[12];
var _mskFea = _data[13];
var cDep = attrDepth();
#region dimension
var ww = 1;
var hh = 1;
var _atlas = is_instanceof(_fore, SurfaceAtlas);
switch(_outp) {
case NODE_BLEND_OUTPUT.background :
ww = surface_get_width_safe(_back);
hh = surface_get_height_safe(_back);
break;
case NODE_BLEND_OUTPUT.foreground :
ww = surface_get_width_safe(_fore);
hh = surface_get_height_safe(_fore);
break;
case NODE_BLEND_OUTPUT.mask :
ww = surface_get_width_safe(_mask);
hh = surface_get_height_safe(_mask);
break;
case NODE_BLEND_OUTPUT.maximum :
ww = max(surface_get_width_safe(_back), surface_get_width_safe(_fore), surface_get_width_safe(_mask));
hh = max(surface_get_height_safe(_back), surface_get_height_safe(_fore), surface_get_height_safe(_mask));
break;
case NODE_BLEND_OUTPUT.constant :
ww = _out_dim[0];
hh = _out_dim[1];
break;
}
#endregion
for( var i = 0; i < 2; i++ ) temp_surface[i] = surface_verify(temp_surface[i], ww, hh, cDep);
var _backDraw = temp_surface[0];
var _foreDraw = temp_surface[1];
surface_set_shader(_backDraw, noone,, BLEND.over);
draw_surface_safe(_back);
surface_reset_shader();
if(_fill == NODE_BLEND_FILL.none || _atlas) {
if(_atlas) {
if(_outp == NODE_BLEND_OUTPUT.background) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_safe(_fore.getSurface(), _fore.x, _fore.y);
surface_reset_shader();
_backDraw = _back;
} else if(_outp == NODE_BLEND_OUTPUT.foreground) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_safe(_fore, 0, 0);
surface_reset_shader();
surface_set_shader(_backDraw, noone,, BLEND.over);
draw_surface_safe(_back, -_fore.x, -_fore.y);
surface_reset_shader();
}
} else if(is_surface(_fore)) {
var sx = 0;
var sy = 0;
var fw = surface_get_width_safe(_fore);
var fh = surface_get_height_safe(_fore);
var px = _posit[0] * ww;
var py = _posit[1] * hh;
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_safe(_fore, px - fw / 2, py - fh / 2);
surface_reset_shader();
_backDraw = _back;
}
} else if(_fill == NODE_BLEND_FILL.stretch) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_stretched(_fore, 0, 0, ww, hh);
surface_reset_shader();
} else if(_fill == NODE_BLEND_FILL.tile) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_tiled(_fore, 0, 0);
surface_reset_shader();
}
var _osurf = is_instanceof(_outSurf, SurfaceAtlas)? _outSurf.surface.surface : _outSurf;
var _output = surface_verify(_osurf, ww, hh, cDep);
_mask = mask_modify(_mask, _mskInv, _mskFea);
surface_set_shader(_output, noone);
if(is_surface(_fore)) draw_surface_blend(_backDraw, _foreDraw, _type, _opacity, _pre_alp, _mask);
else draw_surface_safe(_backDraw);
surface_reset_shader();
if(_atlas) {
var _newAtl = _fore.clone();
if(_outp == NODE_BLEND_OUTPUT.background) {
_newAtl.x = 0;
_newAtl.y = 0;
}
_newAtl.setSurface(_output);
return _newAtl;
}
return _outSurf;
} #endregion
}

View file

@ -0,0 +1,86 @@
// 2024-04-26 18:21:19
function Node_Feedback_Inline(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Feedback";
color = COLORS.node_blend_feedback;
icon = THEME.feedback;
icon_24 = THEME.feedback_24;
w = 0;
h = 0;
is_root = false;
selectable = false;
update_on_frame = true;
attributes.junc_in = [ "", 0 ];
attributes.junc_out = [ "", 0 ];
junc_in = noone;
junc_out = noone;
value_buffer = noone;
static bypassConnection = function() { return CURRENT_FRAME > 0; }
static bypassNextNode = function() { return false; }
static getNextNode = function() { return [] };
static scanJunc = function() { #region
var node_in = PROJECT.nodeMap[? attributes.junc_in[0]];
var node_out = PROJECT.nodeMap[? attributes.junc_out[0]];
junc_in = node_in? node_in.inputs[| attributes.junc_in[1]] : noone;
junc_out = node_out? node_out.outputs[| attributes.junc_out[1]] : noone;
if(junc_in) junc_in.value_from_loop = self;
if(junc_out) array_push(junc_out.value_to_loop, self);
} #endregion
static updateValue = function() { #region
var type = junc_out.type;
var val = junc_out.getValue();
switch(type) {
case VALUE_TYPE.surface :
surface_array_free(value_buffer);
value_buffer = surface_array_clone(val);
break;
default :
value_buffer = variable_clone(val);
break;
}
} #endregion
static getValue = function(arr) { #region
INLINE
arr[@ 0] = value_buffer;
arr[@ 1] = junc_out;
} #endregion
static drawConnections = function(params = {}) { #region
if(!active) return noone;
if(!junc_in || !junc_out) return noone;
if(!junc_in.node.active || !junc_out.node.active) return noone;
params.dashed = true;
var sel = drawJuncConnection(junc_out, junc_in, params);
params.dashed = false;
if(sel) return self;
return noone;
} #endregion
static drawNode = function(_x, _y, _mx, _my, _s, display_parameter = noone) {}
static pointIn = function(_x, _y, _mx, _my, _s) { return false; }
static postDeserialize = function() { #region
scanJunc();
} #endregion
static onDestroy = function() { #region
if(junc_in) junc_in.value_from_loop = noone;
if(junc_out) array_remove(junc_out.value_to_loop, self);
} #endregion
}

View file

@ -0,0 +1,86 @@
// 2024-04-26 18:21:04
function Node_Feedback_Inline(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Feedback";
color = COLORS.node_blend_feedback;
icon = THEME.feedback;
icon_24 = THEME.feedback_24;
w = 0;
h = 0;
is_root = false;
selectable = false;
update_on_frame = true;
attributes.junc_in = [ "", 0 ];
attributes.junc_out = [ "", 0 ];
junc_in = noone;
junc_out = noone;
value_buffer = noone;
static bypassConnection = function() { return CURRENT_FRAME > 0; }
static bypassNextNode = function() { return false; }
static getNextNode = function() { return [] };
static scanJunc = function() { #region
var node_in = PROJECT.nodeMap[? attributes.junc_in[0]];
var node_out = PROJECT.nodeMap[? attributes.junc_out[0]];
junc_in = node_in? node_in.inputs[| attributes.junc_in[1]] : noone;
junc_out = node_out? node_out.outputs[| attributes.junc_out[1]] : noone;
if(junc_in) junc_in.value_from_loop = self;
if(junc_out) array_push(junc_out.value_to_loop, self);
} #endregion
static updateValue = function() { #region
var type = junc_out.type;
var val = junc_out.getValue();
switch(type) {
case VALUE_TYPE.surface :
surface_array_free(value_buffer);
value_buffer = surface_array_clone(val);
break;
default :
value_buffer = variable_clone(val);
break;
}
} #endregion
static getValue = function(arr) { #region
INLINE
arr[@ 0] = value_buffer;
arr[@ 1] = junc_out;
} #endregion
static drawConnections = function(params = {}) { #region
if(!active) return noone;
if(!junc_in || !junc_out) return noone;
if(!junc_in.node.active || !junc_out.node.active) return noone;
params.dashed = true;
var sel = drawJuncConnection(junc_out, junc_in, params);
params.dashed = false;
if(sel) return self;
return noone;
} #endregion
static drawNode = function(_x, _y, _mx, _my, _s, display_parameter = noone) {}
static pointIn = function(_x, _y, _mx, _my, _s) { return false; }
static postDeserialize = function() { #region
scanJunc();
} #endregion
static onDestroy = function() { #region
if(junc_in) junc_in.value_from_loop = noone;
if(junc_out) array_remove(junc_out.value_to_loop, self);
} #endregion
}

View file

@ -1,4 +1,4 @@
// 2024-04-26 14:41:10
// 2024-04-26 14:57:55
function Node_Path_Bridge(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Bridge Path";
w = 96;
@ -137,6 +137,7 @@ function Node_Path_Bridge(_x, _y, _group = noone) : Node(_x, _y, _group) constru
var _p = eval_bezier(_rat, p0[0], p0[1], p1[0], p1[1], _c0x, _c0y, _c1x, _c1y);
out.x = _p[0];
out.y = _p[1];
} else {
out.x = lerp(p0[0], p1[0], _rat);
out.y = lerp(p0[1], p1[1], _rat);

View file

@ -1,4 +1,4 @@
// 2024-04-26 14:39:57
// 2024-04-26 14:52:00
function Node_Path_Bridge(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Bridge Path";
w = 96;
@ -137,6 +137,7 @@ function Node_Path_Bridge(_x, _y, _group = noone) : Node(_x, _y, _group) constru
var _p = eval_bezier(_rat, p0[0], p0[1], p1[0], p1[1], _c0x, _c0y, _c1x, _c1y);
out.x = _p[0];
out.y = _p[1];
} else {
out.x = lerp(p0[0], p1[0], _rat);
out.y = lerp(p0[1], p1[1], _rat);

View file

@ -0,0 +1,386 @@
// 2024-04-26 15:11:01
enum ARRAY_PROCESS {
loop,
hold,
expand,
expand_inv,
}
#macro PROCESSOR_OVERLAY_CHECK if(array_length(current_data) != ds_list_size(inputs)) return;
function Node_Processor(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
attributes.array_process = ARRAY_PROCESS.loop;
current_data = [];
inputs_data = [];
inputs_is_array = [];
all_inputs = [];
process_amount = 0;
process_length = [];
dimension_index = 0;
manage_atlas = true;
atlas_index = 0;
batch_output = false; //Run processData once with all outputs as array.
icon = THEME.node_processor_icon;
array_push(attributeEditors, "Array processor");
array_push(attributeEditors, [ "Array process type", function() { return attributes.array_process; },
new scrollBox([ "Loop", "Hold", "Expand", "Expand inverse" ],
function(val) {
attributes.array_process = val;
triggerRender();
}, false) ]);
static getInputData = function(index, def = 0) { INLINE return array_safe_get_fast(inputs_data, index, def); }
static processData_prebatch = function() {}
static processData_postbatch = function() {}
static processData = function(_outSurf, _data, _output_index, _array_index = 0) { return _outSurf; }
static getSingleValue = function(_index, _arr = preview_index, output = false) { #region
var _l = output? outputs : inputs;
var _n = _l[| _index];
var _in = output? _n.getValue() : getInputData(_index);
if(!_n.isArray(_in)) return _in;
var _aIndex = _arr;
if(!is_array(_in)) return 0;
switch(attributes.array_process) {
case ARRAY_PROCESS.loop : _aIndex = safe_mod(_arr, array_length(_in)); break;
case ARRAY_PROCESS.hold : _aIndex = min(_arr, array_length(_in) - 1); break;
case ARRAY_PROCESS.expand : _aIndex = floor(_arr / process_length[_index][1]) % process_length[_index][0]; break;
case ARRAY_PROCESS.expand_inv : _aIndex = floor(_arr / process_length[ds_list_size(_l) - 1 - _index][1]) % process_length[_index][0]; break;
}
return array_safe_get_fast(_in, _aIndex);
} #endregion
static getDimension = function(arr = 0) { #region
if(dimension_index == -1) return [ 1, 1 ];
var _in = getSingleValue(dimension_index, arr);
if(inputs[| dimension_index].type == VALUE_TYPE.surface && is_surface(_in)) {
var ww = surface_get_width_safe(_in);
var hh = surface_get_height_safe(_in);
return [ww, hh];
}
if(is_array(_in) && array_length(_in) == 2)
return _in;
return [1, 1];
} #endregion
static processDataArray = function(outIndex) { #region
var _output = outputs[| outIndex];
var _out = _output.getValue();
var _atlas = false;
var _pAtl = noone;
var _data = array_create(ds_list_size(inputs));
if(process_amount == 1) { #region render single data
if(_output.type == VALUE_TYPE.d3object) //passing 3D vertex call
return _out;
for(var i = 0; i < ds_list_size(inputs); i++)
_data[i] = inputs_data[i];
if(_output.type == VALUE_TYPE.surface) { // Surface preparation
if(manage_atlas) {
_pAtl = _data[atlas_index];
_atlas = is_instanceof(_pAtl, SurfaceAtlas);
if(_atlas) _data[atlas_index] = _pAtl.getSurface();
}
if(dimension_index > -1) {
var surf = _data[dimension_index];
var _sw = 1, _sh = 1;
if(inputs[| dimension_index].type == VALUE_TYPE.surface) {
if(is_surface(surf)) {
_sw = surface_get_width_safe(surf);
_sh = surface_get_height_safe(surf);
} else
return noone;
} else if(is_array(surf)) {
_sw = array_safe_get_fast(surf, 0, 1);
_sh = array_safe_get_fast(surf, 1, 1);
}
if(is_instanceof(_out, SurfaceAtlas)) {
if(manage_atlas) {
surface_free_safe(_out.getSurface())
_out = surface_verify(_out.getSurface(), _sw, _sh, attrDepth());
}
} else
_out = surface_verify(_out, _sw, _sh, attrDepth());
}
}
current_data = _data;
if(active_index > -1 && !_data[active_index]) { // skip
if(inputs[| 0].type == VALUE_TYPE.surface)
return surface_clone(_data[0], _out);
else
return _data[0];
}
var data = processData(_out, _data, outIndex, 0); // Process data
if(_output.type == VALUE_TYPE.surface) {
if(manage_atlas && _atlas && is_surface(data)) { // Convert back to atlas
var _atl = _pAtl.clone();
_atl.setSurface(data);
return _atl;
}
//data = surface_project_posterize(data);
}
return data;
} #endregion
#region ++++ array preparation ++++
if(!is_array(_out))
_out = array_create(process_amount);
else if(array_length(_out) != process_amount)
array_resize(_out, process_amount);
#endregion
for(var l = 0; l < process_amount; l++) {
for(var i = 0; i < ds_list_size(inputs); i++)
_data[i] = all_inputs[i][l];
if(_output.type == VALUE_TYPE.surface) { #region // Output surface verification
if(manage_atlas) {
_pAtl = _data[atlas_index];
_atlas = is_instanceof(_pAtl, SurfaceAtlas);
if(_atlas) _data[atlas_index] = _pAtl.getSurface();
}
if(dimension_index > -1) {
var surf = _data[dimension_index];
var _sw = 1, _sh = 1;
if(inputs[| dimension_index].type == VALUE_TYPE.surface) {
if(is_surface(surf)) {
_sw = surface_get_width_safe(surf);
_sh = surface_get_height_safe(surf);
} else
return noone;
} else if(is_array(surf)) {
_sw = surf[0];
_sh = surf[1];
}
if(is_instanceof(_out[l], SurfaceAtlas)) {
if(manage_atlas) {
surface_free_safe(_out[l].surface.surface)
_out[l] = surface_verify(_out[l].getSurface(), _sw, _sh, attrDepth());
}
} else
_out[l] = surface_verify(_out[l], _sw, _sh, attrDepth());
}
} #endregion
if(l == 0 || l == preview_index)
current_data = _data;
if(active_index > -1 && !_data[active_index]) { // skip
if(!_atlas && inputs[| 0].type == VALUE_TYPE.surface)
_out[l] = surface_clone(_data[0], _out[l]);
else
_out[l] = _data[0];
} else {
_out[l] = processData(_out[l], _data, outIndex, l); // Process data
if(_output.type == VALUE_TYPE.surface) {
if(manage_atlas && _atlas && is_surface(_out[l])) { // Convert back to atlas
var _atl = _pAtl.clone();
_atl.setSurface(_out[l]);
_out[l] = _atl;
}
//data = surface_project_posterize(data);
}
}
}
return _out;
} #endregion
static processBatchOutput = function() { #region
for(var i = 0; i < ds_list_size(outputs); i++) {
if(outputs[| i].type != VALUE_TYPE.surface) continue;
var _res = outputs[| i].getValue();
surface_array_free(_res);
outputs[| i].setValue(noone);
}
if(process_amount == 1) {
var data = processData(noone, inputs_data, 0, 0);
for(var i = 0; i < ds_list_size(outputs); i++) {
var _outp = array_safe_get_fast(data, i, undefined);
if(_outp == undefined) continue;
outputs[| i].setValue(_outp);
}
} else {
var _outputs = array_create(ds_list_size(outputs));
for( var l = 0; l < process_amount; l++ ) {
var _data = array_create(ds_list_size(inputs));
for(var i = 0; i < ds_list_size(inputs); i++)
_data[i] = all_inputs[i][l];
var data = processData(0, _data, 0, l);
for(var i = 0; i < ds_list_size(outputs); i++) {
var _outp = array_safe_get_fast(data, i, undefined);
_outputs[i][l] = _outp;
}
}
for( var i = 0, n = ds_list_size(outputs); i < n; i++ )
outputs[| i].setValue(_outputs[i]);
}
} #endregion
static processOutput = function() { #region
var val;
for(var i = 0; i < ds_list_size(outputs); i++) {
if(outputs[| i].process_array) {
val = processDataArray(i);
if(val == undefined) continue;
} else
val = processData(noone, noone, i);
outputs[| i].setValue(val);
}
} #endregion
static preGetInputs = function() {}
static getInputs = function() { #region
preGetInputs();
var _len = ds_list_size(inputs);
process_amount = 1;
inputs_data = array_verify(inputs_data, _len);
inputs_is_array = array_verify(inputs_is_array, _len);
process_length = array_verify(process_length, _len);
all_inputs = array_verify(all_inputs, _len);
for(var i = 0; i < _len; i++) {
var raw = inputs[| i].getValue();
var amo = inputs[| i].arrayLength(raw);
var val = raw;
if(amo == 0) val = noone; //empty array
else if(amo == 1) val = raw[0]; //spread single array
amo = max(1, amo);
setInputData(i, val);
inputs_is_array[i] = inputs[| i].isArray(val);
switch(attributes.array_process) {
case ARRAY_PROCESS.loop :
case ARRAY_PROCESS.hold :
process_amount = max(process_amount, amo);
break;
case ARRAY_PROCESS.expand :
case ARRAY_PROCESS.expand_inv :
process_amount *= amo;
break;
}
process_length[i] = [amo, process_amount];
}
var amoMax = process_amount;
for( var i = 0; i < _len; i++ ) {
amoMax /= process_length[i][0];
process_length[i][1] = amoMax;
}
for(var i = 0; i < _len; i++)
all_inputs[i] = array_verify(all_inputs[i], process_amount);
for(var l = 0; l < process_amount; l++) #region input preparation
for(var i = 0; i < _len; i++) {
var _in = inputs_data[i];
if(!inputs_is_array[i]) {
all_inputs[i][l] = _in;
continue;
}
if(array_length(_in) == 0) {
all_inputs[i][l] = 0;
continue;
}
var _index = 0;
switch(attributes.array_process) {
case ARRAY_PROCESS.loop : _index = safe_mod(l, array_length(_in)); break;
case ARRAY_PROCESS.hold : _index = min(l, array_length(_in) - 1); break;
case ARRAY_PROCESS.expand : _index = floor(l / process_length[i][1]) % process_length[i][0]; break;
case ARRAY_PROCESS.expand_inv : _index = floor(l / process_length[ds_list_size(inputs) - 1 - i][1]) % process_length[i][0]; break;
}
all_inputs[i][l] = inputs[| i].arrayBalance(_in[_index]);
} #endregion
} #endregion
static update = function(frame = CURRENT_FRAME) { #region
processData_prebatch();
if(batch_output) processBatchOutput();
else processOutput();
processData_postbatch();
postProcess();
} #endregion
static postProcess = function() {}
static processSerialize = function(_map) { #region
_map.array_process = attributes.array_process;
} #endregion
static processDeserialize = function() { #region
attributes.array_process = struct_try_get(load_map, "array_process", ARRAY_PROCESS.loop);
} #endregion
///////////////////// CACHE /////////////////////
static cacheCurrentFrameIndex = function(_frame, index) { #region
cacheArrayCheck();
if(CURRENT_FRAME < 0) return;
if(CURRENT_FRAME >= array_length(cached_output)) return;
var prev = cached_output[CURRENT_FRAME];
surface_array_free(array_safe_get_fast(prev, index));
cached_output[CURRENT_FRAME][index] = surface_array_clone(_frame);
array_safe_set(cache_result, CURRENT_FRAME, true);
return cached_output[CURRENT_FRAME];
} #endregion
static getCacheFrameIndex = function(frame = CURRENT_FRAME, index = 0) { #region
if(frame < 0) return false;
if(!cacheExist(frame)) return noone;
var surf = array_safe_get_fast(cached_output, frame);
return array_safe_get_fast(surf, index);
} #endregion
}

View file

@ -0,0 +1,386 @@
// 2024-04-26 15:11:00
enum ARRAY_PROCESS {
loop,
hold,
expand,
expand_inv,
}
#macro PROCESSOR_OVERLAY_CHECK if(array_length(current_data) != ds_list_size(inputs)) return;
function Node_Processor(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
attributes.array_process = ARRAY_PROCESS.loop;
current_data = [];
inputs_data = [];
inputs_is_array = [];
all_inputs = [];
process_amount = 0;
process_length = [];
dimension_index = 0;
manage_atlas = true;
atlas_index = 0;
batch_output = false; //Run processData once with all outputs as array.
icon = THEME.node_processor_icon;
array_push(attributeEditors, "Array processor");
array_push(attributeEditors, [ "Array process type", function() { return attributes.array_process; },
new scrollBox([ "Loop", "Hold", "Expand", "Expand inverse" ],
function(val) {
attributes.array_process = val;
triggerRender();
}, false) ]);
static getInputData = function(index, def = 0) { INLINE return array_safe_get_fast(inputs_data, index, def); }
static processData_prebatch = function() {}
static processData_postbatch = function() {}
static processData = function(_outSurf, _data, _output_index, _array_index = 0) { return _outSurf; }
static getSingleValue = function(_index, _arr = preview_index, output = false) { #region
var _l = output? outputs : inputs;
var _n = _l[| _index];
var _in = output? _n.getValue() : getInputData(_index);
if(!_n.isArray(_in)) return _in;
var _aIndex = _arr;
if(!is_array(_in)) return 0;
switch(attributes.array_process) {
case ARRAY_PROCESS.loop : _aIndex = safe_mod(_arr, array_length(_in)); break;
case ARRAY_PROCESS.hold : _aIndex = min(_arr, array_length(_in) - 1); break;
case ARRAY_PROCESS.expand : _aIndex = floor(_arr / process_length[_index][1]) % process_length[_index][0]; break;
case ARRAY_PROCESS.expand_inv : _aIndex = floor(_arr / process_length[ds_list_size(_l) - 1 - _index][1]) % process_length[_index][0]; break;
}
return array_safe_get_fast(_in, _aIndex);
} #endregion
static getDimension = function(arr = 0) { #region
if(dimension_index == -1) return [ 1, 1 ];
var _in = getSingleValue(dimension_index, arr);
if(inputs[| dimension_index].type == VALUE_TYPE.surface && is_surface(_in)) {
var ww = surface_get_width_safe(_in);
var hh = surface_get_height_safe(_in);
return [ww, hh];
}
if(is_array(_in) && array_length(_in) == 2)
return _in;
return [1, 1];
} #endregion
static processDataArray = function(outIndex) { #region
var _output = outputs[| outIndex];
var _out = _output.getValue();
var _atlas = false;
var _pAtl = noone;
var _data = array_create(ds_list_size(inputs));
if(process_amount == 1) { #region render single data
if(_output.type == VALUE_TYPE.d3object) //passing 3D vertex call
return _out;
for(var i = 0; i < ds_list_size(inputs); i++)
_data[i] = inputs_data[i];
if(_output.type == VALUE_TYPE.surface) { // Surface preparation
if(manage_atlas) {
_pAtl = _data[atlas_index];
_atlas = is_instanceof(_pAtl, SurfaceAtlas);
if(_atlas) _data[atlas_index] = _pAtl.getSurface();
}
if(dimension_index > -1) {
var surf = _data[dimension_index];
var _sw = 1, _sh = 1;
if(inputs[| dimension_index].type == VALUE_TYPE.surface) {
if(is_surface(surf)) {
_sw = surface_get_width_safe(surf);
_sh = surface_get_height_safe(surf);
} else
return noone;
} else if(is_array(surf)) {
_sw = array_safe_get_fast(surf, 0, 1);
_sh = array_safe_get_fast(surf, 1, 1);
}
if(is_instanceof(_out, SurfaceAtlas)) {
if(manage_atlas) {
surface_free_safe(_out.getSurface())
_out = surface_verify(_out.getSurface(), _sw, _sh, attrDepth());
}
} else
_out = surface_verify(_out, _sw, _sh, attrDepth());
}
}
current_data = _data;
if(active_index > -1 && !_data[active_index]) { // skip
if(inputs[| 0].type == VALUE_TYPE.surface)
return surface_clone(_data[0], _out);
else
return _data[0];
}
var data = processData(_out, _data, outIndex, 0); // Process data
if(_output.type == VALUE_TYPE.surface) {
if(manage_atlas && _atlas && is_surface(data)) { // Convert back to atlas
var _atl = _pAtl.clone();
_atl.setSurface(data);
return _atl;
}
//data = surface_project_posterize(data);
}
return data;
} #endregion
#region ++++ array preparation ++++
if(!is_array(_out))
_out = array_create(process_amount);
else if(array_length(_out) != process_amount)
array_resize(_out, process_amount);
#endregion
for(var l = 0; l < process_amount; l++) {
for(var i = 0; i < ds_list_size(inputs); i++)
_data[i] = all_inputs[i][l];
if(_output.type == VALUE_TYPE.surface) { #region // Output surface verification
if(manage_atlas) {
_pAtl = _data[atlas_index];
_atlas = is_instanceof(_pAtl, SurfaceAtlas);
if(_atlas) _data[atlas_index] = _pAtl.getSurface();
}
if(dimension_index > -1) {
var surf = _data[dimension_index];
var _sw = 1, _sh = 1;
if(inputs[| dimension_index].type == VALUE_TYPE.surface) {
if(is_surface(surf)) {
_sw = surface_get_width_safe(surf);
_sh = surface_get_height_safe(surf);
} else
return noone;
} else if(is_array(surf)) {
_sw = surf[0];
_sh = surf[1];
}
if(is_instanceof(_out[l], SurfaceAtlas)) {
if(manage_atlas) {
surface_free_safe(_out[l].surface.surface)
_out[l] = surface_verify(_out[l].getSurface(), _sw, _sh, attrDepth());
}
} else
_out[l] = surface_verify(_out[l], _sw, _sh, attrDepth());
}
} #endregion
if(l == 0 || l == preview_index)
current_data = _data;
if(active_index > -1 && !_data[active_index]) { // skip
if(!_atlas && inputs[| 0].type == VALUE_TYPE.surface)
_out[l] = surface_clone(_data[0], _out[l]);
else
_out[l] = _data[0];
} else {
_out[l] = processData(_out[l], _data, outIndex, l); // Process data
if(_output.type == VALUE_TYPE.surface) {
if(manage_atlas && _atlas && is_surface(_out[l])) { // Convert back to atlas
var _atl = _pAtl.clone();
_atl.setSurface(_out[l]);
_out[l] = _atl;
}
//data = surface_project_posterize(data);
}
}
}
return _out;
} #endregion
static processBatchOutput = function() { #region
for(var i = 0; i < ds_list_size(outputs); i++) {
if(outputs[| i].type != VALUE_TYPE.surface) continue;
var _res = outputs[| i].getValue();
surface_array_free(_res);
outputs[| i].setValue(noone);
}
if(process_amount == 1) {
var data = processData(noone, inputs_data, 0, 0);
for(var i = 0; i < ds_list_size(outputs); i++) {
var _outp = array_safe_get_fast(data, i, undefined);
if(_outp == undefined) continue;
outputs[| i].setValue(_outp);
}
} else {
var _outputs = array_create(ds_list_size(outputs));
for( var l = 0; l < process_amount; l++ ) {
var _data = array_create(ds_list_size(inputs));
for(var i = 0; i < ds_list_size(inputs); i++)
_data[i] = all_inputs[i][l];
var data = processData(0, _data, 0, l);
for(var i = 0; i < ds_list_size(outputs); i++) {
var _outp = array_safe_get_fast(data, i, undefined);
_outputs[i][l] = _outp;
}
}
for( var i = 0, n = ds_list_size(outputs); i < n; i++ )
outputs[| i].setValue(_outputs[i]);
}
} #endregion
static processOutput = function() { #region
var val;
for(var i = 0; i < ds_list_size(outputs); i++) {
if(outputs[| i].process_array) {
val = processDataArray(i);
if(val == undefined) continue;
} else
val = processData(noone, noone, i);
outputs[| i].setValue(val);
}
} #endregion
static preGetInputs = function() {}
static getInputs = function() { #region
preGetInputs();
var _len = ds_list_size(inputs);
process_amount = 1;
inputs_data = array_verify(inputs_data, _len);
inputs_is_array = array_verify(inputs_is_array, _len);
process_length = array_verify(process_length, _len);
all_inputs = array_verify(all_inputs, _len);
for(var i = 0; i < _len; i++) {
var raw = inputs[| i].getValue();
var amo = inputs[| i].arrayLength(raw);
var val = raw;
if(amo == 0) val = noone; //empty array
else if(amo == 1) val = raw[0]; //spread single array
amo = max(1, amo);
setInputData(i, val);
inputs_is_array[i] = inputs[| i].isArray(val);
switch(attributes.array_process) {
case ARRAY_PROCESS.loop :
case ARRAY_PROCESS.hold :
process_amount = max(process_amount, amo);
break;
case ARRAY_PROCESS.expand :
case ARRAY_PROCESS.expand_inv :
process_amount *= amo;
break;
}
process_length[i] = [amo, process_amount];
}
var amoMax = process_amount;
for( var i = 0; i < _len; i++ ) {
amoMax /= process_length[i][0];
process_length[i][1] = amoMax;
}
for(var i = 0; i < _len; i++)
all_inputs[i] = array_verify(all_inputs[i], process_amount);
for(var l = 0; l < process_amount; l++) #region input preparation
for(var i = 0; i < _len; i++) {
var _in = inputs_data[i];
if(!inputs_is_array[i]) {
all_inputs[i][l] = _in;
continue;
}
if(array_length(_in) == 0) {
all_inputs[i][l] = 0;
continue;
}
var _index = 0;
switch(attributes.array_process) {
case ARRAY_PROCESS.loop : _index = safe_mod(l, array_length(_in)); break;
case ARRAY_PROCESS.hold : _index = min(l, array_length(_in) - 1); break;
case ARRAY_PROCESS.expand : _index = floor(l / process_length[i][1]) % process_length[i][0]; break;
case ARRAY_PROCESS.expand_inv : _index = floor(l / process_length[ds_list_size(inputs) - 1 - i][1]) % process_length[i][0]; break;
}
all_inputs[i][l] = inputs[| i].arrayBalance(_in[_index]);
} #endregion
} #endregion
static update = function(frame = CURRENT_FRAME) { #region
processData_prebatch();
if(batch_output) processBatchOutput();
else processOutput();
processData_postbatch();
postProcess();
} #endregion
static postProcess = function() {}
static processSerialize = function(_map) { #region
_map.array_process = attributes.array_process;
} #endregion
static processDeserialize = function() { #region
attributes.array_process = struct_try_get(load_map, "array_process", ARRAY_PROCESS.loop);
} #endregion
///////////////////// CACHE /////////////////////
static cacheCurrentFrameIndex = function(_frame, index) { #region
cacheArrayCheck();
if(CURRENT_FRAME < 0) return;
if(CURRENT_FRAME >= array_length(cached_output)) return;
var prev = cached_output[CURRENT_FRAME];
surface_array_free(array_safe_get_fast(prev, index));
cached_output[CURRENT_FRAME][index] = surface_array_clone(_frame);
array_safe_set(cache_result, CURRENT_FRAME, true);
return cached_output[CURRENT_FRAME];
} #endregion
static getCacheFrameIndex = function(frame = CURRENT_FRAME, index = 0) { #region
if(frame < 0) return false;
if(!cacheExist(frame)) return noone;
var surf = array_safe_get_fast(cached_output, frame);
return array_safe_get_fast(surf, index);
} #endregion
}

View file

@ -1,4 +1,4 @@
// 2024-04-24 08:43:01
// 2024-04-26 18:11:04
#region ---- global names ----
global.junctionEndName = [ "Hold", "Loop", "Ping pong", "Wrap" ];

View file

@ -1,4 +1,4 @@
// 2024-04-24 08:42:22
// 2024-04-24 08:43:01
#region ---- global names ----
global.junctionEndName = [ "Hold", "Loop", "Ping pong", "Wrap" ];

View file

@ -1,4 +1,4 @@
// 2024-04-25 15:21:26
// 2024-04-26 16:01:35
#region funtion calls
function __fnInit_Preview() {
__registerFunction("preview_focus_content", panel_preview_focus_content);

View file

@ -1,4 +1,4 @@
// 2024-04-22 18:45:51
// 2024-04-26 15:47:58
#region funtion calls
function __fnInit_Preview() {
__registerFunction("preview_focus_content", panel_preview_focus_content);

View file

@ -1,4 +1,4 @@
// 2024-04-21 15:41:41
// 2024-04-26 15:47:55
#region ==================================== DRAW ====================================
function draw_surface_safe(surface, _x = 0, _y = 0) { #region
@ -219,8 +219,9 @@
function surface_get_pixel_ext(surface, _x, _y) { #region
INLINE
if(!is_surface(surface)) return 0;
if(is_instanceof(surface, SurfaceAtlas)) surface = surface.surface.get();
if(!surface_exists(surface)) return 0;
var px = surface_getpixel_ext(surface, _x, _y);
if(is_numeric(px)) return int64(px);
@ -559,7 +560,8 @@
} #endregion
function surface_encode(surface, stringify = true) { #region
if(!is_surface(surface)) return "";
if(is_instanceof(surface, SurfaceAtlas)) surface = surface.surface.get();
if(!surface_exists(surface)) return "";
var buff = buffer_create(surface_get_width_safe(surface) * surface_get_height_safe(surface) * 4, buffer_fixed, 1);

View file

@ -1,4 +1,4 @@
// 2024-04-21 15:41:27
// 2024-04-26 15:43:13
#region ==================================== DRAW ====================================
function draw_surface_safe(surface, _x = 0, _y = 0) { #region
@ -559,7 +559,8 @@
} #endregion
function surface_encode(surface, stringify = true) { #region
if(!is_surface(surface)) return "";
if(is_instanceof(surface, SurfaceAtlas)) surface = surface.surface.get();
if(!surface_exists(surface)) return "";
var buff = buffer_create(surface_get_width_safe(surface) * surface_get_height_safe(surface) * 4, buffer_fixed, 1);

View file

@ -0,0 +1,66 @@
// 2024-04-26 18:07:44
//
// Simple passthrough fragment shader
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
//Texel size (1/resolution)
uniform vec2 dimension;
#define SPAN_MAX (8.0) //Maximum texel span
//These are more technnical and probably don't need changing:
#define REDUCE_MIN (1.0 / 128.0) //Minimum "dir" reciprocal
#define REDUCE_MUL (1.0 / 32.0) //Luma multiplier for "dir" reciprocal
vec4 textureFXAA(sampler2D tex, vec2 uv) {
vec2 u_texel = 1. / dimension;
//Sample center and 4 corners
vec3 rgbCC = texture2D(tex, uv).rgb;
vec3 rgb00 = texture2D(tex, uv + vec2( -0.5, -0.5) * u_texel).rgb;
vec3 rgb10 = texture2D(tex, uv + vec2( +0.5, -0.5) * u_texel).rgb;
vec3 rgb01 = texture2D(tex, uv + vec2( -0.5, +0.5) * u_texel).rgb;
vec3 rgb11 = texture2D(tex, uv + vec2( +0.5, +0.5) * u_texel).rgb;
//Luma coefficients
const vec3 luma = vec3(0.299, 0.587, 0.114);
//Get luma from the 5 samples
float lumaCC = dot(rgbCC, luma);
float luma00 = dot(rgb00, luma);
float luma10 = dot(rgb10, luma);
float luma01 = dot(rgb01, luma);
float luma11 = dot(rgb11, luma);
//Compute gradient from luma values
vec2 dir = vec2((luma01 + luma11) - (luma00 + luma10), (luma00 + luma01) - (luma10 + luma11));
//Diminish dir length based on total luma
float dirReduce = max((luma00 + luma10 + luma01 + luma11) * REDUCE_MUL, REDUCE_MIN);
//Divide dir by the distance to nearest edge plus dirReduce
float rcpDir = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
//Multiply by reciprocal and limit to pixel span
dir = clamp(dir * rcpDir, -SPAN_MAX, SPAN_MAX) * u_texel.xy;
//Average middle texels along dir line
vec4 A = 0.5 * (
texture2D(tex, uv - dir * (1.0 / 6.0)) +
texture2D(tex, uv + dir * (1.0 / 6.0)));
//Average with outer texels along dir line
vec4 B = A * 0.5 + 0.25 * (
texture2D(tex, uv - dir * (0.5)) +
texture2D(tex, uv + dir * (0.5)));
//Get lowest and highest luma values
float lumaMin = min(lumaCC, min(min(luma00, luma10), min(luma01, luma11)));
float lumaMax = max(lumaCC, max(max(luma00, luma10), max(luma01, luma11)));
//Get average luma
float lumaB = dot(B.rgb, luma);
//If the average is outside the luma range, using the middle average
return ((lumaB < lumaMin) || (lumaB > lumaMax)) ? A : B;
}
void main() {
gl_FragColor = textureFXAA( gm_BaseTexture, v_vTexcoord );
}

View file

@ -355,8 +355,18 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
if(array_empty(surfs)) return;
for( var i = 0, n = array_length(surfs); i < n; i++ ) {
if(is_surface(surface_cache[$ surfs[i]])) continue;
surface_cache[$ surfs[i]] = surface_clone(surfs[i]);
var _s = surfs[i];
if(is_surface(surface_cache[$ _s]))
continue;
if(is_instanceof(_s, SurfaceAtlas))
_s = _s.surface.get();
if(!surface_exists(_s))
continue;
surface_cache[$ surfs[i]] = surface_clone(_s);
}
} #endregion

View file

@ -14,11 +14,24 @@
return node;
}
enum NODE_BLEND_OUTPUT {
background,
foreground,
mask,
maximum,
constant
}
enum NODE_BLEND_FILL {
none,
stretch,
tile
}
#endregion
function Node_Blend(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor {
name = "Blend";
atlas_index = 1;
manage_atlas = false;
inputs[| 0] = nodeValue("Background", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
@ -176,48 +189,53 @@ function Node_Blend(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) con
var _atlas = is_instanceof(_fore, SurfaceAtlas);
switch(_outp) {
case 0 :
case NODE_BLEND_OUTPUT.background :
ww = surface_get_width_safe(_back);
hh = surface_get_height_safe(_back);
break;
case 1 :
case NODE_BLEND_OUTPUT.foreground :
ww = surface_get_width_safe(_fore);
hh = surface_get_height_safe(_fore);
break;
case 2 :
case NODE_BLEND_OUTPUT.mask :
ww = surface_get_width_safe(_mask);
hh = surface_get_height_safe(_mask);
break;
case 3 :
case NODE_BLEND_OUTPUT.maximum :
ww = max(surface_get_width_safe(_back), surface_get_width_safe(_fore), surface_get_width_safe(_mask));
hh = max(surface_get_height_safe(_back), surface_get_height_safe(_fore), surface_get_height_safe(_mask));
break;
case 4 :
case NODE_BLEND_OUTPUT.constant :
ww = _out_dim[0];
hh = _out_dim[1];
break;
}
#endregion
for( var i = 0; i < 2; i++ )
temp_surface[i] = surface_verify(temp_surface[i], ww, hh, cDep);
for( var i = 0; i < 2; i++ ) temp_surface[i] = surface_verify(temp_surface[i], ww, hh, cDep);
var _backDraw = temp_surface[0];
var _foreDraw = temp_surface[1];
var _backDraw = temp_surface[0];
var _foreDraw = temp_surface[1];
surface_set_shader(_backDraw, noone,, BLEND.over);
draw_surface_safe(_back);
surface_reset_shader();
if(_fill == 0 || _atlas) {
if(_fill == NODE_BLEND_FILL.none || _atlas) {
if(_atlas) {
if(_outp == 0) {
if(_outp == NODE_BLEND_OUTPUT.background) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_safe(_fore.getSurface(), _fore.x, _fore.y);
surface_reset_shader();
_backDraw = _back;
} else if(_outp == 1) {
} else if(_outp == NODE_BLEND_OUTPUT.foreground) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_safe(_fore, 0, 0);
surface_reset_shader();
@ -226,6 +244,7 @@ function Node_Blend(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) con
draw_surface_safe(_back, -_fore.x, -_fore.y);
surface_reset_shader();
}
} else if(is_surface(_fore)) {
var sx = 0;
var sy = 0;
@ -242,11 +261,13 @@ function Node_Blend(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) con
_backDraw = _back;
}
} else if(_fill == 1) {
} else if(_fill == NODE_BLEND_FILL.stretch) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_stretched(_fore, 0, 0, ww, hh);
surface_reset_shader();
} else if(_fill == 2) {
} else if(_fill == NODE_BLEND_FILL.tile) {
surface_set_shader(_foreDraw, noone,, BLEND.over);
draw_surface_tiled(_fore, 0, 0);
surface_reset_shader();
@ -258,19 +279,14 @@ function Node_Blend(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) con
_mask = mask_modify(_mask, _mskInv, _mskFea);
surface_set_shader(_output, noone);
if(is_surface(_fore)) {
draw_surface_blend(_backDraw, _foreDraw, _type, _opacity, _pre_alp, _mask);
} else {
BLEND_OVERRIDE
draw_surface(_backDraw, 0, 0);
BLEND_NORMAL
}
if(is_surface(_fore)) draw_surface_blend(_backDraw, _foreDraw, _type, _opacity, _pre_alp, _mask);
else draw_surface_safe(_backDraw);
surface_reset_shader();
if(_atlas) {
var _newAtl = _fore.clone();
if(_outp == 0) {
if(_outp == NODE_BLEND_OUTPUT.background) {
_newAtl.x = 0;
_newAtl.y = 0;
}

View file

@ -19,15 +19,9 @@ function Node_Feedback_Inline(_x, _y, _group = noone) : Node(_x, _y, _group) con
value_buffer = noone;
static bypassConnection = function() { #region
return CURRENT_FRAME > 0;
} #endregion
static bypassNextNode = function() { #region
return false;
} #endregion
static getNextNode = function() { return [] };
static bypassConnection = function() { return CURRENT_FRAME > 0; }
static bypassNextNode = function() { return false; }
static getNextNode = function() { return [] };
static scanJunc = function() { #region
var node_in = PROJECT.nodeMap[? attributes.junc_in[0]];
@ -49,13 +43,14 @@ function Node_Feedback_Inline(_x, _y, _group = noone) : Node(_x, _y, _group) con
surface_array_free(value_buffer);
value_buffer = surface_array_clone(val);
break;
default :
value_buffer = variable_clone(val);
break;
}
} #endregion
static getValue = function() { #region
static getValue = function(arr) { #region
INLINE
arr[@ 0] = value_buffer;

View file

@ -136,6 +136,7 @@ function Node_Path_Bridge(_x, _y, _group = noone) : Node(_x, _y, _group) constru
var _p = eval_bezier(_rat, p0[0], p0[1], p1[0], p1[1], _c0x, _c0y, _c1x, _c1y);
out.x = _p[0];
out.y = _p[1];
} else {
out.x = lerp(p0[0], p1[0], _rat);
out.y = lerp(p0[1], p1[1], _rat);

View file

@ -113,9 +113,11 @@ function Node_Processor(_x, _y, _group = noone) : Node(_x, _y, _group) construct
_sh = array_safe_get_fast(surf, 1, 1);
}
if(manage_atlas && is_instanceof(_out, SurfaceAtlas)) {
surface_free_safe(_out.getSurface())
_out = surface_verify(_out.getSurface(), _sw, _sh, attrDepth());
if(is_instanceof(_out, SurfaceAtlas)) {
if(manage_atlas) {
surface_free_safe(_out.getSurface())
_out = surface_verify(_out.getSurface(), _sw, _sh, attrDepth());
}
} else
_out = surface_verify(_out, _sw, _sh, attrDepth());
}
@ -178,9 +180,12 @@ function Node_Processor(_x, _y, _group = noone) : Node(_x, _y, _group) construct
_sh = surf[1];
}
if(manage_atlas && is_instanceof(_out[l], SurfaceAtlas)) {
surface_free_safe(_out[l].surface.surface)
_out[l] = surface_verify(_out[l].getSurface(), _sw, _sh, attrDepth());
if(is_instanceof(_out[l], SurfaceAtlas)) {
if(manage_atlas) {
surface_free_safe(_out[l].surface.surface)
_out[l] = surface_verify(_out[l].getSurface(), _sw, _sh, attrDepth());
}
} else
_out[l] = surface_verify(_out[l], _sw, _sh, attrDepth());
}

View file

@ -218,8 +218,9 @@
function surface_get_pixel_ext(surface, _x, _y) { #region
INLINE
if(!is_surface(surface)) return 0;
if(is_instanceof(surface, SurfaceAtlas)) surface = surface.surface.get();
if(!surface_exists(surface)) return 0;
var px = surface_getpixel_ext(surface, _x, _y);
if(is_numeric(px)) return int64(px);
@ -558,7 +559,8 @@
} #endregion
function surface_encode(surface, stringify = true) { #region
if(!is_surface(surface)) return "";
if(is_instanceof(surface, SurfaceAtlas)) surface = surface.surface.get();
if(!surface_exists(surface)) return "";
var buff = buffer_create(surface_get_width_safe(surface) * surface_get_height_safe(surface) * 4, buffer_fixed, 1);