2023-11-28 06:50:54 +01:00
enum NODE_SCATTER_DIST {
area,
border,
map,
data,
path,
tile
}
2023-02-28 09:43:01 +01:00
function Node_Scatter(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor {
2022-01-13 05:24:03 +01:00
name = "Scatter";
2023-02-14 05:32:32 +01:00
dimension_index = 1;
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
inputs[| 0] = nodeValue("Surface in", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
2022-01-13 05:24:03 +01:00
2023-07-21 12:40:20 +02:00
inputs[| 1] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF )
2022-01-13 05:24:03 +01:00
.setDisplay(VALUE_DISPLAY.vector);
2023-02-14 05:32:32 +01:00
inputs[| 2] = nodeValue("Amount", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 8);
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
inputs[| 3] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 1, 1, 1, 1 ] )
2023-09-27 14:55:21 +02:00
.setDisplay(VALUE_DISPLAY.vector_range, { linked : true });
2022-01-13 05:24:03 +01:00
2023-09-19 12:53:24 +02:00
inputs[| 4] = nodeValue("Angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, [ 0, 0, 0, 0, 0 ] )
2023-09-11 16:08:58 +02:00
.setDisplay(VALUE_DISPLAY.rotation_random);
2022-01-13 05:24:03 +01:00
2023-11-24 10:41:53 +01:00
onSurfaceSize = function() { return getInputData(1, DEF_SURF); };
2023-07-21 12:40:20 +02:00
inputs[| 5] = nodeValue("Area", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, [ DEF_SURF_W / 2, DEF_SURF_H / 2, DEF_SURF_W / 2, DEF_SURF_H / 2, AREA_SHAPE.rectangle ])
2023-10-02 08:57:44 +02:00
.setDisplay(VALUE_DISPLAY.area, { onSurfaceSize });
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
inputs[| 6] = nodeValue("Distribution", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
2023-07-31 11:47:18 +02:00
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Area", "Border", "Map", "Direct Data", "Path", "Full image + Tile" ]);
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
inputs[| 7] = nodeValue("Point at center", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false, "Rotate each copy to face the spawn center.");
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
inputs[| 8] = nodeValue("Uniform scaling", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
inputs[| 9] = nodeValue("Scatter", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 1)
2022-01-19 03:05:13 +01:00
.setDisplay(VALUE_DISPLAY.enum_button, [ "Uniform", "Random" ]);
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
inputs[| 10] = nodeValue("Seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, irandom(9999999));
2023-01-17 08:11:55 +01:00
2023-05-28 20:00:51 +02:00
inputs[| 11] = nodeValue("Random blend", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) );
2023-01-17 08:11:55 +01:00
2023-02-14 05:32:32 +01:00
inputs[| 12] = nodeValue("Alpha", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 1, 1 ])
2023-10-02 08:57:44 +02:00
.setDisplay(VALUE_DISPLAY.slider_range);
2023-02-14 05:32:32 +01:00
inputs[| 13] = nodeValue("Distribution map", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, 0);
inputs[| 14] = nodeValue("Distribution data", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [])
.setDisplay(VALUE_DISPLAY.vector);
2023-02-21 04:48:50 +01:00
inputs[| 14].array_depth = 1;
2022-01-13 05:24:03 +01:00
2023-02-19 02:13:19 +01:00
inputs[| 15] = nodeValue("Array", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0, @"What to do when input array of surface.
- Spread: Create Array of output each scattering single surface.
- Mixed: Create single output scattering multiple images.")
2023-02-14 05:32:32 +01:00
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Spread output", "Mixed" ]);
2023-02-19 02:13:19 +01:00
inputs[| 16] = nodeValue("Multiply alpha", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
2023-03-23 13:38:50 +01:00
inputs[| 17] = nodeValue("Use value", self, JUNCTION_CONNECT.input, VALUE_TYPE.text, [ "Scale" ], "Apply the third value in each data point (if exist) on given properties.")
2023-10-02 08:57:44 +02:00
.setDisplay(VALUE_DISPLAY.text_array, { data: [ "Scale", "Rotation", "Color" ] });
2023-02-21 04:48:50 +01:00
2023-03-28 06:58:28 +02:00
inputs[| 18] = nodeValue("Blend mode", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Normal", "Add" ]);
2023-04-16 15:26:52 +02:00
inputs[| 19] = nodeValue("Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.pathnode, noone);
2023-07-21 12:40:20 +02:00
inputs[| 20] = nodeValue("Rotate along path", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
2023-08-12 12:35:35 +02:00
inputs[| 21] = nodeValue("Path Shift", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0)
2023-10-02 08:57:44 +02:00
.setDisplay(VALUE_DISPLAY.slider);
2023-08-12 12:35:35 +02:00
inputs[| 22] = nodeValue("Scatter Distance", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0);
2024-01-12 05:03:35 +01:00
inputs[| 23] = nodeValue("Sort Y", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
2023-08-12 12:35:35 +02:00
2023-02-14 05:32:32 +01:00
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
2023-04-16 15:26:52 +02:00
2023-10-06 11:51:11 +02:00
outputs[| 1] = nodeValue("Atlas data", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, [])
2023-05-28 20:00:51 +02:00
.rejectArrayProcess();
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
input_display_list = [
2023-11-08 14:37:51 +01:00
["Surfaces", true], 0, 1, 15, 10,
2023-08-12 12:35:35 +02:00
["Scatter", false], 5, 6, 13, 14, 17, 9, 2,
["Path", false], 19, 20, 21, 22,
2023-01-17 08:11:55 +01:00
["Transform", false], 3, 8, 7, 4,
2024-01-12 05:03:35 +01:00
["Render", false], 18, 11, 12, 16, 23,
2022-01-13 05:24:03 +01:00
];
2023-03-19 09:17:39 +01:00
attribute_surface_depth();
2023-04-16 15:26:52 +02:00
scatter_data = [];
2023-11-03 14:43:28 +01:00
static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
2023-02-21 04:48:50 +01:00
if(process_amount > 1) return;
var _distType = current_data[6];
if(_distType < 3)
inputs[| 5].drawOverlay(active, _x, _y, _s, _mx, _my, _snx, _sny);
2023-11-03 14:43:28 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2023-11-03 14:43:28 +01:00
static onValueUpdate = function(index) { #region
2023-02-14 05:32:32 +01:00
if(index == 15) {
2023-10-02 08:57:44 +02:00
var _arr = getInputData(15);
2023-02-21 04:48:50 +01:00
inputs[| 0].array_depth = _arr;
2023-02-14 05:32:32 +01:00
2023-04-16 15:26:52 +02:00
update();
2023-02-14 05:32:32 +01:00
}
2023-11-03 14:43:28 +01:00
} #endregion
2023-02-14 05:32:32 +01:00
2023-11-03 14:43:28 +01:00
static step = function() { #region
2023-10-02 08:57:44 +02:00
var _dis = getInputData(6);
var _arr = getInputData(15);
2023-02-21 04:48:50 +01:00
inputs[| 0].array_depth = _arr;
2023-02-14 05:32:32 +01:00
inputs[| 13].setVisible(_dis == 2, _dis == 2);
inputs[| 14].setVisible(_dis == 3, _dis == 3);
2023-02-21 04:48:50 +01:00
inputs[| 17].setVisible(_dis == 3);
2023-02-14 05:32:32 +01:00
inputs[| 9].setVisible(_dis != 2);
2023-04-16 15:26:52 +02:00
inputs[| 19].setVisible(_dis == 4, _dis == 4);
2023-07-21 12:40:20 +02:00
inputs[| 20].setVisible(_dis == 4);
2023-08-12 12:35:35 +02:00
inputs[| 21].setVisible(_dis == 4);
inputs[| 22].setVisible(_dis == 4);
2023-11-03 14:43:28 +01:00
} #endregion
2023-02-14 05:32:32 +01:00
2023-11-03 14:43:28 +01:00
static processData = function(_outSurf, _data, _output_index, _array_index) { #region
2023-04-16 15:26:52 +02:00
if(_output_index == 1) return scatter_data;
2023-02-14 05:32:32 +01:00
var _inSurf = _data[0];
2022-01-13 05:24:03 +01:00
if(_inSurf == 0)
return;
2022-12-22 03:09:55 +01:00
var _dim = _data[1];
var _amount = _data[2];
var _scale = _data[3];
var _rota = _data[4];
2022-01-13 05:24:03 +01:00
2022-12-22 03:09:55 +01:00
var _area = _data[5];
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
var _dist = _data[ 6];
var _distMap = _data[13];
var _distData = _data[14];
var _scat = _data[ 9];
2022-01-13 05:24:03 +01:00
2022-12-22 03:09:55 +01:00
var _pint = _data[7];
var _unis = _data[8];
2022-01-13 05:24:03 +01:00
2022-12-22 03:09:55 +01:00
var seed = _data[10];
2023-01-17 08:11:55 +01:00
2023-02-14 05:32:32 +01:00
var color = _data[11];
2023-01-17 08:11:55 +01:00
var alpha = _data[12];
2023-02-19 02:13:19 +01:00
var mulpA = _data[16];
2023-02-21 04:48:50 +01:00
var useV = _data[17];
2023-03-28 06:58:28 +02:00
var blend = _data[18];
2023-07-21 12:40:20 +02:00
2023-04-16 15:26:52 +02:00
var path = _data[19];
2023-07-21 12:40:20 +02:00
var pathRot = _data[20];
2023-08-12 12:35:35 +02:00
var pathShf = _data[21];
var pathDis = _data[22];
2024-01-12 05:03:35 +01:00
var sortY = _data[23];
2022-01-13 05:24:03 +01:00
var _in_w, _in_h;
2023-02-21 04:48:50 +01:00
var vSca = array_exists(useV, "Scale");
var vRot = array_exists(useV, "Rotation");
var vCol = array_exists(useV, "Color");
2023-02-14 05:32:32 +01:00
var _posDist = [];
2023-12-09 09:00:35 +01:00
if(_dist == NODE_SCATTER_DIST.map) {
if(!is_surface(_distMap))
return _outSurf;
2023-02-23 07:02:19 +01:00
_posDist = get_points_from_dist(_distMap, _amount, seed);
2023-12-09 09:00:35 +01:00
}
2023-11-28 06:50:54 +01:00
if(_dist == 4) {
var path_valid = path != noone && struct_has(path, "getPointRatio");
if(!path_valid) return _outSurf;
var _pathProgress = 0;
var path_amount = struct_has(path, "getLineCount")? path.getLineCount() : 1;
var _pre_amount = _amount;
_amount *= path_amount;
var path_line_index = 0;
}
var _sed = seed;
var _sct = array_create(_amount);
var _sct_len = 0;
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
surface_set_target(_outSurf);
2023-03-19 09:17:39 +01:00
DRAW_CLEAR
2023-03-28 06:58:28 +02:00
switch(blend) {
case 0 :
if(mulpA) BLEND_ALPHA_MULP;
else BLEND_ALPHA;
break;
case 1 :
BLEND_ADD;
break;
}
2023-02-19 02:13:19 +01:00
2024-01-12 05:03:35 +01:00
var positions = array_create(_amount);
var posIndex = 0;
2023-02-14 05:32:32 +01:00
for(var i = 0; i < _amount; i++) {
var sp = noone, _x = 0, _y = 0;
2023-02-21 04:48:50 +01:00
var _v = noone;
2023-11-28 06:50:54 +01:00
if(_dist == NODE_SCATTER_DIST.area || _dist == NODE_SCATTER_DIST.border) {
2023-02-14 05:32:32 +01:00
sp = area_get_random_point(_area, _dist, _scat, i, _amount, _sed); _sed += 20;
_x = sp[0];
_y = sp[1];
2023-12-09 09:00:35 +01:00
} else if(_dist == NODE_SCATTER_DIST.map) {
2023-02-14 05:32:32 +01:00
sp = array_safe_get(_posDist, i);
if(!is_array(sp)) continue;
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
_x = _area[0] + _area[2] * (sp[0] * 2 - 1.);
_y = _area[1] + _area[3] * (sp[1] * 2 - 1.);
2023-12-09 09:00:35 +01:00
} else if(_dist == NODE_SCATTER_DIST.data) {
2023-02-14 05:32:32 +01:00
sp = array_safe_get(_distData, i);
if(!is_array(sp)) continue;
2023-02-19 02:13:19 +01:00
2023-02-21 04:48:50 +01:00
_x = array_safe_get(sp, 0);
_y = array_safe_get(sp, 1);
_v = array_safe_get(sp, 2, noone);
2023-11-28 06:50:54 +01:00
} else if(_dist == NODE_SCATTER_DIST.path) {
_pathProgress = _scat? random_seed(1, _sed) : i / max(1, _pre_amount); _sed++;
_pathProgress = frac((_pathProgress + pathShf) * 0.9999);
var pp = path.getPointRatio(_pathProgress, path_line_index);
_x = pp.x + random_range_seed(-pathDis, pathDis, _sed); _sed++;
_y = pp.y + random_range_seed(-pathDis, pathDis, _sed); _sed++;
} else if(_dist == NODE_SCATTER_DIST.tile) {
2023-04-22 11:34:56 +02:00
_x = random_range_seed(0, _dim[0], _sed); _sed++;
_y = random_range_seed(0, _dim[1], _sed); _sed++;
2023-02-14 05:32:32 +01:00
}
2023-02-21 04:48:50 +01:00
2023-04-16 15:26:52 +02:00
var posS = _dist < 4? seed + _y * _dim[0] + _x : seed + i * 100;
2023-02-21 04:48:50 +01:00
var _scx = random_range_seed(_scale[0], _scale[1], posS); posS++;
var _scy = random_range_seed(_scale[2], _scale[3], posS); posS++;
2023-02-14 05:32:32 +01:00
if(_unis) _scy = _scx;
2023-02-21 04:48:50 +01:00
if(vSca && _v != noone) {
_scx *= _v;
_scy *= _v;
}
2023-11-28 06:50:54 +01:00
var _r = (_pint? point_direction(_area[0], _area[1], _x, _y) : 0) + angle_random_eval(_rota, posS); posS++;
2023-02-21 04:48:50 +01:00
if(vRot && _v != noone)
_r *= _v;
2023-07-21 12:40:20 +02:00
2023-11-28 06:50:54 +01:00
if(_dist == NODE_SCATTER_DIST.path && pathRot) {
var p0 = path.getPointRatio(clamp(_pathProgress - 0.001, 0, 0.9999), path_line_index);
var p1 = path.getPointRatio(clamp(_pathProgress + 0.001, 0, 0.9999), path_line_index);
2023-07-21 12:40:20 +02:00
var dirr = point_direction(p0.x, p0.y, p1.x, p1.y);
_r += dirr;
}
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
var surf = _inSurf;
2023-04-16 15:26:52 +02:00
var ind = 0;
if(is_array(_inSurf)) {
if(array_length(_inSurf) == 0) break;
ind = irandom_seed(array_length(_inSurf) - 1, posS);
surf = _inSurf[ind];
posS++;
}
2023-09-08 21:37:36 +02:00
var sw = surface_get_width_safe(surf);
var sh = surface_get_height_safe(surf);
2022-05-17 14:39:12 +02:00
2023-11-28 06:50:54 +01:00
if(_dist != NODE_SCATTER_DIST.area || _scat != AREA_SCATTER.uniform) {
2023-02-14 05:32:32 +01:00
var p = point_rotate(-sw / 2 * _scx, -sh * _scy / 2, 0, 0, _r);
_x += p[0];
_y += p[1];
}
2023-02-21 04:48:50 +01:00
var grSamp = random_seed(1, posS); posS++;
if(vCol && _v != noone)
grSamp *= _v;
2023-03-02 07:59:14 +01:00
var clr = color.eval(grSamp);
2023-02-21 04:48:50 +01:00
var alp = random_range_seed(alpha[0], alpha[1], posS); posS++;
2023-02-14 05:32:32 +01:00
2023-11-28 06:50:54 +01:00
var _atl = array_safe_get(scatter_data, _sct_len);
if(!is_instanceof(_atl, SurfaceAtlas))
_atl = new SurfaceAtlas(surf, _x, _y, _r, _scx, _scy, clr, alp);
else
_atl.set(surf, _x, _y, _r, _scx, _scy, clr, alp);
_sct[_sct_len] = _atl;
_sct_len++;
2024-01-12 05:03:35 +01:00
if(_dist == NODE_SCATTER_DIST.path)
path_line_index = floor(i / _pre_amount);
}
2024-01-15 13:53:46 +01:00
array_resize(_sct, _sct_len);
2024-01-12 05:03:35 +01:00
if(sortY) array_sort(_sct, function(a1, a2) { return a1.y - a2.y; });
for( var i = 0; i < _sct_len; i++ ) {
var _atl = _sct[i];
surf = _atl.getSurface();
_x = _atl.x;
_y = _atl.y;
_scx = _atl.sx;
_scy = _atl.sy;
_r = _atl.rotation;
clr = _atl.blend;
alp = _atl.alpha;
2023-02-14 05:32:32 +01:00
draw_surface_ext_safe(surf, _x, _y, _scx, _scy, _r, clr, alp);
2023-04-22 11:34:56 +02:00
2024-01-12 05:03:35 +01:00
if(_dist == NODE_SCATTER_DIST.tile) {
2023-09-08 21:37:36 +02:00
var _sw = surface_get_width_safe(surf) * _scx;
var _sh = surface_get_height_safe(surf) * _scy;
2023-04-22 11:34:56 +02:00
2023-11-28 06:50:54 +01:00
if(_x < _sw) draw_surface_ext_safe(surf, _dim[0] + _x, _y, _scx, _scy, _r, clr, alp);
if(_y < _sh) draw_surface_ext_safe(surf, _x, _dim[1] + _y, _scx, _scy, _r, clr, alp);
if(_x < _sw && _y < _sh) draw_surface_ext_safe(surf, _dim[0] + _x, _dim[1] + _y, _scx, _scy, _r, clr, alp);
2023-04-22 11:34:56 +02:00
2023-11-28 06:50:54 +01:00
if(_x > _dim[0] - _sw) draw_surface_ext_safe(surf, _x - _dim[0], _y, _scx, _scy, _r, clr, alp);
if(_y > _dim[1] - _sh) draw_surface_ext_safe(surf, _x, _y - _dim[1], _scx, _scy, _r, clr, alp);
if(_x > _dim[0] - _sw || _y > _dim[1] - _sh) draw_surface_ext_safe(surf, _x - _dim[0], _y - _dim[1], _scx, _scy, _r, clr, alp);
2023-04-22 11:34:56 +02:00
}
2023-02-14 05:32:32 +01:00
}
2024-01-12 05:03:35 +01:00
2023-02-14 05:32:32 +01:00
BLEND_NORMAL;
2022-12-27 04:00:50 +01:00
surface_reset_target();
2022-12-22 03:09:55 +01:00
2023-11-28 06:50:54 +01:00
scatter_data = _sct;
2022-12-22 03:09:55 +01:00
return _outSurf;
2023-11-03 14:43:28 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2023-11-03 14:43:28 +01:00
static doApplyDeserialize = function() { #region
2023-10-02 08:57:44 +02:00
var _arr = getInputData(15);
2023-02-21 04:48:50 +01:00
inputs[| 0].array_depth = _arr;
2023-02-14 05:32:32 +01:00
doUpdate();
2023-11-03 14:43:28 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
}