Path improvements

This commit is contained in:
Tanasart 2024-01-23 17:01:19 +07:00
parent 15a90fad61
commit c1eca6817f
26 changed files with 830 additions and 277 deletions

View file

@ -416,6 +416,7 @@
{"name":"s_node_rigidSim_object","order":3,"path":"sprites/s_node_rigidSim_object/s_node_rigidSim_object.yy",}, {"name":"s_node_rigidSim_object","order":3,"path":"sprites/s_node_rigidSim_object/s_node_rigidSim_object.yy",},
{"name":"sh_blend_max","order":8,"path":"shaders/sh_blend_max/sh_blend_max.yy",}, {"name":"sh_blend_max","order":8,"path":"shaders/sh_blend_max/sh_blend_max.yy",},
{"name":"s_node_color_out","order":6,"path":"sprites/s_node_color_out/s_node_color_out.yy",}, {"name":"s_node_color_out","order":6,"path":"sprites/s_node_color_out/s_node_color_out.yy",},
{"name":"pathAnchorBox","order":17,"path":"scripts/pathAnchorBox/pathAnchorBox.yy",},
{"name":"bbmod_lerp_delta_time","order":1,"path":"scripts/bbmod_lerp_delta_time/bbmod_lerp_delta_time.yy",}, {"name":"bbmod_lerp_delta_time","order":1,"path":"scripts/bbmod_lerp_delta_time/bbmod_lerp_delta_time.yy",},
{"name":"__3D","order":8,"path":"scripts/__3D/__3D.yy",}, {"name":"__3D","order":8,"path":"scripts/__3D/__3D.yy",},
{"name":"node_vector_cross2D","order":11,"path":"scripts/node_vector_cross2D/node_vector_cross2D.yy",}, {"name":"node_vector_cross2D","order":11,"path":"scripts/node_vector_cross2D/node_vector_cross2D.yy",},
@ -596,6 +597,7 @@
{"name":"sh_channel_G_grey","order":8,"path":"shaders/sh_channel_G_grey/sh_channel_G_grey.yy",}, {"name":"sh_channel_G_grey","order":8,"path":"shaders/sh_channel_G_grey/sh_channel_G_grey.yy",},
{"name":"display_screenshot","order":4,"path":"extensions/display_screenshot/display_screenshot.yy",}, {"name":"display_screenshot","order":4,"path":"extensions/display_screenshot/display_screenshot.yy",},
{"name":"node_strand_sim_inline","order":12,"path":"scripts/node_strand_sim_inline/node_strand_sim_inline.yy",}, {"name":"node_strand_sim_inline","order":12,"path":"scripts/node_strand_sim_inline/node_strand_sim_inline.yy",},
{"name":"node_path_map","order":17,"path":"scripts/node_path_map/node_path_map.yy",},
{"name":"s_node_smokeSim_update","order":10,"path":"sprites/s_node_smokeSim_update/s_node_smokeSim_update.yy",}, {"name":"s_node_smokeSim_update","order":10,"path":"sprites/s_node_smokeSim_update/s_node_smokeSim_update.yy",},
{"name":"node_3d_depth","order":15,"path":"scripts/node_3d_depth/node_3d_depth.yy",}, {"name":"node_3d_depth","order":15,"path":"scripts/node_3d_depth/node_3d_depth.yy",},
{"name":"s_node_vec4","order":9,"path":"sprites/s_node_vec4/s_node_vec4.yy",}, {"name":"s_node_vec4","order":9,"path":"sprites/s_node_vec4/s_node_vec4.yy",},
@ -1371,6 +1373,7 @@
{"name":"s_node_trigger","order":3,"path":"sprites/s_node_trigger/s_node_trigger.yy",}, {"name":"s_node_trigger","order":3,"path":"sprites/s_node_trigger/s_node_trigger.yy",},
{"name":"fd_rectangle_get_repeat","order":19,"path":"scripts/fd_rectangle_get_repeat/fd_rectangle_get_repeat.yy",}, {"name":"fd_rectangle_get_repeat","order":19,"path":"scripts/fd_rectangle_get_repeat/fd_rectangle_get_repeat.yy",},
{"name":"s_menu_white","order":1,"path":"sprites/s_menu_white/s_menu_white.yy",}, {"name":"s_menu_white","order":1,"path":"sprites/s_menu_white/s_menu_white.yy",},
{"name":"s_node_path_smooth","order":18,"path":"sprites/s_node_path_smooth/s_node_path_smooth.yy",},
{"name":"node_struct_json_parse","order":2,"path":"scripts/node_struct_json_parse/node_struct_json_parse.yy",}, {"name":"node_struct_json_parse","order":2,"path":"scripts/node_struct_json_parse/node_struct_json_parse.yy",},
{"name":"color_loader","order":13,"path":"scripts/color_loader/color_loader.yy",}, {"name":"color_loader","order":13,"path":"scripts/color_loader/color_loader.yy",},
{"name":"node_rigid_override","order":9,"path":"scripts/node_rigid_override/node_rigid_override.yy",}, {"name":"node_rigid_override","order":9,"path":"scripts/node_rigid_override/node_rigid_override.yy",},
@ -1515,6 +1518,7 @@
{"name":"s_node_text_render","order":17,"path":"sprites/s_node_text_render/s_node_text_render.yy",}, {"name":"s_node_text_render","order":17,"path":"sprites/s_node_text_render/s_node_text_render.yy",},
{"name":"__init_global","order":8,"path":"scripts/__init_global/__init_global.yy",}, {"name":"__init_global","order":8,"path":"scripts/__init_global/__init_global.yy",},
{"name":"sh_trail_filler_pass2","order":32,"path":"shaders/sh_trail_filler_pass2/sh_trail_filler_pass2.yy",}, {"name":"sh_trail_filler_pass2","order":32,"path":"shaders/sh_trail_filler_pass2/sh_trail_filler_pass2.yy",},
{"name":"node_path_smooth","order":18,"path":"scripts/node_path_smooth/node_path_smooth.yy",},
{"name":"node_PCX_array_set","order":1,"path":"scripts/node_PCX_array_set/node_PCX_array_set.yy",}, {"name":"node_PCX_array_set","order":1,"path":"scripts/node_PCX_array_set/node_PCX_array_set.yy",},
{"name":"node_caustic","order":23,"path":"scripts/node_caustic/node_caustic.yy",}, {"name":"node_caustic","order":23,"path":"scripts/node_caustic/node_caustic.yy",},
{"name":"s_node_regex_search","order":11,"path":"sprites/s_node_regex_search/s_node_regex_search.yy",}, {"name":"s_node_regex_search","order":11,"path":"sprites/s_node_regex_search/s_node_regex_search.yy",},
@ -1845,6 +1849,7 @@
{"name":"node_frame","order":1,"path":"scripts/node_frame/node_frame.yy",}, {"name":"node_frame","order":1,"path":"scripts/node_frame/node_frame.yy",},
{"name":"s_node_scale_algo","order":7,"path":"sprites/s_node_scale_algo/s_node_scale_algo.yy",}, {"name":"s_node_scale_algo","order":7,"path":"sprites/s_node_scale_algo/s_node_scale_algo.yy",},
{"name":"sh_sdf_dist","order":4,"path":"shaders/sh_sdf_dist/sh_sdf_dist.yy",}, {"name":"sh_sdf_dist","order":4,"path":"shaders/sh_sdf_dist/sh_sdf_dist.yy",},
{"name":"s_node_path_mapp","order":17,"path":"sprites/s_node_path_mapp/s_node_path_mapp.yy",},
{"name":"node_path_plot","order":12,"path":"scripts/node_path_plot/node_path_plot.yy",}, {"name":"node_path_plot","order":12,"path":"scripts/node_path_plot/node_path_plot.yy",},
{"name":"sh_de_corner","order":6,"path":"shaders/sh_de_corner/sh_de_corner.yy",}, {"name":"sh_de_corner","order":6,"path":"shaders/sh_de_corner/sh_de_corner.yy",},
{"name":"BBMOD_Vec3","order":5,"path":"scripts/BBMOD_Vec3/BBMOD_Vec3.yy",}, {"name":"BBMOD_Vec3","order":5,"path":"scripts/BBMOD_Vec3/BBMOD_Vec3.yy",},

View file

