Pixel-Composer/scripts/node_mesh_warp/node_mesh_warp.gml

828 lines
23 KiB
Text
Raw Normal View History

2023-02-28 09:43:01 +01:00
function Node_Mesh_Warp(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor {
2023-01-25 06:49:00 +01:00
name = "Mesh Warp";
2022-01-13 05:24:03 +01:00
2023-07-31 11:47:18 +02:00
attributes.mesh_bound = [];
points = [];
2024-01-28 09:53:41 +01:00
data = { points : [], tris : [], links : [], controls: [] };
function _Point(node, index, _x, _y) constructor { #region
self.index = index;
2024-02-03 13:11:50 +01:00
self.node = node;
2024-01-28 09:53:41 +01:00
x = _x;
y = _y;
xp = x;
yp = y;
node.points[index] = self;
ndx = 0;
ndy = 0;
sx = x;
sy = y;
pin = false;
controlWeights = [];
static reset = function(data) {
INLINE
x = sx;
y = sy;
xp = x;
yp = y;
var dist = 0;
for( var i = 0, n = array_length(data.controls); i < n; i++ ) {
var d = point_distance(x, y, data.controls[i][PUPPET_CONTROL.cx], data.controls[i][PUPPET_CONTROL.cy]);
controlWeights[i] = 1 / d;
dist += 1 / d;
}
for( var i = 0, n = array_length(controlWeights); i < n; i++ )
controlWeights[i] /= dist;
}
static draw = function(_x, _y, _s) {
INLINE
if(pin) {
draw_set_color(COLORS._main_accent);
draw_circle_prec(_x + x * _s, _y + y * _s, 3, false);
} else {
draw_set_color(COLORS.node_overlay_gizmo_inactive);
draw_circle_prec(_x + x * _s, _y + y * _s, 2, false);
}
}
u = 0;
v = 0;
static mapTexture = function(ww, hh) {
INLINE
u = x / ww;
v = y / hh;
}
static move = function(dx, dy) {
INLINE
if(pin) return;
x += dx;
y += dy;
}
static planMove = function(dx, dy) {
INLINE
if(pin) return;
ndx += dx;
ndy += dy;
}
static stepMove = function(rat) {
INLINE
if(pin) return;
move(ndx * rat, ndy * rat);
}
static clearMove = function(rat) {
INLINE
if(pin) return;
ndx = 0;
ndy = 0;
}
static setPin = function(pin) {
INLINE
self.pin = pin;
}
static equal = function(point) {
INLINE
return x == point.x && y == point.y;
}
} #endregion
function _Link(_p0, _p1, _k = 1) constructor { #region
p0 = _p0;
p1 = _p1;
k = _k;
len = point_distance(p0.x, p0.y, p1.x, p1.y);
static resolve = function(strength = 1) {
INLINE
var _len = point_distance(p0.x, p0.y, p1.x, p1.y);
var _dir = point_direction(p0.x, p0.y, p1.x, p1.y);
var _slen = lerp(_len, len, strength);
var f = k * (_len - _slen);
var dx = lengthdir_x(f, _dir);
var dy = lengthdir_y(f, _dir);
p0.move( dx / 2, dy / 2);
p1.move(-dx / 2, -dy / 2);
}
static draw = function(_x, _y, _s) {
INLINE
draw_set_color(c_red);
draw_line(_x + p0.x * _s, _y + p0.y * _s, _x + p1.x * _s, _y + p1.y * _s);
}
} #endregion
function _Triangle(_p0, _p1, _p2) constructor { #region
p0 = _p0;
p1 = _p1;
p2 = _p2;
static reset = function(data) {
INLINE
p0.reset(data);
p1.reset(data);
p2.reset(data);
}
static initSurface = function(surf) {
INLINE
p0.mapTexture(surface_get_width_safe(surf), surface_get_height_safe(surf));
p1.mapTexture(surface_get_width_safe(surf), surface_get_height_safe(surf));
p2.mapTexture(surface_get_width_safe(surf), surface_get_height_safe(surf));
}
static drawSurface = function(surf) {
INLINE
draw_set_color(c_white);
draw_set_alpha(1);
draw_primitive_begin_texture(pr_trianglelist, surface_get_texture(surf));
draw_vertex_texture(p0.x, p0.y, p0.u, p0.v);
draw_vertex_texture(p1.x, p1.y, p1.u, p1.v);
draw_vertex_texture(p2.x, p2.y, p2.u, p2.v);
draw_primitive_end();
}
static drawPoints = function(_x, _y, _s) {
INLINE
p0.draw(_x, _y, _s);
p1.draw(_x, _y, _s);
p2.draw(_x, _y, _s);
}
static contain = function(p) {
INLINE
return p == p0 || p == p1 || p == p2;
}
} #endregion
2022-01-13 05:24:03 +01:00
2024-01-27 14:36:36 +01:00
is_convex = true;
hover = -1;
2023-07-31 11:47:18 +02:00
anchor_dragging = -1;
anchor_drag_sx = -1;
anchor_drag_sy = -1;
anchor_drag_mx = -1;
anchor_drag_my = -1;
2024-03-14 14:35:19 +01:00
inputs[| 0] = nodeValue("Surface in", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
2023-02-14 05:32:32 +01:00
inputs[| 1] = nodeValue("Sample", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 8, "Amount of grid subdivision. Higher number means more grid, detail.")
2024-03-24 04:58:08 +01:00
.setDisplay(VALUE_DISPLAY.slider, { range: [ 2, 32, 0.1 ] });
2022-01-13 05:24:03 +01:00
2023-05-22 20:31:55 +02:00
inputs[| 2] = nodeValue("Spring Force", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.5)
.setDisplay(VALUE_DISPLAY.slider);
2022-01-13 05:24:03 +01:00
2024-04-08 07:13:46 +02:00
inputs[| 3] = nodeValue("Mesh", self, JUNCTION_CONNECT.input, VALUE_TYPE.trigger, false )
.setDisplay(VALUE_DISPLAY.button, { name: "Generate", UI : true, onClick: function() { Mesh_setTriangle(); } });
2022-01-13 05:24:03 +01:00
2023-05-22 20:31:55 +02:00
inputs[| 4] = nodeValue("Diagonal Link", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false, "Include diagonal link to prevent drastic grid deformation.");
2022-09-23 13:28:42 +02:00
2023-02-14 05:32:32 +01:00
inputs[| 5] = nodeValue("Active", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
active_index = 5;
2023-03-26 07:13:36 +02:00
2023-05-22 20:31:55 +02:00
inputs[| 6] = nodeValue("Link Strength", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0, "Link length preservation, setting it to 1 will prevent any stretching, contraction.")
.setDisplay(VALUE_DISPLAY.slider);
2023-02-14 05:32:32 +01:00
2023-05-22 20:31:55 +02:00
inputs[| 7] = nodeValue("Full Mesh", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
2023-07-31 11:47:18 +02:00
inputs[| 8] = nodeValue("Mesh Type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
2024-01-28 09:53:41 +01:00
.setDisplay(VALUE_DISPLAY.enum_scroll, [ new scrollItem("Grid", s_node_mesh_type, 0),
new scrollItem("Custom", s_node_mesh_type, 1), ] );
2023-07-31 11:47:18 +02:00
inputs[| 9] = nodeValue("Seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, seed_random(6))
2024-06-08 06:31:21 +02:00
.setDisplay(VALUE_DISPLAY._default, { side_button : button(function() { randomize(); inputs[| 9].setValue(seed_random(6)); }).setIcon(THEME.icon_random, 0, COLORS._main_icon) });
2023-05-22 20:31:55 +02:00
2024-02-03 13:11:50 +01:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
outputs[| 1] = nodeValue("Mesh data", self, JUNCTION_CONNECT.output, VALUE_TYPE.object, data);
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
input_display_list = [ 5,
2023-07-31 11:47:18 +02:00
["Mesh", false], 0, 8, 9, 1, 7, 3,
2023-03-26 07:13:36 +02:00
["Link", false], 4, 6,
2022-09-23 13:28:42 +02:00
["Control points", false],
];
2024-02-03 13:11:50 +01:00
control_index = ds_list_size(inputs);
function createControl() { #region
var index = ds_list_size(inputs);
inputs[| index] = nodeValue("Control point", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ PUPPET_FORCE_MODE.move, 16, 16, 8, 0, 8, 8 ])
.setDisplay(VALUE_DISPLAY.puppet_control)
array_push(input_display_list, index);
return inputs[| index];
} #endregion
2023-03-19 09:17:39 +01:00
attribute_surface_depth();
2023-03-21 03:01:53 +01:00
attribute_interpolation();
2023-03-19 09:17:39 +01:00
2022-09-23 13:28:42 +02:00
input_display_index = array_length(input_display_list);
2024-01-28 09:53:41 +01:00
#region ============ attributes & tools ============
array_push(attributeEditors, "Warp");
2023-06-04 12:38:40 +02:00
2024-01-28 09:53:41 +01:00
attributes.iteration = 4;
array_push(attributeEditors, ["Iteration", function() { return attributes.iteration; },
new textBox(TEXTBOX_INPUT.number, function(val) {
attributes.iteration = val;
triggerRender();
})]);
2023-03-19 09:17:39 +01:00
2024-01-28 09:53:41 +01:00
tools = [];
2023-07-31 11:47:18 +02:00
2024-01-28 09:53:41 +01:00
tools_edit = [
new NodeTool( "Edit control point", THEME.control_add ),
new NodeTool( "Pin mesh", THEME.control_pin ),
];
2023-07-31 11:47:18 +02:00
2024-01-28 09:53:41 +01:00
tools_mesh = [
tools_edit[0],
tools_edit[1],
2024-02-03 13:11:50 +01:00
new NodeTool( "Mesh edit", THEME.mesh_tool_edit ),
new NodeTool( "Mesh anchor remove", THEME.mesh_tool_delete ),
2024-01-28 09:53:41 +01:00
];
#endregion
2022-01-13 05:24:03 +01:00
2024-02-03 13:11:50 +01:00
insp1UpdateTooltip = "Generate";
2024-03-31 05:36:11 +02:00
insp1UpdateIcon = [ THEME.refresh_icon, 1, COLORS._main_value_positive ];
2024-02-03 13:11:50 +01:00
will_triangluate = false;
2023-06-04 12:38:40 +02:00
2023-11-30 03:18:25 +01:00
static onInspector1Update = function() { #region
2024-01-28 09:53:41 +01:00
Mesh_setTriangle();
2023-11-30 03:18:25 +01:00
} #endregion
2023-06-04 12:38:40 +02:00
2023-11-30 03:18:25 +01:00
static onValueFromUpdate = function(index) { #region
if(LOADING || APPENDING) return;
2023-03-28 06:58:28 +02:00
if(index == 0 && array_empty(data.tris))
2024-01-28 09:53:41 +01:00
Mesh_setTriangle();
2023-11-30 03:18:25 +01:00
} #endregion
2023-01-09 03:14:20 +01:00
2024-03-14 14:35:19 +01:00
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
2023-07-31 11:47:18 +02:00
var mx = (_mx - _x) / _s;
var my = (_my - _y) / _s;
var _type = getInputData(8);
2024-02-03 13:11:50 +01:00
if(_type == 1 && (isUsingTool("Mesh edit") || isUsingTool("Mesh anchor remove"))) {
2023-07-31 11:47:18 +02:00
var mesh = attributes.mesh_bound;
var len = array_length(mesh);
var _hover = -0.5, _side = 0;
draw_set_color(is_convex? COLORS._main_accent : COLORS._main_value_negative);
is_convex = true;
for( var i = 0; i < len; i++ ) {
var _px0 = mesh[safe_mod(i + 0, len)][0];
var _py0 = mesh[safe_mod(i + 0, len)][1];
var _px1 = mesh[safe_mod(i + 1, len)][0];
var _py1 = mesh[safe_mod(i + 1, len)][1];
var _px2 = mesh[safe_mod(i + 2, len)][0];
var _py2 = mesh[safe_mod(i + 2, len)][1];
var side = cross_product(_px0, _py0, _px1, _py1, _px2, _py2);
if(_side != 0 && sign(_side) != sign(side))
is_convex = false;
_side = side;
var _dx0 = _x + _px0 * _s;
var _dy0 = _y + _py0 * _s;
var _dx1 = _x + _px1 * _s;
var _dy1 = _y + _py1 * _s;
draw_line_width(_dx0, _dy0, _dx1, _dy1, hover == i + 0.5? 4 : 2);
if(isUsingTool("Mesh edit") && distance_to_line(_mx, _my, _dx0, _dy0, _dx1, _dy1) < 6)
_hover = i + 0.5;
}
draw_set_color(COLORS._main_accent);
for( var i = 0; i < len; i++ ) {
var _px = mesh[i][0];
var _py = mesh[i][1];
var _dx = _x + _px * _s;
var _dy = _y + _py * _s;
draw_circle_prec(_dx, _dy, hover == i? 6 : 4, false);
2024-02-03 13:11:50 +01:00
if((isUsingTool("Mesh edit") || isUsingTool("Mesh anchor remove")) && point_distance(_dx, _dy, _mx, _my) < 6)
2023-07-31 11:47:18 +02:00
_hover = i;
}
hover = _hover;
if(anchor_dragging > -1) {
var dx = anchor_drag_sx + (_mx - anchor_drag_mx) / _s;
var dy = anchor_drag_sy + (_my - anchor_drag_my) / _s;
dx = value_snap(dx, _snx);
dy = value_snap(dy, _sny);
attributes.mesh_bound[anchor_dragging][0] = dx;
attributes.mesh_bound[anchor_dragging][1] = dy;
2024-01-28 09:53:41 +01:00
Mesh_setTriangle();
2023-07-31 11:47:18 +02:00
if(mouse_release(mb_left))
anchor_dragging = -1;
}
if(mouse_press(mb_left, active)) {
if(frac(hover) == 0) {
if(isUsingTool("Mesh edit")) {
anchor_dragging = hover;
anchor_drag_sx = mesh[hover][0];
anchor_drag_sy = mesh[hover][1];
anchor_drag_mx = _mx;
anchor_drag_my = _my;
2024-02-03 13:11:50 +01:00
} else if(isUsingTool("Mesh anchor remove")) {
2023-07-31 11:47:18 +02:00
if(array_length(mesh) > 3) {
array_delete(mesh, hover, 1);
2024-01-28 09:53:41 +01:00
Mesh_setTriangle();
2023-07-31 11:47:18 +02:00
}
}
} else if(isUsingTool("Mesh edit")) {
var ind = hover == -0.5? len : ceil(hover);
array_insert(attributes.mesh_bound, ind, [ mx, my ]);
anchor_dragging = ind;
anchor_drag_sx = mx;
anchor_drag_sy = my;
anchor_drag_mx = _mx;
anchor_drag_my = _my;
}
}
}
2023-03-26 07:13:36 +02:00
for(var i = 0; i < array_length(data.links); i++)
data.links[i].draw(_x, _y, _s);
for(var i = 0; i < array_length(data.tris); i++)
data.tris[i].drawPoints(_x, _y, _s);
2022-01-13 05:24:03 +01:00
2023-07-31 11:47:18 +02:00
var _hover = -1;
2022-01-13 05:24:03 +01:00
for(var i = control_index; i < ds_list_size(inputs); i++) {
2024-03-14 14:35:19 +01:00
if(inputs[| i].drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny))
2023-07-31 11:47:18 +02:00
_hover = i;
2022-01-13 05:24:03 +01:00
}
2023-07-31 11:47:18 +02:00
if(isUsingTool("Edit control point")) {
2023-02-14 05:32:32 +01:00
if(key_mod_press(SHIFT))
draw_sprite_ui_uniform(THEME.cursor_path_remove, 0, _mx + 16, _my + 16);
else
draw_sprite_ui_uniform(THEME.cursor_path_add, 0, _mx + 16, _my + 16);
2023-07-31 11:47:18 +02:00
if(mouse_press(mb_left, active)) {
if(_hover == -1) {
2022-01-13 05:24:03 +01:00
var i = createControl();
2023-03-28 06:58:28 +02:00
i.setValue( [ PUPPET_FORCE_MODE.move, value_snap(_mx - _x, _snx) / _s, value_snap(_my - _y, _sny) / _s, 0, 0, 8, 8 ] );
2022-01-13 05:24:03 +01:00
i.drag_type = 2;
i.drag_sx = 0;
i.drag_sy = 0;
i.drag_mx = _mx;
i.drag_my = _my;
2023-02-14 05:32:32 +01:00
} else if(key_mod_press(SHIFT)) {
2023-07-31 11:47:18 +02:00
ds_list_delete(inputs, _hover);
array_delete(input_display_list, input_display_index + _hover - control_index, 1);
2022-01-13 05:24:03 +01:00
}
reset();
2022-09-23 13:28:42 +02:00
control(input_display_list);
}
2023-07-31 11:47:18 +02:00
} else if(isUsingTool("Pin mesh")) {
2023-02-14 05:32:32 +01:00
draw_sprite_ui_uniform(key_mod_press(SHIFT)? THEME.cursor_path_remove : THEME.cursor_path_add, 0, _mx + 16, _my + 16);
2022-11-18 03:20:31 +01:00
draw_set_color(COLORS._main_accent);
2022-09-23 13:28:42 +02:00
var rad = 16;
2023-06-17 14:30:49 +02:00
draw_circle_prec(_mx, _my, rad, true);
2022-09-23 13:28:42 +02:00
var _xx = (_mx - _x) / _s;
var _yy = (_my - _y) / _s;
2023-07-31 11:47:18 +02:00
if(mouse_click(mb_left, active)) {
2023-03-26 07:13:36 +02:00
for(var j = 0; j < array_length(data.tris); j++) {
var t = data.tris[j];
2022-09-23 13:28:42 +02:00
if(point_in_circle(t.p0.x, t.p0.y, _xx, _yy, rad / _s))
2023-02-14 05:32:32 +01:00
t.p0.setPin(!key_mod_press(SHIFT));
2022-09-23 13:28:42 +02:00
if(point_in_circle(t.p1.x, t.p1.y, _xx, _yy, rad / _s))
2023-02-14 05:32:32 +01:00
t.p1.setPin(!key_mod_press(SHIFT));
2022-09-23 13:28:42 +02:00
if(point_in_circle(t.p2.x, t.p2.y, _xx, _yy, rad / _s))
2023-02-14 05:32:32 +01:00
t.p2.setPin(!key_mod_press(SHIFT));
2022-09-23 13:28:42 +02:00
}
2022-01-13 05:24:03 +01:00
}
2023-07-31 11:47:18 +02:00
}
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
static step = function() { #region
var _type = getInputData(8);
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
inputs[| 2].setVisible(_type == 0);
inputs[| 4].setVisible(_type == 0);
inputs[| 7].setVisible(_type == 0);
2022-01-29 14:25:18 +01:00
2024-01-28 09:53:41 +01:00
if(_type == 0) tools = tools_edit;
else if (_type == 1) tools = tools_mesh;
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
static reset = function() { #region
for(var i = 0; i < array_length(data.tris); i++)
data.tris[i].reset(data);
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2024-02-03 13:11:50 +01:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2024-01-28 09:53:41 +01:00
static Mesh_regularTri = function(surf) { #region
2024-03-31 05:36:11 +02:00
if(is_array(surf)) surf = array_safe_get_fast(surf, 0);
2022-01-13 05:24:03 +01:00
2024-01-27 14:36:36 +01:00
if(!is_surface(surf)) return;
2022-01-13 05:24:03 +01:00
if(!inputs[| 0].value_from) return;
2024-01-27 14:36:36 +01:00
var sample = getInputData(1);
var spring = getInputData(2);
var diagon = getInputData(4);
var fullmh = getInputData(7);
2024-01-27 14:36:36 +01:00
var ww = surface_get_width_safe(surf);
var hh = surface_get_height_safe(surf);
2023-06-17 14:30:49 +02:00
2024-01-28 09:53:41 +01:00
var gw = ww / sample;
var gh = hh / sample;
2023-06-04 12:38:40 +02:00
var cont = noone;
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
if(!fullmh) { #region alpha filter
2023-06-04 12:38:40 +02:00
cont = surface_create_valid(ww, hh);
2023-01-25 06:49:00 +01:00
2022-12-22 03:09:55 +01:00
surface_set_target(cont);
shader_set(sh_content_sampler);
var uniform_dim = shader_get_uniform(sh_content_sampler, "dimension");
var uniform_sam = shader_get_uniform(sh_content_sampler, "sampler");
2022-09-21 06:09:40 +02:00
2023-02-14 05:32:32 +01:00
shader_set_uniform_f_array_safe(uniform_dim, [ww, hh]);
shader_set_uniform_f_array_safe(uniform_sam, [gw, gh]);
2022-12-22 03:09:55 +01:00
draw_surface_safe(surf, 0, 0);
shader_reset();
surface_reset_target();
2024-01-28 09:53:41 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2023-07-31 11:47:18 +02:00
var _sam = sample + 1;
data.points = array_create(_sam * _sam);
2022-01-13 05:24:03 +01:00
2022-09-23 13:28:42 +02:00
var ind = 0;
2023-07-31 11:47:18 +02:00
for(var i = 0; i < _sam; i++)
2024-01-28 09:53:41 +01:00
for(var j = 0; j < _sam; j++) { #region mesh
2022-12-22 03:09:55 +01:00
var fill = false;
2024-01-28 09:53:41 +01:00
2023-05-22 20:31:55 +02:00
if(fullmh) {
2022-12-22 03:09:55 +01:00
fill = true;
} else {
2023-05-22 20:31:55 +02:00
var _i = i * gh;
var _j = j * gw;
fill |= surface_get_pixel(cont, _j - 1, _i - 1);
fill |= surface_get_pixel(cont, _j - 1, _i);
fill |= surface_get_pixel(cont, _j - 1, _i + 1);
fill |= surface_get_pixel(cont, _j, _i - 1);
fill |= surface_get_pixel(cont, _j, _i);
fill |= surface_get_pixel(cont, _j, _i + 1);
fill |= surface_get_pixel(cont, _j + 1, _i - 1);
fill |= surface_get_pixel(cont, _j + 1, _i);
fill |= surface_get_pixel(cont, _j + 1, _i + 1);
2022-12-22 03:09:55 +01:00
}
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
if(!fill) continue;
var px = min(j * gw, ww);
var py = min(i * gh, hh);
data.points[i * _sam + j] = new _Point(self, ind++, px, py);
if(i == 0) continue;
2022-12-10 05:06:01 +01:00
2024-01-28 09:53:41 +01:00
if(j && data.points[(i - 1) * _sam + j] != 0 && data.points[i * _sam + j - 1] != 0)
array_push(data.tris, new _Triangle(data.points[(i - 1) * _sam + j], data.points[i * _sam + j - 1], data.points[i * _sam + j]));
if(j < sample && data.points[(i - 1) * _sam + j] != 0 && data.points[(i - 1) * _sam + j + 1] != 0)
array_push(data.tris, new _Triangle(data.points[(i - 1) * _sam + j], data.points[(i - 1) * _sam + j + 1], data.points[i * _sam + j]));
} #endregion
2022-01-13 05:24:03 +01:00
2023-07-31 11:47:18 +02:00
for(var i = 0; i < _sam; i++)
2024-01-28 09:53:41 +01:00
for(var j = 0; j < _sam; j++) { #region diagonal
var p0 = i && j? data.points[ (i - 1) * _sam + j - 1 ] : 0;
var p1 = i? data.points[ (i - 1) * _sam + j ] : 0;
var p2 = j? data.points[ (i ) * _sam + j - 1 ] : 0;
var p3 = data.points[ (i ) * _sam + j ];
if(p3 && p1) array_push(data.links, new _Link(p3, p1));
if(p3 && p2) array_push(data.links, new _Link(p3, p2));
var d0 = p0 && p3;
var d1 = p1 && p2;
if(diagon || d0 ^ d1) {
if(d0) array_push(data.links, new _Link(p0, p3, spring));
if(d1) array_push(data.links, new _Link(p1, p2, spring));
2022-01-13 05:24:03 +01:00
}
2024-01-28 09:53:41 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2023-06-04 12:38:40 +02:00
if(is_surface(cont)) surface_free(cont);
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
static Mesh_triangulate = function(surf) { #region
var sample = getInputData(1);
var seed = getInputData(9);
2023-07-31 11:47:18 +02:00
if(!inputs[| 0].value_from) return;
2024-02-03 13:11:50 +01:00
if(is_array(surf)) surf = surf[0];
var ww = surface_get_width_safe(surf);
var hh = surface_get_height_safe(surf);
2023-07-31 11:47:18 +02:00
var _m = attributes.mesh_bound;
if(array_length(_m) < 3) return;
var _mb = array_length(_m);
var ind = 0;
var minX, maxX, minY, maxY;
for (var i = 0; i < array_length(_m); i++) {
var point = _m[i];
var _x = point[0];
var _y = point[1];
if (i == 0) {
minX = _x; maxX = _x;
minY = _y; maxY = _y;
} else {
minX = min(minX, _x);
maxX = max(maxX, _x);
minY = min(minY, _y);
maxY = max(maxY, _y);
}
}
var gw = ww / sample / 3;
var gh = hh / sample / 3;
random_set_seed(seed);
var _p = [];
for( var i = 0; i <= sample; i++ )
for( var j = 0; j <= sample; j++ ) {
var px = lerp(minX, maxX, i / sample);
var py = lerp(minY, maxY, j / sample);
px += random_range(-gw, gw);
py += random_range(-gh, gh);
if(point_in_polygon(px, py, _m))
array_push(_p, [ px, py ]);
}
data.points = array_create(_mb + array_length(_p));
for( var i = 0, n = _mb; i < n; i++ )
data.points[i] = new _Point(self, ind++, _m[i][0], _m[i][1]);
for( var i = 0, n = array_length(_p); i < n; i++ )
data.points[_mb + i] = new _Point(self, ind++, _p[i][0], _p[i][1]);
var _t = delaunay_triangulation(data.points);
for( var i = 0, n = array_length(_t); i < n; i++ ) {
var t = _t[i];
array_push(data.tris, new _Triangle(t[0], t[1], t[2]));
2024-01-28 09:53:41 +01:00
array_push(data.links, new _Link(t[0], t[1]));
array_push(data.links, new _Link(t[1], t[2]));
array_push(data.links, new _Link(t[2], t[0]));
2023-07-31 11:47:18 +02:00
}
2023-11-30 03:18:25 +01:00
} #endregion
2023-07-31 11:47:18 +02:00
2024-01-28 09:53:41 +01:00
static Mesh_setTriangle = function() { #region
var _inSurf = getInputData(0);
var _type = getInputData(8);
2023-07-31 11:47:18 +02:00
2024-01-28 09:53:41 +01:00
points = [];
data = { points : [], tris : [], links : [], controls: [] };
2023-07-31 11:47:18 +02:00
switch(_type) {
2024-01-28 09:53:41 +01:00
case 0 : Mesh_regularTri(_inSurf); break;
case 1 : Mesh_triangulate(_inSurf); break;
2023-07-31 11:47:18 +02:00
}
2023-01-25 06:49:00 +01:00
2023-03-26 07:13:36 +02:00
for(var i = 0; i < array_length(data.tris); i++)
data.tris[i].initSurface(is_array(_inSurf)? _inSurf[0] : _inSurf);
2024-02-03 13:11:50 +01:00
triggerRender();
2024-02-15 14:23:26 +01:00
if(loadPin != noone) {
for( var i = 0, n = array_length(loadPin); i < n; i++ ) {
var ind = loadPin[i];
if(ind < array_length(points))
points[ind].pin = true;
}
loadPin = noone;
}
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
static Control_affectPoint = function(c, p) { #region
2022-09-23 13:28:42 +02:00
var mode = c[PUPPET_CONTROL.mode];
var cx = c[PUPPET_CONTROL.cx];
var cy = c[PUPPET_CONTROL.cy];
var fx = c[PUPPET_CONTROL.fx];
var fy = c[PUPPET_CONTROL.fy];
var cw = c[PUPPET_CONTROL.width];
var ch = c[PUPPET_CONTROL.height];
switch(mode) {
case PUPPET_FORCE_MODE.move:
var dis = point_distance(cx, cy, p.x, p.y);
var inf = clamp(1 - dis / cw, 0, 1);
inf = ease_cubic_inout(inf);
p.planMove(fx * inf, fy * inf);
break;
case PUPPET_FORCE_MODE.wind:
var lx0 = cx + lengthdir_x(1000, fy);
var ly0 = cy + lengthdir_y(1000, fy);
var lx1 = cx - lengthdir_x(1000, fy);
var ly1 = cy - lengthdir_y(1000, fy);
var dist = distance_to_line(p.x, p.y, lx0, ly0, lx1, ly1);
var inf = clamp(1 - dist / cw, 0, 1);
inf = ease_cubic_inout(inf);
p.planMove(lengthdir_x(fx * inf, fy), lengthdir_y(fx * inf, fy));
break;
}
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2023-11-30 03:18:25 +01:00
static control = function() { #region
var lStr = getInputData(6);
2023-03-26 07:13:36 +02:00
2024-01-28 09:53:41 +01:00
for(var i = control_index, n = ds_list_size(inputs); i < n; i++) {
var c = getInputData(i);
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
for( var j = 0, m = array_length(data.points); j < m; j++ ) {
2023-07-31 11:47:18 +02:00
if(data.points[j] == 0) continue;
2024-01-28 09:53:41 +01:00
Control_affectPoint(c, data.points[j]);
}
}
for( var i = 0, n = array_length(data.points); i < n; i++ ) {
var _p = data.points[i]; if(_p == 0) continue;
var _dx = 0;
var _dy = 0;
for( var j = 0, m = array_length(data.controls); j < m; j++ ) {
var _c = data.controls[j];
_dx += _c[PUPPET_CONTROL.fx] * _p.controlWeights[j];
_dy += _c[PUPPET_CONTROL.fy] * _p.controlWeights[j];
2022-01-13 05:24:03 +01:00
}
2024-01-28 09:53:41 +01:00
_p.planMove(_dx, _dy);
2022-01-13 05:24:03 +01:00
}
2023-06-13 14:42:06 +02:00
var it = attributes.iteration;
2023-03-26 07:13:36 +02:00
var _rat = 1 / it;
2022-09-23 13:28:42 +02:00
repeat(it) {
2023-07-31 11:47:18 +02:00
for( var j = 0; j < array_length(data.points); j++ ) {
if(data.points[j] == 0) continue;
data.points[j].stepMove(_rat);
2022-09-23 13:28:42 +02:00
}
2023-03-26 07:13:36 +02:00
if(lStr > 0)
repeat(it) {
for(var i = 0; i < array_length(data.links); i++)
data.links[i].resolve(lStr);
2022-09-23 13:28:42 +02:00
}
}
2023-07-31 11:47:18 +02:00
for( var j = 0; j < array_length(data.points); j++ ) {
if(data.points[j] == 0) continue;
data.points[j].clearMove();
2022-09-23 13:28:42 +02:00
}
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2023-11-30 03:18:25 +01:00
static processData = function(_outSurf, _data, _output_index, _array_index) { #region
2024-02-03 13:11:50 +01:00
if(will_triangluate) {
Mesh_setTriangle();
will_triangluate = false;
}
2024-01-27 14:36:36 +01:00
var _inSurf = _data[0];
2023-01-09 03:14:20 +01:00
if(!is_surface(_inSurf)) return _outSurf;
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
data.controls = [];
for(var i = control_index; i < ds_list_size(inputs); i++) {
var c = getInputData(i);
if(c[0] == PUPPET_FORCE_MODE.puppet)
array_push(data.controls, c);
}
2022-01-13 05:24:03 +01:00
reset();
control();
2024-01-27 14:36:36 +01:00
var _sw = surface_get_width_safe(_inSurf);
var _sh = surface_get_height_safe(_inSurf);
_outSurf = surface_verify(_outSurf, _sw, _sh, attrDepth());
2023-01-09 03:14:20 +01:00
2023-03-21 03:01:53 +01:00
surface_set_shader(_outSurf);
shader_set_interpolation(_outSurf);
2023-05-16 21:28:16 +02:00
2024-01-27 14:36:36 +01:00
if(array_length(data.tris) == 0) {
draw_surface_safe(_inSurf);
} else {
for(var i = 0; i < array_length(data.tris); i++)
data.tris[i].drawSurface(_inSurf);
}
2023-05-16 21:28:16 +02:00
2023-03-21 03:01:53 +01:00
surface_reset_shader();
2022-12-22 03:09:55 +01:00
return _outSurf;
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
2024-01-28 09:53:41 +01:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2023-11-30 03:18:25 +01:00
static postDeserialize = function() { #region
2023-06-13 14:42:06 +02:00
var _inputs = load_map.inputs;
2022-01-13 05:24:03 +01:00
2023-06-13 14:42:06 +02:00
for(var i = control_index; i < array_length(_inputs); i++) {
2023-03-28 06:58:28 +02:00
var inp = createControl();
2023-06-13 14:42:06 +02:00
inp.applyDeserialize(_inputs[i]);
2022-01-13 05:24:03 +01:00
}
2023-11-30 03:18:25 +01:00
} #endregion
2022-09-23 13:28:42 +02:00
2023-11-30 03:18:25 +01:00
static attributeSerialize = function() { #region
2023-06-13 14:42:06 +02:00
var att = {};
2024-04-30 05:57:34 +02:00
struct_append(att, attributes);
2023-03-28 06:58:28 +02:00
2023-06-13 14:42:06 +02:00
var pinList = [];
2023-07-31 11:47:18 +02:00
for( var j = 0; j < array_length(data.points); j++ ) {
var p = data.points[j];
2023-03-28 06:58:28 +02:00
if(p == 0) continue;
2023-06-13 14:42:06 +02:00
if(p.pin) array_push(pinList, p.index);
2023-03-28 06:58:28 +02:00
}
2024-02-03 13:11:50 +01:00
2023-06-13 14:42:06 +02:00
att.pin = pinList;
2023-07-31 11:47:18 +02:00
att.mesh_bound = attributes.mesh_bound;
2022-09-23 13:28:42 +02:00
return att;
2023-11-30 03:18:25 +01:00
} #endregion
2022-09-23 13:28:42 +02:00
2023-03-28 06:58:28 +02:00
loadPin = noone;
2023-11-30 03:18:25 +01:00
static attributeDeserialize = function(attr) { #region
2024-04-30 05:57:34 +02:00
struct_append(attributes, attr);
2023-07-31 11:47:18 +02:00
if(struct_has(attr, "pin")) loadPin = attr.pin;
if(struct_has(attr, "mesh_bound")) attributes.mesh_bound = attr.mesh_bound;;
2023-11-30 03:18:25 +01:00
} #endregion
2023-03-28 06:58:28 +02:00
2023-11-30 03:18:25 +01:00
static postLoad = function() { #region
2024-02-03 13:11:50 +01:00
will_triangluate = true;
2023-11-30 03:18:25 +01:00
} #endregion
2022-01-13 05:24:03 +01:00
}