Pixel-Composer/scripts/node_path_scatter/node_path_scatter.gml

234 lines
7.4 KiB
Plaintext

function Node_Path_Scatter(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Scatter Path";
setDimension(96, 48);
inputs[| 0] = nodeValue("Base Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.pathnode, noone)
.setVisible(true, true);
inputs[| 1] = nodeValue("Scatter Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.pathnode, noone)
.setVisible(true, true);
inputs[| 2] = nodeValue("Range", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 1 ])
.setDisplay(VALUE_DISPLAY.slider_range);
inputs[| 3] = nodeValue("Amount", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 4);
inputs[| 4] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0.5, 1 ])
.setDisplay(VALUE_DISPLAY.slider_range);
inputs[| 5] = nodeValue("Seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, seed_random(6))
.setDisplay(VALUE_DISPLAY._default, { side_button : button(function() { randomize(); inputs[| 5].setValue(seed_random(6)); }).setIcon(THEME.icon_random, 0, COLORS._main_icon) });
inputs[| 6] = nodeValue("Scale over Length", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_11);
inputs[| 7] = nodeValue("Rotation", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 45, 135, 0, 0 ] )
.setDisplay(VALUE_DISPLAY.rotation_random);
inputs[| 8] = nodeValue("Distribution", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0 )
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Uniform", "Random" ]);
inputs[| 9] = nodeValue("Trim over Length", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_11);
inputs[| 10] = nodeValue("Range", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
.setDisplay(VALUE_DISPLAY.slider);
inputs[| 11] = nodeValue("Flip if Negative", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false );
inputs[| 12] = nodeValue("Origin", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0 )
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Individual", "First", "Zero" ]);
outputs[| 0] = nodeValue("Path", self, JUNCTION_CONNECT.output, VALUE_TYPE.pathnode, self);
input_display_list = [ 5,
["Paths", false], 0, 1, 10, 9,
["Scatter", false], 8, 3,
["Position", false], 12, 2,
["Rotation", false], 7, 11,
["Scale", false], 4, 6,
];
cached_pos = ds_map_create();
line_amount = 0;
paths = [];
segment_counts = [];
line_lengths = [];
accu_lengths = [];
__temp_p = [ 0, 0 ];
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
var _path = getInputData(0);
if(_path && struct_has(_path, "drawOverlay")) _path.drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny);
var _path = getInputData(1);
if(_path && struct_has(_path, "drawOverlay")) _path.drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny);
} #endregion
static getLineCount = function() { return line_amount; }
static getSegmentCount = function(ind = 0) { return array_safe_get_fast(segment_counts, ind); }
static getLength = function(ind = 0) { return array_safe_get_fast(line_lengths, ind); }
static getAccuLength = function(ind = 0) { return array_safe_get_fast(accu_lengths, ind); }
static getPointRatio = function(_rat, ind = 0, out = undefined) { #region
if(out == undefined) out = new __vec2(); else { out.x = 0; out.y = 0; }
var _path = array_safe_get_fast(paths, ind, 0);
if(_path == 0) return out;
var _pathObj = _path.path;
if(!is_struct(_pathObj) || !struct_has(_pathObj, "getPointRatio"))
return out;
var _ind = _path.index;
var _ori = _path.ori;
var _pos = _path.pos;
var _rot = _path.rot;
var _rotW = _path.rotW;
var _sca = _path.sca;
var _trm = _path.trim;
var _flip = _path.flip;
_rat *= _trm;
out = _pathObj.getPointRatio(_rat, _ind, out);
var _px = out.x - _ori[0];
var _py = out.y - _ori[1];
if(_flip && angle_difference(_rotW, 90) < 0)
_px = -_px;
__temp_p = point_rotate(_px, _py, 0, 0, _rot, __temp_p);
out.x = _pos[0] + __temp_p[0] * _sca;
out.y = _pos[1] + __temp_p[1] * _sca;
return out;
} #endregion
static getPointDistance = function(_dist, ind = 0, out = undefined) { return getPointRatio(_dist / getLength(ind), ind, out); }
static getBoundary = function(ind = 0) { #region
var _path = getInputData(0);
return struct_has(_path, "getBoundary")? _path.getBoundary(ind) : new BoundingBox( 0, 0, 1, 1 );
} #endregion
static update = function() { #region
ds_map_clear(cached_pos);
var path_base = getInputData(0);
var path_scat = getInputData(1);
var _range = getInputData(2);
var _repeat = getInputData(3);
var _scale = getInputData(4);
var _seed = getInputData(5);
var _sca_wid = getInputData(6);
var _rotation = getInputData(7);
var _distrib = getInputData(8);
var _trim = getInputData(9);
var _trim_rng = getInputData(10);
var _flip = getInputData(11);
var _resetOri = getInputData(12);
if(path_base == noone) return;
if(path_scat == noone) return;
var p = new __vec2();
random_set_seed(_seed);
var _line_amounts = path_scat.getLineCount();
var _ind = 0;
line_amount = _repeat * _line_amounts;
paths = array_create(line_amount);
segment_counts = array_create(line_amount);
line_lengths = array_create(line_amount);
accu_lengths = array_create(line_amount);
var ori, pos;
var _prog_raw, _prog;
var x0, y0, x1, y1;
var _dir, _sca, _rot, _rotW, _trm;
for (var i = 0; i < _repeat; i++) {
_prog_raw = _distrib? random_range(0, 1) : (i / max(1, _repeat - 1)) * 0.9999;
_prog = lerp(_range[0], _range[1], _prog_raw);
_sca = random_range(_scale[0], _scale[1]);
_sca *= eval_curve_x(_sca_wid, _prog_raw);
_rot = angle_random_eval(_rotation);
_trm = _trim_rng;
_trm *= eval_curve_x(_trim, _prog_raw);
for (var k = 0; k < _line_amounts; k++) {
switch(_resetOri) {
case 0 :
p = path_scat.getPointRatio(0, k, p);
ori = [ p.x, p.y ];
break;
case 1 :
p = path_scat.getPointRatio(0, 0, p);
ori = [ p.x, p.y ];
break;
case 2 :
ori = [ 0, 0 ];
break;
}
p = path_base.getPointRatio(_prog, k, p);
pos = [ p.x, p.y ];
p = path_base.getPointRatio(clamp(_prog - 0.001, 0., 0.9999), k, p);
x0 = p.x;
y0 = p.y;
p = path_base.getPointRatio(clamp(_prog + 0.001, 0., 0.9999), k, p);
x1 = p.x;
y1 = p.y;
_dir = point_direction(x0, y0, x1, y1);
_dir += _rot;
paths[_ind] = {
path : path_scat,
index : k,
ori : ori,
pos : pos,
rot : _dir,
rotW : _rot,
sca : _sca,
trim : max(0, _trm),
flip : _flip,
}
var _segment_counts = array_clone(path_scat.getSegmentCount(k));
var _line_lengths = array_clone(path_scat.getLength(k));
var _accu_lengths = array_clone(path_scat.getAccuLength(k));
_line_lengths *= _sca;
for (var j = 0, m = array_length(_accu_lengths); j < m; j++)
_accu_lengths[j] *= _sca;
segment_counts[_ind] = _segment_counts;
line_lengths[_ind] = _line_lengths;
accu_lengths[_ind] = _accu_lengths;
_ind++;
}
}
outputs[| 0].setValue(self);
} #endregion
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(s_node_path_scatter, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
} #endregion
}