@ -629,6 +629,7 @@
{"id":{"name":"s_node_rigidSim_object","path":"sprites/s_node_rigidSim_object/s_node_rigidSim_object.yy",},}, {"id":{"name":"s_node_rigidSim_object","path":"sprites/s_node_rigidSim_object/s_node_rigidSim_object.yy",},},
{"id":{"name":"sh_blend_max","path":"shaders/sh_blend_max/sh_blend_max.yy",},}, {"id":{"name":"sh_blend_max","path":"shaders/sh_blend_max/sh_blend_max.yy",},},
{"id":{"name":"s_node_color_out","path":"sprites/s_node_color_out/s_node_color_out.yy",},}, {"id":{"name":"s_node_color_out","path":"sprites/s_node_color_out/s_node_color_out.yy",},},
{"id":{"name":"pathAnchorBox","path":"scripts/pathAnchorBox/pathAnchorBox.yy",},},
{"id":{"name":"bbmod_lerp_delta_time","path":"scripts/bbmod_lerp_delta_time/bbmod_lerp_delta_time.yy",},}, {"id":{"name":"bbmod_lerp_delta_time","path":"scripts/bbmod_lerp_delta_time/bbmod_lerp_delta_time.yy",},},
{"id":{"name":"__3D","path":"scripts/__3D/__3D.yy",},}, {"id":{"name":"__3D","path":"scripts/__3D/__3D.yy",},},
{"id":{"name":"node_vector_cross2D","path":"scripts/node_vector_cross2D/node_vector_cross2D.yy",},}, {"id":{"name":"node_vector_cross2D","path":"scripts/node_vector_cross2D/node_vector_cross2D.yy",},},
@ -831,6 +832,7 @@
{"id":{"name":"sh_channel_G_grey","path":"shaders/sh_channel_G_grey/sh_channel_G_grey.yy",},}, {"id":{"name":"sh_channel_G_grey","path":"shaders/sh_channel_G_grey/sh_channel_G_grey.yy",},},
{"id":{"name":"display_screenshot","path":"extensions/display_screenshot/display_screenshot.yy",},}, {"id":{"name":"display_screenshot","path":"extensions/display_screenshot/display_screenshot.yy",},},
{"id":{"name":"node_strand_sim_inline","path":"scripts/node_strand_sim_inline/node_strand_sim_inline.yy",},}, {"id":{"name":"node_strand_sim_inline","path":"scripts/node_strand_sim_inline/node_strand_sim_inline.yy",},},
{"id":{"name":"node_path_map","path":"scripts/node_path_map/node_path_map.yy",},},
{"id":{"name":"s_node_smokeSim_update","path":"sprites/s_node_smokeSim_update/s_node_smokeSim_update.yy",},}, {"id":{"name":"s_node_smokeSim_update","path":"sprites/s_node_smokeSim_update/s_node_smokeSim_update.yy",},},
{"id":{"name":"node_3d_depth","path":"scripts/node_3d_depth/node_3d_depth.yy",},}, {"id":{"name":"node_3d_depth","path":"scripts/node_3d_depth/node_3d_depth.yy",},},
{"id":{"name":"s_node_vec4","path":"sprites/s_node_vec4/s_node_vec4.yy",},}, {"id":{"name":"s_node_vec4","path":"sprites/s_node_vec4/s_node_vec4.yy",},},
@ -1709,6 +1711,7 @@
{"id":{"name":"s_node_trigger","path":"sprites/s_node_trigger/s_node_trigger.yy",},}, {"id":{"name":"s_node_trigger","path":"sprites/s_node_trigger/s_node_trigger.yy",},},
{"id":{"name":"fd_rectangle_get_repeat","path":"scripts/fd_rectangle_get_repeat/fd_rectangle_get_repeat.yy",},}, {"id":{"name":"fd_rectangle_get_repeat","path":"scripts/fd_rectangle_get_repeat/fd_rectangle_get_repeat.yy",},},
{"id":{"name":"s_menu_white","path":"sprites/s_menu_white/s_menu_white.yy",},}, {"id":{"name":"s_menu_white","path":"sprites/s_menu_white/s_menu_white.yy",},},
{"id":{"name":"s_node_path_smooth","path":"sprites/s_node_path_smooth/s_node_path_smooth.yy",},},
{"id":{"name":"node_struct_json_parse","path":"scripts/node_struct_json_parse/node_struct_json_parse.yy",},}, {"id":{"name":"node_struct_json_parse","path":"scripts/node_struct_json_parse/node_struct_json_parse.yy",},},
{"id":{"name":"color_loader","path":"scripts/color_loader/color_loader.yy",},}, {"id":{"name":"color_loader","path":"scripts/color_loader/color_loader.yy",},},
{"id":{"name":"node_rigid_override","path":"scripts/node_rigid_override/node_rigid_override.yy",},}, {"id":{"name":"node_rigid_override","path":"scripts/node_rigid_override/node_rigid_override.yy",},},
@ -1882,6 +1885,7 @@
{"id":{"name":"s_node_text_render","path":"sprites/s_node_text_render/s_node_text_render.yy",},}, {"id":{"name":"s_node_text_render","path":"sprites/s_node_text_render/s_node_text_render.yy",},},
{"id":{"name":"__init_global","path":"scripts/__init_global/__init_global.yy",},}, {"id":{"name":"__init_global","path":"scripts/__init_global/__init_global.yy",},},
{"id":{"name":"sh_trail_filler_pass2","path":"shaders/sh_trail_filler_pass2/sh_trail_filler_pass2.yy",},}, {"id":{"name":"sh_trail_filler_pass2","path":"shaders/sh_trail_filler_pass2/sh_trail_filler_pass2.yy",},},
{"id":{"name":"node_path_smooth","path":"scripts/node_path_smooth/node_path_smooth.yy",},},
{"id":{"name":"node_PCX_array_set","path":"scripts/node_PCX_array_set/node_PCX_array_set.yy",},}, {"id":{"name":"node_PCX_array_set","path":"scripts/node_PCX_array_set/node_PCX_array_set.yy",},},
{"id":{"name":"sh_color_select_side","path":"shaders/sh_color_select_side/sh_color_select_side.yy",},}, {"id":{"name":"sh_color_select_side","path":"shaders/sh_color_select_side/sh_color_select_side.yy",},},
{"id":{"name":"node_caustic","path":"scripts/node_caustic/node_caustic.yy",},}, {"id":{"name":"node_caustic","path":"scripts/node_caustic/node_caustic.yy",},},
@ -2262,6 +2266,7 @@
{"id":{"name":"node_frame","path":"scripts/node_frame/node_frame.yy",},}, {"id":{"name":"node_frame","path":"scripts/node_frame/node_frame.yy",},},
{"id":{"name":"s_node_scale_algo","path":"sprites/s_node_scale_algo/s_node_scale_algo.yy",},}, {"id":{"name":"s_node_scale_algo","path":"sprites/s_node_scale_algo/s_node_scale_algo.yy",},},
{"id":{"name":"sh_sdf_dist","path":"shaders/sh_sdf_dist/sh_sdf_dist.yy",},}, {"id":{"name":"sh_sdf_dist","path":"shaders/sh_sdf_dist/sh_sdf_dist.yy",},},
{"id":{"name":"s_node_path_mapp","path":"sprites/s_node_path_mapp/s_node_path_mapp.yy",},},
{"id":{"name":"node_path_plot","path":"scripts/node_path_plot/node_path_plot.yy",},}, {"id":{"name":"node_path_plot","path":"scripts/node_path_plot/node_path_plot.yy",},},
{"id":{"name":"node_bw","path":"scripts/node_bw/node_bw.yy",},}, {"id":{"name":"node_bw","path":"scripts/node_bw/node_bw.yy",},},
{"id":{"name":"sh_de_corner","path":"shaders/sh_de_corner/sh_de_corner.yy",},}, {"id":{"name":"sh_de_corner","path":"shaders/sh_de_corner/sh_de_corner.yy",},},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -18,8 +18,6 @@ function Path() constructor {
var pix = frac(_rat) * lengthTotal; var pix = frac(_rat) * lengthTotal;
return getPointDistance(pix, _ind, out); return getPointDistance(pix, _ind, out);
} }
static getPointSegment = function(_seg, _ind = 0, out = undefined) { return new __vec2(0, 0); }
} }
function PathSegment() : Path() constructor { function PathSegment() : Path() constructor {
@ -77,16 +75,8 @@ function PathSegment() : Path() constructor {
return new __vec2(0, 0); return new __vec2(0, 0);
} }
static getPointSegment = function(_seg) {
var fr = (floor(_seg)) % getSegmentCount();
var to = (fr + 1) % getSegmentCount();
var st = frac(_seg);
return segments[fr].lerpTo(segments[to], st);
}
static getPointRatio = function(_rat) { static getPointRatio = function(_rat) {
return getPointSegment(frac(_rat) * lengthTotal); return getPointDistance(frac(_rat) * lengthTotal);
} }
static getTangentRatio = function(_rat) { static getTangentRatio = function(_rat) {

View file

@ -58,15 +58,18 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
#region ---- path ---- #region ---- path ----
anchors = []; anchors = [];
segments = [];
lengths = []; lengths = [];
lengthAccs = []; lengthAccs = [];
boundary = [];
lengthTotal = 0; lengthTotal = 0;
boundary = new BoundingBox();
cached_pos = ds_map_create(); cached_pos = ds_map_create();
#endregion #endregion
#region ---- editor ---- #region ---- editor ----
line_hover = -1;
drag_point = -1; drag_point = -1;
drag_points = []; drag_points = [];
drag_type = 0; drag_type = 0;
@ -91,15 +94,17 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
["Anchors", false], ["Anchors", false],
]; ];
for( var i = input_fix_len, n = ds_list_size(inputs); i < n; i++ ) for( var i = input_fix_len, n = ds_list_size(inputs); i < n; i++ ) {
array_push(input_display_list, i); array_push(input_display_list, i);
inputs[| i].name = $"Anchor {i - input_fix_len}";
}
} #endregion } #endregion
static createNewInput = function(_x = 0, _y = 0, _dxx = 0, _dxy = 0, _dyx = 0, _dyy = 0) { #region static createNewInput = function(_x = 0, _y = 0, _dxx = 0, _dxy = 0, _dyx = 0, _dyy = 0) { #region
var index = ds_list_size(inputs); var index = ds_list_size(inputs);
inputs[| index] = nodeValue("Anchor", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ _x, _y, _dxx, _dxy, _dyx, _dyy, false ]) inputs[| index] = nodeValue("Anchor", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ _x, _y, _dxx, _dxy, _dyx, _dyy, false ])
.setDisplay(VALUE_DISPLAY.vector); .setDisplay(VALUE_DISPLAY.path_anchor);
recordAction(ACTION_TYPE.list_insert, inputs, [ inputs[| index], index, "add path anchor point" ]); recordAction(ACTION_TYPE.list_insert, inputs, [ inputs[| index], index, "add path anchor point" ]);
resetDisplayList(); resetDisplayList();
@ -545,116 +550,88 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
} }
} }
#region check line hover var _line_hover = -1;
var line_hover = -1; var anchor_hover = -1;
var points = []; var hover_type = 0;
var _a0, _a1;
var minx = 99999, miny = 99999; var points = [];
var maxx = -99999, maxy = -99999; var _a0, _a1;
for(var i = loop? 0 : 1; i < ansize; i++) { var minx = 99999, miny = 99999;
if(i) { var maxx = -99999, maxy = -99999;
_a0 = getInputData(input_fix_len + i - 1);
_a1 = getInputData(input_fix_len + i);
} else {
_a0 = getInputData(input_fix_len + ansize - 1);
_a1 = getInputData(input_fix_len + 0);
}
var _ox = 0, _oy = 0, _nx = 0, _ny = 0, p = 0, pnt = []; if(!array_empty(anchors)) {
for(var j = 0; j < sample; j++) {
if(array_length(_a0) < 6) continue;
p = eval_bezier(j / (sample - 1), _a0[_ANCHOR.x], _a0[_ANCHOR.y],
_a1[_ANCHOR.x], _a1[_ANCHOR.y],
_a0[_ANCHOR.x] + _a0[_ANCHOR.c2x], _a0[_ANCHOR.y] + _a0[_ANCHOR.c2y],
_a1[_ANCHOR.x] + _a1[_ANCHOR.c1x], _a1[_ANCHOR.y] + _a1[_ANCHOR.c1y]);
_nx = _x + p[0] * _s;
_ny = _y + p[1] * _s;
minx = min(minx, _nx); miny = min(miny, _ny);
maxx = max(maxx, _nx); maxy = max(maxy, _ny);
array_push(pnt, [ _nx, _ny ]);
if(j && (key_mod_press(CTRL) || isUsingTool(1)) && distance_to_line(_mx, _my, _ox, _oy, _nx, _ny) < 4)
line_hover = i;
_ox = _nx;
_oy = _ny;
}
array_push(points, pnt);
}
#endregion
#region draw path
draw_set_color(isUsingTool(0)? c_white : COLORS._main_accent); draw_set_color(isUsingTool(0)? c_white : COLORS._main_accent);
var ind = 0; for( var i = 0, n = array_length(segments); i < n; i++ ) { #region draw path
for(var i = loop? 0 : 1; i < ansize; i++) { var _seg = segments[i];
for(var j = 0; j < sample; j++) { var _ox = 0, _oy = 0, _nx = 0, _ny = 0, p = 0;
_nx = points[ind][j][_ANCHOR.x];
_ny = points[ind][j][_ANCHOR.y];
if(j) draw_line_width(_ox, _oy, _nx, _ny, 1 + 2 * (line_hover == i)); for( var j = 0, m = array_length(_seg); j < m; j++ ) {
_nx = _x + _seg[j][0] * _s;
_ny = _y + _seg[j][1] * _s;
if(j) {
if((key_mod_press(CTRL) || isUsingTool(1)) && distance_to_line(_mx, _my, _ox, _oy, _nx, _ny) < 4)
_line_hover = i;
draw_line_width(_ox, _oy, _nx, _ny, 1 + 2 * (line_hover == i));
}
_ox = _nx; _ox = _nx;
_oy = _ny; _oy = _ny;
} }
} #endregion
ind++; #region draw anchor
} if(!isUsingTool(0))
for(var i = 0; i < ansize; i++) {
var _a = anchors[i];
var xx = _x + _a[0] * _s;
var yy = _y + _a[1] * _s;
var cont = false;
var _ax0 = 0, _ay0 = 0;
var _ax1 = 0, _ay1 = 0;
var anchor_hover = -1; if(array_length(_a) < 6) continue;
var hover_type = 0;
if(!isUsingTool(0)) if(_a[2] != 0 || _a[3] != 0 || _a[4] != 0 || _a[5] != 0) {
for(var i = 0; i < ansize; i++) { _ax0 = _x + (_a[0] + _a[2]) * _s;
var _a = getInputData(input_fix_len + i); _ay0 = _y + (_a[1] + _a[3]) * _s;
var xx = _x + _a[0] * _s; _ax1 = _x + (_a[0] + _a[4]) * _s;
var yy = _y + _a[1] * _s; _ay1 = _y + (_a[1] + _a[5]) * _s;
var cont = false; cont = true;
var _ax0 = 0, _ay0 = 0;
var _ax1 = 0, _ay1 = 0;
if(array_length(_a) < 6) continue; draw_set_color(COLORS.node_path_overlay_control_line);
draw_line(_ax0, _ay0, xx, yy);
draw_line(_ax1, _ay1, xx, yy);
if(_a[2] != 0 || _a[3] != 0 || _a[4] != 0 || _a[5] != 0) { draw_sprite_colored(THEME.anchor_selector, 2, _ax0, _ay0);
_ax0 = _x + (_a[0] + _a[2]) * _s; draw_sprite_colored(THEME.anchor_selector, 2, _ax1, _ay1);
_ay0 = _y + (_a[1] + _a[3]) * _s; }
_ax1 = _x + (_a[0] + _a[4]) * _s;
_ay1 = _y + (_a[1] + _a[5]) * _s;
cont = true;
draw_set_color(COLORS.node_path_overlay_control_line); draw_sprite_colored(THEME.anchor_selector, 0, xx, yy);
draw_line(_ax0, _ay0, xx, yy); draw_set_text(f_p1, fa_left, fa_bottom, COLORS._main_accent);
draw_line(_ax1, _ay1, xx, yy); draw_text(xx + ui(4), yy - ui(4), inputs[| input_fix_len + i].name);
draw_sprite_colored(THEME.anchor_selector, 2, _ax0, _ay0); if(drag_point == i) {
draw_sprite_colored(THEME.anchor_selector, 2, _ax1, _ay1); draw_sprite_colored(THEME.anchor_selector, 1, xx, yy);
} else if(point_in_circle(_mx, _my, xx, yy, 8)) {
draw_sprite_colored(THEME.anchor_selector, 1, xx, yy);
anchor_hover = i;
hover_type = 0;
} else if(cont && point_in_circle(_mx, _my, _ax0, _ay0, 8)) {
draw_sprite_colored(THEME.anchor_selector, 0, _ax0, _ay0);
anchor_hover = i;
hover_type = 1;
} else if(cont && point_in_circle(_mx, _my, _ax1, _ay1, 8)) {
draw_sprite_colored(THEME.anchor_selector, 0, _ax1, _ay1);
anchor_hover = i;
hover_type = -1;
}
} }
#endregion
}
draw_sprite_colored(THEME.anchor_selector, 0, xx, yy); line_hover = _line_hover;
draw_set_text(f_p1, fa_left, fa_bottom, COLORS._main_accent);
draw_text(xx + ui(4), yy - ui(4), i + 1);
if(drag_point == i) {
draw_sprite_colored(THEME.anchor_selector, 1, xx, yy);
} else if(point_in_circle(_mx, _my, xx, yy, 8)) {
draw_sprite_colored(THEME.anchor_selector, 1, xx, yy);
anchor_hover = i;
hover_type = 0;
} else if(cont && point_in_circle(_mx, _my, _ax0, _ay0, 8)) {
draw_sprite_colored(THEME.anchor_selector, 0, _ax0, _ay0);
anchor_hover = i;
hover_type = 1;
} else if(cont && point_in_circle(_mx, _my, _ax1, _ay1, 8)) {
draw_sprite_colored(THEME.anchor_selector, 0, _ax1, _ay1);
anchor_hover = i;
hover_type = -1;
}
}
#endregion
if(isUsingTool(0)) { #region transform tools if(isUsingTool(0)) { #region transform tools
var hov = 0; var hov = 0;
@ -790,12 +767,12 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
var anc = createNewInput(value_snap((_mx - _x) / _s, _snx), value_snap((_my - _y) / _s, _sny)); var anc = createNewInput(value_snap((_mx - _x) / _s, _snx), value_snap((_my - _y) / _s, _sny));
UNDO_HOLDING = true; UNDO_HOLDING = true;
if(line_hover == -1) { if(_line_hover == -1) {
drag_point = ds_list_size(inputs) - input_fix_len - 1; drag_point = ds_list_size(inputs) - input_fix_len - 1;
} else { } else {
ds_list_remove(inputs, anc); ds_list_remove(inputs, anc);
ds_list_insert(inputs, input_fix_len + line_hover, anc); ds_list_insert(inputs, input_fix_len + _line_hover + 1, anc);
drag_point = line_hover; drag_point = _line_hover + 1;
} }
drag_type = -1; drag_type = -1;
@ -812,46 +789,32 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
static updateLength = function() { #region static updateLength = function() { #region
boundary = new BoundingBox(); boundary = new BoundingBox();
segments = [];
lengths = [];
lengthAccs = [];
lengthTotal = 0; lengthTotal = 0;
var loop = getInputData(1); var loop = getInputData(1);
var rond = getInputData(3); var sample = PREFERENCES.path_resolution;
if(!is_real(rond)) rond = false;
var ansize = ds_list_size(inputs) - input_fix_len; var ansize = ds_list_size(inputs) - input_fix_len;
if(ansize < 2) { if(ansize < 2) return;
lengths = [];
anchors = [];
return;
}
var sample = PREFERENCES.path_resolution;
var con = loop? ansize : ansize - 1; var con = loop? ansize : ansize - 1;
lengths = [];
lengthAccs = [];
anchors = array_create(ansize);
for(var i = 0; i < con; i++) { for(var i = 0; i < con; i++) {
var index_0 = input_fix_len + i; var _a0 = anchors[(i + 0) % ansize];
var index_1 = input_fix_len + i + 1; var _a1 = anchors[(i + 1) % ansize];
if(index_1 >= ds_list_size(inputs)) index_1 = input_fix_len;
var _a0 = array_clone(getInputData(index_0));
var _a1 = array_clone(getInputData(index_1));
if(rond) {
_a0[0] = round(_a0[0]);
_a0[1] = round(_a0[1]);
_a1[0] = round(_a1[0]);
_a1[1] = round(_a1[1]);
}
anchors[i + 0] = array_clone(_a0);
anchors[i + 1] = array_clone(_a1);
var l = 0, _ox = 0, _oy = 0, _nx = 0, _ny = 0, p = 0; var l = 0, _ox = 0, _oy = 0, _nx = 0, _ny = 0, p = 0;
var sg = array_create(sample);
for(var j = 0; j < sample; j++) { for(var j = 0; j < sample; j++) {
p = eval_bezier(j / sample, _a0[0], _a0[1], _a1[0], _a1[1], _a0[0] + _a0[4], _a0[1] + _a0[5], _a1[0] + _a1[2], _a1[1] + _a1[3]); p = eval_bezier(j / sample, _a0[0], _a0[1], _a1[0], _a1[1],
_nx = p[0]; _a0[0] + _a0[4], _a0[1] + _a0[5],
_ny = p[1]; _a1[0] + _a1[2], _a1[1] + _a1[3]);
sg[j] = p;
_nx = p[0];
_ny = p[1];
boundary.addPoint(_nx, _ny); boundary.addPoint(_nx, _ny);
if(j) l += point_distance(_nx, _ny, _ox, _oy); if(j) l += point_distance(_nx, _ny, _ox, _oy);
@ -860,6 +823,7 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
_oy = _ny; _oy = _ny;
} }
segments[i] = sg;
lengths[i] = l; lengths[i] = l;
lengthTotal += l; lengthTotal += l;
lengthAccs[i] = lengthTotal; lengthAccs[i] = lengthTotal;
@ -875,6 +839,7 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
static getPointDistance = function(_dist, _ind = 0, out = undefined) { #region static getPointDistance = function(_dist, _ind = 0, out = undefined) { #region
if(out == undefined) out = new __vec2(); else { out.x = 0; out.y = 0; } if(out == undefined) out = new __vec2(); else { out.x = 0; out.y = 0; }
if(array_empty(lengths)) return out;
var _cKey = _dist; var _cKey = _dist;
if(ds_map_exists(cached_pos, _cKey)) { if(ds_map_exists(cached_pos, _cKey)) {
@ -884,33 +849,17 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
return out; return out;
} }
var loop = getInputData(1); var loop = getInputData(1);
var rond = getInputData(3);
if(!is_real(rond)) rond = false;
if(loop) _dist = safe_mod(_dist, lengthTotal, MOD_NEG.wrap); if(loop) _dist = safe_mod(_dist, lengthTotal, MOD_NEG.wrap);
var _oDist = _dist;
var ansize = array_length(lengths);
var amo = ds_list_size(inputs) - input_fix_len;
var ansize = ds_list_size(inputs) - input_fix_len;
if(ansize == 0) return out; if(ansize == 0) return out;
var _a0, _a1; var _a0, _a1;
for(var i = 0; i < ansize; i++) { for(var i = 0; i < ansize; i++) {
_a0 = array_clone(anchors[safe_mod(i + 0, amo)]); _a0 = anchors[(i + 0) % ansize];
_a1 = array_clone(anchors[safe_mod(i + 1, amo)]); _a1 = anchors[(i + 1) % ansize];
if(!is_array(_a0) || !is_array(_a1))
return out;
if(rond) {
_a0[0] = round(_a0[0]);
_a0[1] = round(_a0[1]);
_a1[0] = round(_a1[0]);
_a1[1] = round(_a1[1]);
}
if(_dist > lengths[i]) { if(_dist > lengths[i]) {
_dist -= lengths[i]; _dist -= lengths[i];
@ -919,8 +868,8 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
var _t = _dist / lengths[i]; var _t = _dist / lengths[i];
var _p = eval_bezier(_t, _a0[0], _a0[1], _a1[0], _a1[1], _a0[0] + _a0[4], _a0[1] + _a0[5], _a1[0] + _a1[2], _a1[1] + _a1[3]); var _p = eval_bezier(_t, _a0[0], _a0[1], _a1[0], _a1[1], _a0[0] + _a0[4], _a0[1] + _a0[5], _a1[0] + _a1[2], _a1[1] + _a1[3]);
out.x = _p[0]; out.x = _p[0];
out.y = _p[1]; out.y = _p[1];
cached_pos[? _cKey] = out.clone(); cached_pos[? _cKey] = out.clone();
return out; return out;
@ -935,69 +884,50 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
} #endregion } #endregion
static getPointSegment = function(_rat) { #region static getPointSegment = function(_rat) { #region
if(array_empty(lengths)) return new __vec2();
var loop = getInputData(1); var loop = getInputData(1);
var rond = getInputData(3); var ansize = ds_list_size(inputs) - input_fix_len;
if(!is_real(rond)) rond = false;
var ansize = array_length(lengths); if(_rat < 0) return new __vec2(anchors[0][0], anchors[0][1]);
var amo = ds_list_size(inputs) - input_fix_len;
if(amo < 1) return new __vec2(0, 0);
if(_rat < 0) {
var _p0 = getInputData(input_fix_len);
if(rond)
return new __vec2(round(_p0[0]), round(_p0[1]));
return new __vec2(_p0[0], _p0[1]);
}
_rat = safe_mod(_rat, ansize); _rat = safe_mod(_rat, ansize);
var _i0 = clamp(floor(_rat), 0, amo - 1); var _i0 = clamp(floor(_rat), 0, ansize - 1);
var _i1 = (_i0 + 1) % ansize;
var _t = frac(_rat); var _t = frac(_rat);
var _i1 = _i0 + 1;
if(_i1 >= amo) { if(_i1 >= ansize && !loop) return new __vec2(anchors[ansize - 1][0], anchors[ansize - 1][1]);
if(!loop) {
var _p1 = getInputData(ds_list_size(inputs) - 1)
if(rond)
return new __vec2(round(_p1[0]), round(_p1[1]));
return new __vec2(_p1[0], _p1[1]);
}
_i1 = 0; var _a0 = anchors[_i0];
} var _a1 = anchors[_i1];
var p = eval_bezier(_t, _a0[0], _a0[1], _a1[0], _a1[1], _a0[0] + _a0[4], _a0[1] + _a0[5], _a1[0] + _a1[2], _a1[1] + _a1[3]);
var _a0 = array_clone(getInputData(input_fix_len + _i0));
var _a1 = array_clone(getInputData(input_fix_len + _i1));
if(rond) {
_a0[0] = round(_a0[0]); _a0[1] = round(_a0[1]);
_a1[0] = round(_a1[0]); _a1[1] = round(_a1[1]);
}
var p = eval_bezier(_t, _a0[0], _a0[1], _a1[0], _a1[1], _a0[0] + _a0[4], _a0[1] + _a0[5], _a1[0] + _a1[2], _a1[1] + _a1[3]);
return new __vec2(p[0], p[1]); return new __vec2(p[0], p[1]);
} #endregion } #endregion
static update = function(frame = CURRENT_FRAME) { #region static update = function(frame = CURRENT_FRAME) { #region
ds_map_clear(cached_pos); ds_map_clear(cached_pos);
updateLength();
var _rat = getInputData(0); var _rat = getInputData(0);
var _typ = getInputData(2); var _typ = getInputData(2);
var _rnd = getInputData(3); var _rnd = getInputData(3);
var anchors = []; var _a = [];
for(var i = input_fix_len; i < ds_list_size(inputs); i++) { for(var i = input_fix_len; i < ds_list_size(inputs); i++) {
var _anc = array_clone(getInputData(i)); var _anc = array_clone(getInputData(i));
if(_rnd) { if(_rnd) {
_anc[0] = round(_anc[0]); _anc[0] = round(_anc[0]);
_anc[1] = round(_anc[2]); _anc[1] = round(_anc[1]);
} }
array_push(anchors, _anc); array_push(_a, _anc);
} }
outputs[| 2].setValue(anchors);
anchors = _a;
outputs[| 2].setValue(_a);
updateLength();
if(is_array(_rat)) { if(is_array(_rat)) {
var _out = array_create(array_length(_rat)); var _out = array_create(array_length(_rat));

View file

@ -12,23 +12,10 @@ function Node_Path_Bridge(_x, _y, _group = noone) : Node(_x, _y, _group) constru
inputs[| 2] = nodeValue("Smooth", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false) inputs[| 2] = nodeValue("Smooth", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false)
.rejectArray(); .rejectArray();
inputs[| 3] = nodeValue("UV Mapping", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false)
.rejectArray();
inputs[| 4] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF)
.setDisplay(VALUE_DISPLAY.vector);
inputs[| 5] = nodeValue("Texture", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
outputs[| 0] = nodeValue("Path", self, JUNCTION_CONNECT.output, VALUE_TYPE.pathnode, self); outputs[| 0] = nodeValue("Path", self, JUNCTION_CONNECT.output, VALUE_TYPE.pathnode, self);
outputs[| 1] = nodeValue("Rendered", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
preview_channel = 1;
input_display_list = [ 0, input_display_list = [ 0,
["Bridge", false], 1, 2, ["Bridge", false], 1, 2,
["Mapping", true, 3], 4, 5,
] ]
cached_pos = ds_map_create(); cached_pos = ds_map_create();
@ -274,62 +261,5 @@ function Node_Path_Bridge(_x, _y, _group = noone) : Node(_x, _y, _group) constru
} }
} }
#endregion #endregion
var _map = getInputData(3);
var _dim = getInputData(4);
var _surf = getInputData(5);
if(!_map || !is_surface(_surf) || _amo < 2) return;
var _pnt = array_create(_amo + 1);
var _sub = 16;
var _isb = 1 / _sub;
var _pp = new __vec2();
for( var i = 0; i < _amo; i++ ) {
var _p = array_create(_sub + 1);
var _ind = 0;
for( var j = 0; j <= 1; j += _isb ) {
_pp = getPointRatio(j, i, _pp);
_p[_ind++] = [ _pp.x, _pp.y ];
}
_pnt[i] = _p;
}
var _out = outputs[| 1].getValue();
_out = surface_verify(_out, _dim[0], _dim[1])
surface_set_shader(_out, noone);
draw_set_color(c_white);
draw_primitive_begin_texture(pr_trianglelist, surface_get_texture(_surf));
for( var i = 0; i < _amo - 1; i++ )
for( var j = 0; j < _sub - 1; j++ ) {
var p0 = _pnt[i + 0][j + 0];
var p1 = _pnt[i + 1][j + 0];
var p2 = _pnt[i + 0][j + 1];
var p3 = _pnt[i + 1][j + 1];
var p0u = (j + 0) / (_sub - 1), p0v = (i + 0) / (_amo - 1);
var p1u = (j + 0) / (_sub - 1), p1v = (i + 1) / (_amo - 1);
var p2u = (j + 1) / (_sub - 1), p2v = (i + 0) / (_amo - 1);
var p3u = (j + 1) / (_sub - 1), p3v = (i + 1) / (_amo - 1);
draw_vertex_texture(p0[0], p0[1], p0u, p0v);
draw_vertex_texture(p1[0], p1[1], p1u, p1v);
draw_vertex_texture(p2[0], p2[1], p2u, p2v);
draw_vertex_texture(p1[0], p1[1], p1u, p1v);
draw_vertex_texture(p2[0], p2[1], p2u, p2v);
draw_vertex_texture(p3[0], p3[1], p3u, p3v);
}
draw_primitive_end();
surface_reset_shader();
outputs[| 1].setValue(_out);
} #endregion } #endregion
} }

View file

@ -0,0 +1,88 @@
function Node_Path_Map(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Map Path";
inputs[| 0] = nodeValue("Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.pathnode, noone)
.setVisible(true, true)
.rejectArray();
inputs[| 1] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF)
.setDisplay(VALUE_DISPLAY.vector);
inputs[| 2] = nodeValue("Texture", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 3] = nodeValue("Subdivision", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 16)
.rejectArray();
outputs[| 0] = nodeValue("Rendered", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
input_display_list = [ 0,
["Mapping", false], 1, 2, 3,
]
static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
var _path = getInputData(0);
if(_path) _path.drawOverlay(active, _x, _y, _s, _mx, _my, _snx, _sny);
} #endregion
static update = function() { #region
var _path = getInputData(0);
if(_path == noone) return;
var _dim = getInputData(1);
var _surf = getInputData(2);
var _sub = getInputData(3);
var _amo = _path.getLineCount();
if(!is_surface(_surf) || _amo < 2) return;
var _pnt = array_create(_amo + 1);
var _isb = 1 / _sub;
var _pp = new __vec2();
for( var i = 0; i < _amo; i++ ) {
var _p = array_create(_sub + 1);
var _ind = 0;
for( var j = 0; j <= 1; j += _isb ) {
_pp = _path.getPointRatio(j, i, _pp);
_p[_ind++] = [ _pp.x, _pp.y ];
}
_pnt[i] = _p;
}
var _out = outputs[| 0].getValue();
_out = surface_verify(_out, _dim[0], _dim[1])
surface_set_shader(_out, noone);
draw_set_color(c_white);
draw_primitive_begin_texture(pr_trianglelist, surface_get_texture(_surf));
for( var i = 0; i < _amo - 1; i++ )
for( var j = 0; j < _sub - 1; j++ ) {
var p0 = _pnt[i + 0][j + 0];
var p1 = _pnt[i + 1][j + 0];
var p2 = _pnt[i + 0][j + 1];
var p3 = _pnt[i + 1][j + 1];
var p0u = (j + 0) / (_sub - 1), p0v = (i + 0) / (_amo - 1);
var p1u = (j + 0) / (_sub - 1), p1v = (i + 1) / (_amo - 1);
var p2u = (j + 1) / (_sub - 1), p2v = (i + 0) / (_amo - 1);
var p3u = (j + 1) / (_sub - 1), p3v = (i + 1) / (_amo - 1);
draw_vertex_texture(p0[0], p0[1], p0u, p0v);
draw_vertex_texture(p1[0], p1[1], p1u, p1v);
draw_vertex_texture(p2[0], p2[1], p2u, p2v);
draw_vertex_texture(p1[0], p1[1], p1u, p1v);
draw_vertex_texture(p2[0], p2[1], p2u, p2v);
draw_vertex_texture(p3[0], p3[1], p3u, p3v);
}
draw_primitive_end();
surface_reset_shader();
outputs[| 0].setValue(_out);
} #endregion
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "node_path_map",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "path",
"path": "folders/nodes/data/value/path.yy",
},
}

View file

@ -0,0 +1,299 @@
function Node_Path_Smooth(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Smooth Path";
w = 96;
inputs[| 0] = nodeValue("Loop", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false)
.rejectArray();
inputs[| 1] = nodeValue("Round anchor", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false)
.rejectArray();
inputs[| 2] = nodeValue("Smoothness", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 3)
.setDisplay(VALUE_DISPLAY.slider, { range : [ 1, 5, 0.01 ] } );
outputs[| 0] = nodeValue("Path data", self, JUNCTION_CONNECT.output, VALUE_TYPE.pathnode, self);
input_display_list = [
["Path", false], 0, 1, 2,
["Anchors", false],
];
setIsDynamicInput(1);
tools = [
new NodeTool( "Anchor add / remove", THEME.path_tools_add ),
];
#region ---- path ----
anchors = [];
controls = [];
segments = [];
lengths = [];
lengthAccs = [];
lengthTotal = 0;
boundary = new BoundingBox();
cached_pos = ds_map_create();
#endregion
#region ---- editor ----
#endregion
static resetDisplayList = function() { #region
recordAction(ACTION_TYPE.var_modify, self, [ array_clone(input_display_list), "input_display_list" ]);
input_display_list = [
["Path", false], 0, 1, 2,
["Anchors", false],
];
for( var i = input_fix_len, n = ds_list_size(inputs); i < n; i++ ) {
array_push(input_display_list, i);
inputs[| i].name = $"Anchor {i - input_fix_len}";
}
} #endregion
static createNewInput = function(_x = 0, _y = 0) { #region
var index = ds_list_size(inputs);
inputs[| index] = nodeValue("Anchor", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ _x, _y ])
.setDisplay(VALUE_DISPLAY.vector);
recordAction(ACTION_TYPE.list_insert, inputs, [ inputs[| index], index, "add path anchor point" ]);
resetDisplayList();
return inputs[| index];
} #endregion
static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
var sample = PREFERENCES.path_resolution;
var ansize = ds_list_size(inputs) - input_fix_len;
var loop = getInputData(0);
var rond = getInputData(1);
var _line_hover = -1;
var _anchor_hover = -1;
if(!array_empty(anchors)) {
draw_set_color(COLORS._main_accent);
for( var i = 0, n = array_length(segments); i < n; i++ ) { #region draw path
var _seg = segments[i];
var _ox = 0, _oy = 0, _nx = 0, _ny = 0, p = 0;
for( var j = 0, m = array_length(_seg); j < m; j++ ) {
_nx = _x + _seg[j][0] * _s;
_ny = _y + _seg[j][1] * _s;
if(j) {
if((key_mod_press(CTRL) || isUsingTool(0)) && distance_to_line(_mx, _my, _ox, _oy, _nx, _ny) < 4)
_line_hover = i;
draw_line_width(_ox, _oy, _nx, _ny, 1 + 2 * (line_hover == i));
}
_ox = _nx;
_oy = _ny;
}
} #endregion
#region draw anchor
var _act = active && !isUsingTool(0);
for(var i = input_fix_len; i < ds_list_size(inputs); i++) {
var a = inputs[| i].drawOverlay(_act, _x, _y, _s, _mx, _my, _snx, _sny);
_act &= !a;
if(a) _anchor_hover = i;
//var a = anchors[ i - input_fix_len];
//var c = controls[i - input_fix_len];
//draw_set_color(c_red);
//draw_circle(_x + (a[0] + c[0]) * _s, _y + (a[1] + c[1]) * _s, 4, false);
//draw_set_color(c_blue);
//draw_circle(_x + (a[0] + c[2]) * _s, _y + (a[1] + c[3]) * _s, 4, false);
}
#endregion
}
line_hover = _line_hover;
if(key_mod_press(CTRL) || isUsingTool(0)) { #region anchor edit
draw_sprite_ui_uniform(_anchor_hover == -1? THEME.cursor_path_add : THEME.cursor_path_remove, 0, _mx + 16, _my + 16);
if(mouse_press(mb_left, active)) {
if(_anchor_hover == -1) {
var anc = createNewInput(value_snap((_mx - _x) / _s, _snx), value_snap((_my - _y) / _s, _sny));
UNDO_HOLDING = true;
if(_line_hover != -1) {
ds_list_remove(inputs, anc);
ds_list_insert(inputs, input_fix_len + _line_hover + 1, anc);
}
} else {
recordAction(ACTION_TYPE.list_delete, inputs, [ inputs[| input_fix_len + _anchor_hover], input_fix_len + _anchor_hover, "remove path anchor point" ]);
ds_list_delete(inputs, input_fix_len + _anchor_hover);
resetDisplayList();
}
RENDER_ALL
}
#endregion
}
} #endregion
static updateLength = function() { #region
var loop = getInputData(0);
segments = [];
lengths = [];
lengthAccs = [];
lengthTotal = 0;
boundary = new BoundingBox();
var sample = PREFERENCES.path_resolution;
var ansize = ds_list_size(inputs) - input_fix_len;
if(ansize < 2) return;
var con = loop? ansize : ansize - 1;
for(var i = 0; i < con; i++) {
var _a0 = anchors[(i + 0) % ansize];
var _a1 = anchors[(i + 1) % ansize];
var _c0 = controls[(i + 0) % ansize];
var _c1 = controls[(i + 1) % ansize];
var l = 0, _ox = 0, _oy = 0, _nx = 0, _ny = 0, p = 0;
var sg = array_create(sample);
for(var j = 0; j < sample; j++) {
p = eval_bezier(j / sample, _a0[0], _a0[1], _a1[0], _a1[1],
_a0[0] + _c0[2], _a0[1] + _c0[3],
_a1[0] + _c1[0], _a1[1] + _c1[1]);
sg[j] = p;
_nx = p[0];
_ny = p[1];
boundary.addPoint(_nx, _ny);
if(j) l += point_distance(_nx, _ny, _ox, _oy);
_ox = _nx;
_oy = _ny;
}
segments[i] = sg;
lengths[i] = l;
lengthTotal += l;
lengthAccs[i] = lengthTotal;
}
} #endregion
static getLineCount = function() { return 1; }
static getSegmentCount = function() { return array_length(lengths); }
static getBoundary = function() { return boundary; }
static getLength = function() { return lengthTotal; }
static getAccuLength = function() { return lengthAccs; }
static getPointDistance = function(_dist, _ind = 0, out = undefined) { #region
if(out == undefined) out = new __vec2(); else { out.x = 0; out.y = 0; }
if(array_empty(lengths)) return out;
var _cKey = _dist;
if(ds_map_exists(cached_pos, _cKey)) {
var _p = cached_pos[? _cKey];
out.x = _p.x;
out.y = _p.y;
return out;
}
var loop = getInputData(1);
if(loop) _dist = safe_mod(_dist, lengthTotal, MOD_NEG.wrap);
var ansize = ds_list_size(inputs) - input_fix_len;
if(ansize == 0) return out;
var _a0, _a1;
for(var i = 0; i < ansize; i++) {
_a0 = anchors[(i + 0) % ansize];
_a1 = anchors[(i + 1) % ansize];
if(_dist > lengths[i]) {
_dist -= lengths[i];
continue;
}
var _t = _dist / lengths[i];
//var _p = eval_bezier(_t, _a0[0], _a0[1], _a1[0], _a1[1], _a0[0] + _a0[4], _a0[1] + _a0[5], _a1[0] + _a1[2], _a1[1] + _a1[3]);
out.x = _p[0];
out.y = _p[1];
cached_pos[? _cKey] = out.clone();
return out;
}
return out;
} #endregion
static getPointRatio = function(_rat, _ind = 0, out = undefined) { #region
var pix = frac(_rat) * lengthTotal;
return getPointDistance(pix, _ind, out);
} #endregion
static update = function(frame = CURRENT_FRAME) { #region
ds_map_clear(cached_pos);
var loop = getInputData(0);
var rond = getInputData(1);
var smot = getInputData(2);
var _a = [];
for(var i = input_fix_len; i < ds_list_size(inputs); i++) {
var _anc = array_clone(getInputData(i));
if(rond) {
_anc[0] = round(_anc[0]);
_anc[1] = round(_anc[1]);
}
array_push(_a, _anc);
}
var amo = array_length(_a);
anchors = _a;
controls = array_create(amo);
if(amo == 2) {
controls = [
[ 0, 0, 0, 0 ],
[ 0, 0, 0, 0 ],
];
} else {
for( var i = 0, n = amo; i < n; i++ ) {
var _a0 = array_safe_get(anchors, i - 1,, ARRAY_OVERFLOW.loop);
var _a1 = array_safe_get(anchors, i ,, ARRAY_OVERFLOW.loop);
var _a2 = array_safe_get(anchors, i + 1,, ARRAY_OVERFLOW.loop);
var _dr = point_direction(_a0[0], _a0[1], _a2[0], _a2[1]);
var _ds0 = point_distance(_a1[0], _a1[1], _a0[0], _a0[1]) / smot;
var _ds2 = point_distance(_a1[0], _a1[1], _a2[0], _a2[1]) / smot;
controls[i] = [ -lengthdir_x(_ds0, _dr), -lengthdir_y(_ds0, _dr),
lengthdir_x(_ds2, _dr), lengthdir_y(_ds2, _dr) ];
}
if(!loop && amo) {
controls[0] = [ 0, 0, 0, 0 ];
controls[amo - 1] = [ 0, 0, 0, 0 ];
}
}
updateLength();
} #endregion
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(THEME.node_draw_path, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
} #endregion
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "node_path_smooth",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "path",
"path": "folders/nodes/data/value/path.yy",
},
}

View file

@ -777,6 +777,7 @@ function __initNodes() {
ds_list_add(values, "Paths"); ds_list_add(values, "Paths");
addNodeObject(values, "Path", s_node_path, "Node_Path", [1, Node_Path]); addNodeObject(values, "Path", s_node_path, "Node_Path", [1, Node_Path]);
addNodeObject(values, "Smooth Path", s_node_path_smooth, "Node_Path_Smooth", [1, Node_Path_Smooth], ["path smooth"]).setVersion(11640);
addNodeObject(values, "Path Anchor", s_node_path_anchor, "Node_Path_Anchor", [1, Node_Path_Anchor]).setVersion(1140); addNodeObject(values, "Path Anchor", s_node_path_anchor, "Node_Path_Anchor", [1, Node_Path_Anchor]).setVersion(1140);
addNodeObject(values, "Path Array", s_node_path_array, "Node_Path_Array", [1, Node_Path_Array], ["array path"]).setVersion(1137); addNodeObject(values, "Path Array", s_node_path_array, "Node_Path_Array", [1, Node_Path_Array], ["array path"]).setVersion(1137);
addNodeObject(values, "Sample Path", s_node_path_sample, "Node_Path_Sample", [1, Node_Path_Sample], ["path sample"], "Sample a 2D position from a path"); addNodeObject(values, "Sample Path", s_node_path_sample, "Node_Path_Sample", [1, Node_Path_Sample], ["path sample"], "Sample a 2D position from a path");
@ -793,6 +794,7 @@ function __initNodes() {
addNodeObject(values, "Path from Mask", s_node_path_from_mask, "Node_Path_From_Mask", [1, Node_Path_From_Mask]).setVersion(11640); addNodeObject(values, "Path from Mask", s_node_path_from_mask, "Node_Path_From_Mask", [1, Node_Path_From_Mask]).setVersion(11640);
addNodeObject(values, "Bridge Path", s_node_path_bridge, "Node_Path_Bridge", [1, Node_Path_Bridge]).setVersion(11640); addNodeObject(values, "Bridge Path", s_node_path_bridge, "Node_Path_Bridge", [1, Node_Path_Bridge]).setVersion(11640);
addNodeObject(values, "Bake Path", s_node_path_bake, "Node_Path_Bake", [1, Node_Path_Bake]).setVersion(11640); addNodeObject(values, "Bake Path", s_node_path_bake, "Node_Path_Bake", [1, Node_Path_Bake]).setVersion(11640);
addNodeObject(values, "Map Path", s_node_path_mapp, "Node_Path_Map", [1, Node_Path_Map]).setVersion(11640);
ds_list_add(values, "Boolean"); ds_list_add(values, "Boolean");
addNodeObject(values, "Boolean", s_node_boolean, "Node_Boolean", [1, Node_Boolean]); addNodeObject(values, "Boolean", s_node_boolean, "Node_Boolean", [1, Node_Boolean]);

View file

@ -88,6 +88,7 @@ enum VALUE_DISPLAY {
corner, corner,
toggle, toggle,
matrix, matrix,
path_anchor,
gradient_range, gradient_range,
//Curve //Curve
@ -366,6 +367,7 @@ function typeArray(_type) { #region
case VALUE_DISPLAY.rotation_range : case VALUE_DISPLAY.rotation_range :
case VALUE_DISPLAY.rotation_random : case VALUE_DISPLAY.rotation_random :
case VALUE_DISPLAY.slider_range : case VALUE_DISPLAY.slider_range :
case VALUE_DISPLAY.path_anchor :
case VALUE_DISPLAY.gradient_range : case VALUE_DISPLAY.gradient_range :
case VALUE_DISPLAY.vector : case VALUE_DISPLAY.vector :
@ -1119,6 +1121,13 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru
extract_node = "Node_Vector4"; extract_node = "Node_Vector4";
display_data.angle_display = QUARTERNION_DISPLAY.quarterion; display_data.angle_display = QUARTERNION_DISPLAY.quarterion;
break; #endregion break; #endregion
case VALUE_DISPLAY.path_anchor : #region
editWidget = new pathAnchorBox(function(index, val) {
return setValueDirect(val, index);
});
extract_node = "Node_Path_Anchor";
break; #endregion
} }
break; break;

View file

@ -0,0 +1,82 @@
function pathAnchorBox(_onModify) : widget() constructor {
onModify = _onModify;
onModifySingle[0] = function(val) { return onModify(0, toNumber(val)); }
onModifySingle[1] = function(val) { return onModify(1, toNumber(val)); }
onModifySingle[2] = function(val) { return onModify(2, toNumber(val)); }
onModifySingle[3] = function(val) { return onModify(3, toNumber(val)); }
onModifySingle[4] = function(val) { return onModify(4, toNumber(val)); }
onModifySingle[5] = function(val) { return onModify(5, toNumber(val)); }
for(var i = 0; i < 6; i++) {
tb[i] = new textBox(TEXTBOX_INPUT.number, onModifySingle[i]);
tb[i].slidable = true;
}
tb[0].setPrecision(2).setLabel("x");
tb[1].setPrecision(2).setLabel("y");
tb[2].setPrecision(2).setLabel("dx0");
tb[3].setPrecision(2).setLabel("dy0");
tb[4].setPrecision(2).setLabel("dx1");
tb[5].setPrecision(2).setLabel("dy1");
static setSlideSpeed = function(speed) {
for( var i = 0, n = array_length(tb); i < n; i++ )
tb[i].setSlidable(speed);
}
static setInteract = function(interactable = noone) {
self.interactable = interactable;
for( var i = 0, n = array_length(tb); i < n; i++ )
tb[i].interactable = interactable;
}
static register = function(parent = noone) {
for( var i = 0, n = array_length(tb); i < n; i++ )
tb[i].register(parent);
}
static drawParam = function(params) {
return draw(params.x, params.y, params.w, params.h, params.data, params.m);
}
static draw = function(_x, _y, _w, _h, _data, _m) {
x = _x;
y = _y;
w = _w;
h = _h * 2 + 6;
for( var i = 0, n = array_length(tb); i < n; i++ )
tb[i].setFocusHover(active, hover);
var _tx = _x, _ty = _y;
var _tw = _w / 2 - 4;
var _th = _h;
tb[0].draw(_tx, _ty, _tw, _th, _data[0], _m);
tb[1].draw(_tx + _w / 2, _ty, _tw, _th, _data[1], _m);
var _bw = ui(28);
var _ty = _y + _th + 6;
var _tw = (_w - _bw - 8) / 4 - 4;
tb[2].draw(_tx + (_tw + 4) * 0, _ty, _tw, _th, _data[2], _m);
tb[3].draw(_tx + (_tw + 4) * 1, _ty, _tw, _th, _data[3], _m);
tb[4].draw(_tx + (_tw + 4) * 2 + _bw + 8, _ty, _tw, _th, _data[4], _m);
tb[5].draw(_tx + (_tw + 4) * 3 + _bw + 8, _ty, _tw, _th, _data[5], _m);
var _linked = _data[6];
var _blend = !_linked? COLORS._main_accent : COLORS._main_icon;
var bx = _x + _w / 2 - _bw / 2 - 2;
var by = _ty + _th / 2 - _bw / 2;
if(buttonInstant(THEME.button_hide, bx, by, _bw, _bw, _m, active, hover, "Linked", THEME.value_link, !_linked, _blend) == 2)
onModify(6, !_linked);
resetFocus();
return h;
}
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "pathAnchorBox",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "text",
"path": "folders/widgets/text.yy",
},
}

View file

@ -0,0 +1,12 @@
{
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "widgets",
"path": "folders/widgets/widgets.yy",
},
"resourceVersion": "1.0",
"name": "vectorBox",
"tags": [],
"resourceType": "GMScript",
}

View file

@ -31,7 +31,7 @@ function string_partial_match(str, key) { #region
return -9999; return -9999;
} #endregion } #endregion
function string_real(val, digMax = 999) { #region function string_real(val, digMax = 999, decMin = 5) { #region
if(is_string(val)) return val; if(is_string(val)) return val;
if(is_struct(val)) return string(val); if(is_struct(val)) return string(val);
@ -45,7 +45,7 @@ function string_real(val, digMax = 999) { #region
if(val == 0) return "0"; if(val == 0) return "0";
var pres, p = 1; var pres, p = 1;
var presMax = min(5, digMax - ceil(log10(ceil(abs(val))))); var presMax = min(decMin, digMax - ceil(log10(ceil(abs(val)))));
for( pres = 0; pres < presMax; pres++ ) { for( pres = 0; pres < presMax; pres++ ) {
if(frac(val * p) == 0) if(frac(val * p) == 0)
break; break;

View file

@ -8,8 +8,9 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor {
hide = false; hide = false;
font = noone; font = noone;
color = COLORS._main_text; color = COLORS._main_text;
boxColor = c_white; boxColor = c_white;
format = TEXT_AREA_FORMAT._default; format = TEXT_AREA_FORMAT._default;
precision = 5;
no_empty = true; no_empty = true;
auto_update = false; auto_update = false;
@ -21,6 +22,8 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor {
slide_speed = 1 / 10; slide_speed = 1 / 10;
slide_range = noone; slide_range = noone;
label = "";
starting_char = 1; starting_char = 1;
_current_text = ""; _current_text = "";
@ -81,6 +84,16 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor {
return self; return self;
} #endregion } #endregion
static setLabel = function(label) { #region
self.label = label;
return self;
} #endregion
static setPrecision = function(precision) { #region
self.precision = precision;
return self;
} #endregion
static setEmpty = function() { #region static setEmpty = function() { #region
no_empty = false; no_empty = false;
return self; return self;
@ -495,7 +508,7 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor {
var _display_text = _raw_text; var _display_text = _raw_text;
if(input == TEXTBOX_INPUT.number) { if(input == TEXTBOX_INPUT.number) {
var dig = floor(_w / string_width("0")) - 3; var dig = floor(_w / string_width("0")) - 3;
_display_text = string_real(_display_text, dig); _display_text = string_real(_display_text, dig, precision);
} }
var tw = string_width(_display_text); var tw = string_width(_display_text);
var th = string_height(_display_text); var th = string_height(_display_text);
@ -526,7 +539,7 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor {
draw_sprite_stretched_ext(THEME.textbox, 0, _x, _y, _w, _h, boxColor, 0.5 + 0.5 * interactable); draw_sprite_stretched_ext(THEME.textbox, 0, _x, _y, _w, _h, boxColor, 0.5 + 0.5 * interactable);
if(slidable) { if(slidable) {
if(_w > ui(64) && _h >= TEXTBOX_HEIGHT) if(_w > ui(64) && _h >= TEXTBOX_HEIGHT && label == "")
draw_sprite_ui_uniform(THEME.text_slider, 0, _x + ui(20), _y + _h / 2, 1, COLORS._main_icon, 0.5); draw_sprite_ui_uniform(THEME.text_slider, 0, _x + ui(20), _y + _h / 2, 1, COLORS._main_icon, 0.5);
if(hover && point_in_rectangle(_m[0], _m[1], _x, _y, _x + _w, _y + _h) && mouse_press(mb_left, active)) { if(hover && point_in_rectangle(_m[0], _m[1], _x, _y, _x + _w, _y + _h) && mouse_press(mb_left, active)) {
@ -544,6 +557,13 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor {
BLEND_ALPHA BLEND_ALPHA
draw_surface(text_surface, tb_surf_x, tb_surf_y); draw_surface(text_surface, tb_surf_x, tb_surf_y);
BLEND_NORMAL BLEND_NORMAL
if(label != "") {
draw_set_text(f_p2, fa_left, fa_center, COLORS._main_icon);
draw_set_alpha(0.5);
draw_text_add(_x + ui(8), _y + _h / 2, label);
draw_set_alpha(1);
}
} #endregion } #endregion
if(sliding > 0) { #region if(sliding > 0) { #region

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,74 @@
{
"resourceType": "GMSprite",
"resourceVersion": "1.0",
"name": "s_node_path_mapp",
"bbox_bottom": 60,
"bbox_left": 1,
"bbox_right": 60,
"bbox_top": 4,
"bboxMode": 0,
"collisionKind": 1,
"collisionTolerance": 0,
"DynamicTexturePage": false,
"edgeFiltering": false,
"For3D": false,
"frames": [
{"resourceType":"GMSpriteFrame","resourceVersion":"1.1","name":"ec70cd3b-4977-4a0d-bfae-db0427d3bcec",},
],
"gridX": 0,
"gridY": 0,
"height": 64,
"HTile": false,
"layers": [
{"resourceType":"GMImageLayer","resourceVersion":"1.0","name":"c3649735-9a85-48ac-9447-0cdd5cff4b3e","blendMode":0,"displayName":"default","isLocked":false,"opacity":100.0,"visible":true,},
],
"nineSlice": null,
"origin": 4,
"parent": {
"name": "path",
"path": "folders/nodes/icons/value/path.yy",
},
"preMultiplyAlpha": false,
"sequence": {
"resourceType": "GMSequence",
"resourceVersion": "1.4",
"name": "s_node_path_mapp",
"autoRecord": true,
"backdropHeight": 768,
"backdropImageOpacity": 0.5,
"backdropImagePath": "",
"backdropWidth": 1366,
"backdropXOffset": 0.0,
"backdropYOffset": 0.0,
"events": {"resourceType":"KeyframeStore<MessageEventKeyframe>","resourceVersion":"1.0","Keyframes":[],},
"eventStubScript": null,
"eventToFunction": {},
"length": 1.0,
"lockOrigin": false,
"moments": {"resourceType":"KeyframeStore<MomentsEventKeyframe>","resourceVersion":"1.0","Keyframes":[],},
"playback": 1,
"playbackSpeed": 30.0,
"playbackSpeedType": 0,
"showBackdrop": true,
"showBackdropImage": false,
"timeUnits": 1,
"tracks": [
{"resourceType":"GMSpriteFramesTrack","resourceVersion":"1.0","name":"frames","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"resourceType":"KeyframeStore<SpriteFrameKeyframe>","resourceVersion":"1.0","Keyframes":[
{"resourceType":"Keyframe<SpriteFrameKeyframe>","resourceVersion":"1.0","Channels":{"0":{"resourceType":"SpriteFrameKeyframe","resourceVersion":"1.0","Id":{"name":"ec70cd3b-4977-4a0d-bfae-db0427d3bcec","path":"sprites/s_node_path_mapp/s_node_path_mapp.yy",},},},"Disabled":false,"id":"a5efdb4b-ccd1-46dd-af92-327e2471156f","IsCreationKey":false,"Key":0.0,"Length":1.0,"Stretch":false,},
],},"modifiers":[],"spriteId":null,"trackColour":0,"tracks":[],"traits":0,},
],
"visibleRange": null,
"volume": 1.0,
"xorigin": 32,
"yorigin": 32,
},
"swatchColours": null,
"swfPrecision": 2.525,
"textureGroupId": {
"name": "Default",
"path": "texturegroups/Default",
},
"type": 0,
"VTile": false,
"width": 64,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,74 @@
{
"resourceType": "GMSprite",
"resourceVersion": "1.0",
"name": "s_node_path_smooth",
"bbox_bottom": 58,
"bbox_left": 2,
"bbox_right": 59,
"bbox_top": 2,
"bboxMode": 0,
"collisionKind": 1,
"collisionTolerance": 0,
"DynamicTexturePage": false,
"edgeFiltering": false,
"For3D": false,
"frames": [
{"resourceType":"GMSpriteFrame","resourceVersion":"1.1","name":"cab5eac1-5bb6-4eb1-82e8-addb0b69ee2a",},
],
"gridX": 0,
"gridY": 0,
"height": 64,
"HTile": false,
"layers": [
{"resourceType":"GMImageLayer","resourceVersion":"1.0","name":"eb4d330c-5343-4301-8779-f59b17310094","blendMode":0,"displayName":"default","isLocked":false,"opacity":100.0,"visible":true,},
],
"nineSlice": null,
"origin": 4,
"parent": {
"name": "path",
"path": "folders/nodes/icons/value/path.yy",
},
"preMultiplyAlpha": false,
"sequence": {
"resourceType": "GMSequence",
"resourceVersion": "1.4",
"name": "s_node_path_smooth",
"autoRecord": true,
"backdropHeight": 768,
"backdropImageOpacity": 0.5,
"backdropImagePath": "",
"backdropWidth": 1366,
"backdropXOffset": 0.0,
"backdropYOffset": 0.0,
"events": {"resourceType":"KeyframeStore<MessageEventKeyframe>","resourceVersion":"1.0","Keyframes":[],},
"eventStubScript": null,
"eventToFunction": {},
"length": 1.0,
"lockOrigin": false,
"moments": {"resourceType":"KeyframeStore<MomentsEventKeyframe>","resourceVersion":"1.0","Keyframes":[],},
"playback": 1,
"playbackSpeed": 30.0,
"playbackSpeedType": 0,
"showBackdrop": true,
"showBackdropImage": false,
"timeUnits": 1,
"tracks": [
{"resourceType":"GMSpriteFramesTrack","resourceVersion":"1.0","name":"frames","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"resourceType":"KeyframeStore<SpriteFrameKeyframe>","resourceVersion":"1.0","Keyframes":[
{"resourceType":"Keyframe<SpriteFrameKeyframe>","resourceVersion":"1.0","Channels":{"0":{"resourceType":"SpriteFrameKeyframe","resourceVersion":"1.0","Id":{"name":"cab5eac1-5bb6-4eb1-82e8-addb0b69ee2a","path":"sprites/s_node_path_smooth/s_node_path_smooth.yy",},},},"Disabled":false,"id":"86b96d5b-e205-4c36-ad8d-83d8e3353724","IsCreationKey":false,"Key":0.0,"Length":1.0,"Stretch":false,},
],},"modifiers":[],"spriteId":null,"trackColour":0,"tracks":[],"traits":0,},
],
"visibleRange": null,
"volume": 1.0,
"xorigin": 32,
"yorigin": 32,
},
"swatchColours": null,
"swfPrecision": 2.525,
"textureGroupId": {
"name": "Default",
"path": "texturegroups/Default",
},
"type": 0,
"VTile": false,
"width": 64,
}