diff --git a/PixelComposer.resource_order b/PixelComposer.resource_order index 4ce3b6d16..45bb08d04 100644 --- a/PixelComposer.resource_order +++ b/PixelComposer.resource_order @@ -416,6 +416,7 @@ {"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":"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":"__3D","order":8,"path":"scripts/__3D/__3D.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":"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_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":"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",}, @@ -1371,6 +1373,7 @@ {"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":"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":"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",}, @@ -1515,6 +1518,7 @@ {"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":"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_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",}, @@ -1845,6 +1849,7 @@ {"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":"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":"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",}, diff --git a/PixelComposer.yyp b/PixelComposer.yyp index cd2b612df..948801b0d 100644 --- a/PixelComposer.yyp +++ b/PixelComposer.yyp @@ -629,6 +629,7 @@ {"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":"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":"__3D","path":"scripts/__3D/__3D.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":"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_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":"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",},}, @@ -1709,6 +1711,7 @@ {"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":"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":"color_loader","path":"scripts/color_loader/color_loader.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":"__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":"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":"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",},}, @@ -2262,6 +2266,7 @@ {"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":"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_bw","path":"scripts/node_bw/node_bw.yy",},}, {"id":{"name":"sh_de_corner","path":"shaders/sh_de_corner/sh_de_corner.yy",},}, diff --git a/fonts/_f_sdf/_f_sdf.old.png b/fonts/_f_sdf/_f_sdf.old.png index 40fffc822..9919ac84a 100644 Binary files a/fonts/_f_sdf/_f_sdf.old.png and b/fonts/_f_sdf/_f_sdf.old.png differ diff --git a/fonts/_f_sdf/_f_sdf.png b/fonts/_f_sdf/_f_sdf.png index 219fe0f1d..2e92c95b8 100644 Binary files a/fonts/_f_sdf/_f_sdf.png and b/fonts/_f_sdf/_f_sdf.png differ diff --git a/fonts/_f_sdf_medium/_f_sdf_medium.old.png b/fonts/_f_sdf_medium/_f_sdf_medium.old.png index 322967bea..281be5ce6 100644 Binary files a/fonts/_f_sdf_medium/_f_sdf_medium.old.png and b/fonts/_f_sdf_medium/_f_sdf_medium.old.png differ diff --git a/fonts/_f_sdf_medium/_f_sdf_medium.png b/fonts/_f_sdf_medium/_f_sdf_medium.png index 559f830c7..a595a98e8 100644 Binary files a/fonts/_f_sdf_medium/_f_sdf_medium.png and b/fonts/_f_sdf_medium/_f_sdf_medium.png differ diff --git a/scripts/__path/__path.gml b/scripts/__path/__path.gml index 4e4053481..0df9914ec 100644 --- a/scripts/__path/__path.gml +++ b/scripts/__path/__path.gml @@ -18,8 +18,6 @@ function Path() constructor { var pix = frac(_rat) * lengthTotal; return getPointDistance(pix, _ind, out); } - - static getPointSegment = function(_seg, _ind = 0, out = undefined) { return new __vec2(0, 0); } } function PathSegment() : Path() constructor { @@ -77,18 +75,10 @@ function PathSegment() : Path() constructor { 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) { - return getPointSegment(frac(_rat) * lengthTotal); + return getPointDistance(frac(_rat) * lengthTotal); } - + static getTangentRatio = function(_rat) { _rat = frac(_rat); var l = _rat * lengthTotal; diff --git a/scripts/node_path/node_path.gml b/scripts/node_path/node_path.gml index deeb07ec7..253adef18 100644 --- a/scripts/node_path/node_path.gml +++ b/scripts/node_path/node_path.gml @@ -58,15 +58,18 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { #region ---- path ---- anchors = []; + segments = []; lengths = []; lengthAccs = []; - boundary = []; lengthTotal = 0; + boundary = new BoundingBox(); cached_pos = ds_map_create(); #endregion #region ---- editor ---- + line_hover = -1; + drag_point = -1; drag_points = []; drag_type = 0; @@ -91,15 +94,17 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { ["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); + inputs[| i].name = $"Anchor {i - input_fix_len}"; + } } #endregion static createNewInput = function(_x = 0, _y = 0, _dxx = 0, _dxy = 0, _dyx = 0, _dyy = 0) { #region var index = ds_list_size(inputs); 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" ]); 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 points = []; - var _a0, _a1; + var _line_hover = -1; + var anchor_hover = -1; + var hover_type = 0; - var minx = 99999, miny = 99999; - var maxx = -99999, maxy = -99999; + var points = []; + var _a0, _a1; - for(var i = loop? 0 : 1; i < ansize; i++) { - if(i) { - _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 = []; - 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 ]); + var minx = 99999, miny = 99999; + var maxx = -99999, maxy = -99999; - 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 + if(!array_empty(anchors)) { draw_set_color(isUsingTool(0)? c_white : COLORS._main_accent); - var ind = 0; - for(var i = loop? 0 : 1; i < ansize; i++) { - for(var j = 0; j < sample; j++) { - _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 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(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; _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; - var hover_type = 0; - - if(!isUsingTool(0)) - for(var i = 0; i < ansize; i++) { - var _a = getInputData(input_fix_len + 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; + if(array_length(_a) < 6) continue; - if(array_length(_a) < 6) continue; + if(_a[2] != 0 || _a[3] != 0 || _a[4] != 0 || _a[5] != 0) { + _ax0 = _x + (_a[0] + _a[2]) * _s; + _ay0 = _y + (_a[1] + _a[3]) * _s; + _ax1 = _x + (_a[0] + _a[4]) * _s; + _ay1 = _y + (_a[1] + _a[5]) * _s; + cont = true; - if(_a[2] != 0 || _a[3] != 0 || _a[4] != 0 || _a[5] != 0) { - _ax0 = _x + (_a[0] + _a[2]) * _s; - _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_line(_ax0, _ay0, xx, yy); - draw_line(_ax1, _ay1, xx, yy); + draw_set_color(COLORS.node_path_overlay_control_line); + draw_line(_ax0, _ay0, xx, yy); + draw_line(_ax1, _ay1, xx, yy); - draw_sprite_colored(THEME.anchor_selector, 2, _ax0, _ay0); - draw_sprite_colored(THEME.anchor_selector, 2, _ax1, _ay1); - } + draw_sprite_colored(THEME.anchor_selector, 2, _ax0, _ay0); + draw_sprite_colored(THEME.anchor_selector, 2, _ax1, _ay1); + } - draw_sprite_colored(THEME.anchor_selector, 0, xx, yy); - draw_set_text(f_p1, fa_left, fa_bottom, COLORS._main_accent); - draw_text(xx + ui(4), yy - ui(4), i + 1); + draw_sprite_colored(THEME.anchor_selector, 0, xx, yy); + draw_set_text(f_p1, fa_left, fa_bottom, COLORS._main_accent); + draw_text(xx + ui(4), yy - ui(4), inputs[| input_fix_len + i].name); - 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; + 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 + #endregion + } + + line_hover = _line_hover; if(isUsingTool(0)) { #region transform tools 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)); UNDO_HOLDING = true; - if(line_hover == -1) { + if(_line_hover == -1) { drag_point = ds_list_size(inputs) - input_fix_len - 1; } else { ds_list_remove(inputs, anc); - ds_list_insert(inputs, input_fix_len + line_hover, anc); - drag_point = line_hover; + ds_list_insert(inputs, input_fix_len + _line_hover + 1, anc); + drag_point = _line_hover + 1; } drag_type = -1; @@ -812,46 +789,32 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { static updateLength = function() { #region boundary = new BoundingBox(); + segments = []; + lengths = []; + lengthAccs = []; lengthTotal = 0; + var loop = getInputData(1); - var rond = getInputData(3); - if(!is_real(rond)) rond = false; + var sample = PREFERENCES.path_resolution; var ansize = ds_list_size(inputs) - input_fix_len; - if(ansize < 2) { - lengths = []; - anchors = []; - return; - } - var sample = PREFERENCES.path_resolution; + if(ansize < 2) return; var con = loop? ansize : ansize - 1; - lengths = []; - lengthAccs = []; - anchors = array_create(ansize); for(var i = 0; i < con; i++) { - var index_0 = input_fix_len + i; - var index_1 = input_fix_len + i + 1; - 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 _a0 = anchors[(i + 0) % ansize]; + var _a1 = anchors[(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] + _a0[4], _a0[1] + _a0[5], _a1[0] + _a1[2], _a1[1] + _a1[3]); - _nx = p[0]; - _ny = p[1]; + 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]); + sg[j] = p; + _nx = p[0]; + _ny = p[1]; boundary.addPoint(_nx, _ny); 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; } + segments[i] = sg; lengths[i] = l; lengthTotal += l; 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 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)) { @@ -884,33 +849,17 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { return out; } - var loop = getInputData(1); - var rond = getInputData(3); - if(!is_real(rond)) rond = false; - + var loop = getInputData(1); 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; var _a0, _a1; for(var i = 0; i < ansize; i++) { - _a0 = array_clone(anchors[safe_mod(i + 0, amo)]); - _a1 = array_clone(anchors[safe_mod(i + 1, amo)]); - - 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]); - } + _a0 = anchors[(i + 0) % ansize]; + _a1 = anchors[(i + 1) % ansize]; if(_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 _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]; + out.x = _p[0]; + out.y = _p[1]; cached_pos[? _cKey] = out.clone(); return out; @@ -935,69 +884,50 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { } #endregion static getPointSegment = function(_rat) { #region + if(array_empty(lengths)) return new __vec2(); + var loop = getInputData(1); - var rond = getInputData(3); - if(!is_real(rond)) rond = false; + var ansize = ds_list_size(inputs) - input_fix_len; - var ansize = array_length(lengths); - 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]); - } + if(_rat < 0) return new __vec2(anchors[0][0], anchors[0][1]); _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 _i1 = _i0 + 1; - if(_i1 >= amo) { - 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; - } + if(_i1 >= ansize && !loop) return new __vec2(anchors[ansize - 1][0], anchors[ansize - 1][1]); - var _a0 = array_clone(getInputData(input_fix_len + _i0)); - var _a1 = array_clone(getInputData(input_fix_len + _i1)); + 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]); - 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]); } #endregion static update = function(frame = CURRENT_FRAME) { #region ds_map_clear(cached_pos); - updateLength(); var _rat = getInputData(0); var _typ = getInputData(2); var _rnd = getInputData(3); - var anchors = []; + var _a = []; for(var i = input_fix_len; i < ds_list_size(inputs); i++) { var _anc = array_clone(getInputData(i)); if(_rnd) { _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)) { var _out = array_create(array_length(_rat)); diff --git a/scripts/node_path_bridge/node_path_bridge.gml b/scripts/node_path_bridge/node_path_bridge.gml index eb0008a34..40f3bd497 100644 --- a/scripts/node_path_bridge/node_path_bridge.gml +++ b/scripts/node_path_bridge/node_path_bridge.gml @@ -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) .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[| 1] = nodeValue("Rendered", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); - - preview_channel = 1; - input_display_list = [ 0, ["Bridge", false], 1, 2, - ["Mapping", true, 3], 4, 5, ] cached_pos = ds_map_create(); @@ -274,62 +261,5 @@ function Node_Path_Bridge(_x, _y, _group = noone) : Node(_x, _y, _group) constru } } #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 } \ No newline at end of file diff --git a/scripts/node_path_map/node_path_map.gml b/scripts/node_path_map/node_path_map.gml new file mode 100644 index 000000000..3cc93e7c0 --- /dev/null +++ b/scripts/node_path_map/node_path_map.gml @@ -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 +} \ No newline at end of file diff --git a/scripts/node_path_map/node_path_map.yy b/scripts/node_path_map/node_path_map.yy new file mode 100644 index 000000000..531ff894a --- /dev/null +++ b/scripts/node_path_map/node_path_map.yy @@ -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", + }, +} \ No newline at end of file diff --git a/scripts/node_path_smooth/node_path_smooth.gml b/scripts/node_path_smooth/node_path_smooth.gml new file mode 100644 index 000000000..d9f480155 --- /dev/null +++ b/scripts/node_path_smooth/node_path_smooth.gml @@ -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 +} \ No newline at end of file diff --git a/scripts/node_path_smooth/node_path_smooth.yy b/scripts/node_path_smooth/node_path_smooth.yy new file mode 100644 index 000000000..c57147920 --- /dev/null +++ b/scripts/node_path_smooth/node_path_smooth.yy @@ -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", + }, +} \ No newline at end of file diff --git a/scripts/node_registry/node_registry.gml b/scripts/node_registry/node_registry.gml index 0dcda7d83..2c3d50168 100644 --- a/scripts/node_registry/node_registry.gml +++ b/scripts/node_registry/node_registry.gml @@ -777,6 +777,7 @@ function __initNodes() { ds_list_add(values, "Paths"); 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 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"); @@ -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, "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, "Map Path", s_node_path_mapp, "Node_Path_Map", [1, Node_Path_Map]).setVersion(11640); ds_list_add(values, "Boolean"); addNodeObject(values, "Boolean", s_node_boolean, "Node_Boolean", [1, Node_Boolean]); diff --git a/scripts/node_value/node_value.gml b/scripts/node_value/node_value.gml index a8b930842..1655bcace 100644 --- a/scripts/node_value/node_value.gml +++ b/scripts/node_value/node_value.gml @@ -88,6 +88,7 @@ enum VALUE_DISPLAY { corner, toggle, matrix, + path_anchor, gradient_range, //Curve @@ -366,6 +367,7 @@ function typeArray(_type) { #region case VALUE_DISPLAY.rotation_range : case VALUE_DISPLAY.rotation_random : case VALUE_DISPLAY.slider_range : + case VALUE_DISPLAY.path_anchor : case VALUE_DISPLAY.gradient_range : case VALUE_DISPLAY.vector : @@ -1119,6 +1121,13 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru extract_node = "Node_Vector4"; display_data.angle_display = QUARTERNION_DISPLAY.quarterion; 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; diff --git a/scripts/pathAnchorBox/pathAnchorBox.gml b/scripts/pathAnchorBox/pathAnchorBox.gml new file mode 100644 index 000000000..f1c5d39a5 --- /dev/null +++ b/scripts/pathAnchorBox/pathAnchorBox.gml @@ -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; + } +} \ No newline at end of file diff --git a/scripts/pathAnchorBox/pathAnchorBox.yy b/scripts/pathAnchorBox/pathAnchorBox.yy new file mode 100644 index 000000000..eb5b94b93 --- /dev/null +++ b/scripts/pathAnchorBox/pathAnchorBox.yy @@ -0,0 +1,11 @@ +{ + "resourceType": "GMScript", + "resourceVersion": "1.0", + "name": "pathAnchorBox", + "isCompatibility": false, + "isDnD": false, + "parent": { + "name": "text", + "path": "folders/widgets/text.yy", + }, +} \ No newline at end of file diff --git a/scripts/pathAnchorBox/vectorBox.yy b/scripts/pathAnchorBox/vectorBox.yy new file mode 100644 index 000000000..b3ed13803 --- /dev/null +++ b/scripts/pathAnchorBox/vectorBox.yy @@ -0,0 +1,12 @@ +{ + "isDnD": false, + "isCompatibility": false, + "parent": { + "name": "widgets", + "path": "folders/widgets/widgets.yy", + }, + "resourceVersion": "1.0", + "name": "vectorBox", + "tags": [], + "resourceType": "GMScript", +} \ No newline at end of file diff --git a/scripts/string_functions/string_functions.gml b/scripts/string_functions/string_functions.gml index 91f17d6ba..08a75223f 100644 --- a/scripts/string_functions/string_functions.gml +++ b/scripts/string_functions/string_functions.gml @@ -31,7 +31,7 @@ function string_partial_match(str, key) { #region return -9999; } #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_struct(val)) return string(val); @@ -45,7 +45,7 @@ function string_real(val, digMax = 999) { #region if(val == 0) return "0"; 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++ ) { if(frac(val * p) == 0) break; diff --git a/scripts/textBox/textBox.gml b/scripts/textBox/textBox.gml index 87eb9384c..8ce85a72f 100644 --- a/scripts/textBox/textBox.gml +++ b/scripts/textBox/textBox.gml @@ -8,8 +8,9 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { hide = false; font = noone; color = COLORS._main_text; - boxColor = c_white; - format = TEXT_AREA_FORMAT._default; + boxColor = c_white; + format = TEXT_AREA_FORMAT._default; + precision = 5; no_empty = true; auto_update = false; @@ -21,6 +22,8 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { slide_speed = 1 / 10; slide_range = noone; + label = ""; + starting_char = 1; _current_text = ""; @@ -81,6 +84,16 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { return self; } #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 no_empty = false; return self; @@ -495,7 +508,7 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { var _display_text = _raw_text; if(input == TEXTBOX_INPUT.number) { 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 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); 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); 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 draw_surface(text_surface, tb_surf_x, tb_surf_y); 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 if(sliding > 0) { #region diff --git a/sprites/s_node_path_mapp/ec70cd3b-4977-4a0d-bfae-db0427d3bcec.png b/sprites/s_node_path_mapp/ec70cd3b-4977-4a0d-bfae-db0427d3bcec.png new file mode 100644 index 000000000..5d9dfb618 Binary files /dev/null and b/sprites/s_node_path_mapp/ec70cd3b-4977-4a0d-bfae-db0427d3bcec.png differ diff --git a/sprites/s_node_path_mapp/layers/ec70cd3b-4977-4a0d-bfae-db0427d3bcec/c3649735-9a85-48ac-9447-0cdd5cff4b3e.png b/sprites/s_node_path_mapp/layers/ec70cd3b-4977-4a0d-bfae-db0427d3bcec/c3649735-9a85-48ac-9447-0cdd5cff4b3e.png new file mode 100644 index 000000000..5d9dfb618 Binary files /dev/null and b/sprites/s_node_path_mapp/layers/ec70cd3b-4977-4a0d-bfae-db0427d3bcec/c3649735-9a85-48ac-9447-0cdd5cff4b3e.png differ diff --git a/sprites/s_node_path_mapp/s_node_path_mapp.yy b/sprites/s_node_path_mapp/s_node_path_mapp.yy new file mode 100644 index 000000000..092d38152 --- /dev/null +++ b/sprites/s_node_path_mapp/s_node_path_mapp.yy @@ -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","resourceVersion":"1.0","Keyframes":[],}, + "eventStubScript": null, + "eventToFunction": {}, + "length": 1.0, + "lockOrigin": false, + "moments": {"resourceType":"KeyframeStore","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","resourceVersion":"1.0","Keyframes":[ + {"resourceType":"Keyframe","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, +} \ No newline at end of file diff --git a/sprites/s_node_path_smooth/cab5eac1-5bb6-4eb1-82e8-addb0b69ee2a.png b/sprites/s_node_path_smooth/cab5eac1-5bb6-4eb1-82e8-addb0b69ee2a.png new file mode 100644 index 000000000..cacc84b80 Binary files /dev/null and b/sprites/s_node_path_smooth/cab5eac1-5bb6-4eb1-82e8-addb0b69ee2a.png differ diff --git a/sprites/s_node_path_smooth/layers/cab5eac1-5bb6-4eb1-82e8-addb0b69ee2a/eb4d330c-5343-4301-8779-f59b17310094.png b/sprites/s_node_path_smooth/layers/cab5eac1-5bb6-4eb1-82e8-addb0b69ee2a/eb4d330c-5343-4301-8779-f59b17310094.png new file mode 100644 index 000000000..cacc84b80 Binary files /dev/null and b/sprites/s_node_path_smooth/layers/cab5eac1-5bb6-4eb1-82e8-addb0b69ee2a/eb4d330c-5343-4301-8779-f59b17310094.png differ diff --git a/sprites/s_node_path_smooth/s_node_path_smooth.yy b/sprites/s_node_path_smooth/s_node_path_smooth.yy new file mode 100644 index 000000000..f64943071 --- /dev/null +++ b/sprites/s_node_path_smooth/s_node_path_smooth.yy @@ -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","resourceVersion":"1.0","Keyframes":[],}, + "eventStubScript": null, + "eventToFunction": {}, + "length": 1.0, + "lockOrigin": false, + "moments": {"resourceType":"KeyframeStore","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","resourceVersion":"1.0","Keyframes":[ + {"resourceType":"Keyframe","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, +} \ No newline at end of file