- [Curve data] Add shfit and scale properties.

This commit is contained in:
Tanasart 2024-06-18 10:18:50 +07:00
parent 2426e9a3fb
commit ee9b5ac672
7 changed files with 506 additions and 233 deletions

View file

@ -122,22 +122,41 @@
} #endregion } #endregion
function colorMultiply(c1, c2) { #region function colorMultiply(c1, c2) { #region
INLINE
if(c1 * c2 == 0) return 0; if(c1 * c2 == 0) return 0;
if(c1 == c_white) return c2; if(c1 == c_white) return c2;
if(c2 == c_white) return c1; if(c2 == c_white) return c1;
var r1 = _color_get_red(c1); var a1 = c1 >> 24 & 0xFF;
var g1 = _color_get_green(c1); var r1 = c1 >> 16 & 0xFF;
var b1 = _color_get_blue(c1); var g1 = c1 >> 8 & 0xFF;
var a1 = _color_get_alpha(c1); var b1 = c1 & 0xFF;
var r2 = _color_get_red(c2); var a2 = c2 >> 24 & 0xFF;
var g2 = _color_get_green(c2); var r2 = c2 >> 16 & 0xFF;
var b2 = _color_get_blue(c2); var g2 = c2 >> 8 & 0xFF;
var a2 = _color_get_alpha(c2); var b2 = c2 & 0xFF;
var a = min(a1 * a2 / 255, 255);
var r = min(r1 * r2 / 255, 255);
var g = min(g1 * g2 / 255, 255);
var b = min(b1 * b2 / 255, 255);
if(is_real(c1)) return make_color_rgb((r1 * r2) * 255, (g1 * g2) * 255, (b1 * b2) * 255); return (a << 24) | (r << 16) | (g << 8) | b;
return make_color_rgba((r1 * r2) * 255, (g1 * g2) * 255, (b1 * b2) * 255, (a1 * a2) * 255);
// var r1 = _color_get_red(c1);
// var g1 = _color_get_green(c1);
// var b1 = _color_get_blue(c1);
// var a1 = _color_get_alpha(c1);
// var r2 = _color_get_red(c2);
// var g2 = _color_get_green(c2);
// var b2 = _color_get_blue(c2);
// var a2 = _color_get_alpha(c2);
// if(is_real(c1)) return make_color_rgb((r1 * r2) * 255, (g1 * g2) * 255, (b1 * b2) * 255);
// return make_color_rgba((r1 * r2) * 255, (g1 * g2) * 255, (b1 * b2) * 255, (a1 * a2) * 255);
} #endregion } #endregion
function colorAdd(c1, c2) { #region function colorAdd(c1, c2) { #region

View file

@ -1,11 +1,12 @@
function curveBox(_onModify) : widget() constructor { function curveBox(_onModify) : widget() constructor {
onModify = _onModify; onModify = _onModify;
curr_data = [];
curve_surface = surface_create(1, 1); curve_surface = surface_create(1, 1);
node_dragging = -1; node_dragging = -1;
node_drag_typ = -1; node_drag_typ = -1;
h = 160; h = 200;
height_drag = false; height_drag = false;
height_my = 0; height_my = 0;
height_ss = 0; height_ss = 0;
@ -32,14 +33,41 @@ function curveBox(_onModify) : widget() constructor {
cw = 0; cw = 0;
ch = 0; ch = 0;
tb_shift = new textBox(TEXTBOX_INPUT.number, function(val) { var _data = array_clone(curr_data); _data[0] = val; onModify(_data); }).setSlidable(1 / 100);
tb_scale = new textBox(TEXTBOX_INPUT.number, function(val) { var _data = array_clone(curr_data); _data[1] = val; onModify(_data); }).setSlidable(1 / 100);
tb_shift.label = "Shift";
tb_scale.label = "Scale";
static get_x = function(val) { return cw * (val - minx) / (maxx - minx); } static get_x = function(val) { return cw * (val - minx) / (maxx - minx); }
static get_y = function(val) { return ch * (1 - (val - miny) / (maxy - miny)); } static get_y = function(val) { return ch * (1 - (val - miny) / (maxy - miny)); }
static register = function() {} static register = function() {}
static setInteract = function(interactable = noone) { #region
self.interactable = interactable;
tb_shift.setInteract(interactable);
tb_scale.setInteract(interactable);
} #endregion
static register = function(parent = noone) {
tb_shift.register(parent);
tb_scale.register(parent);
}
static isHovering = function() { #region
if(tb_shift.isHovering()) return true;
if(tb_scale.isHovering()) return true;
return hovering;
} #endregion
static drawParam = function(params) { static drawParam = function(params) {
rx = params.rx; rx = params.rx;
ry = params.ry; ry = params.ry;
tb_shift.setParam(params);
tb_scale.setParam(params);
return draw(params.x, params.y, params.w, params.data, params.m); return draw(params.x, params.y, params.w, params.data, params.m);
} }
@ -49,30 +77,39 @@ function curveBox(_onModify) : widget() constructor {
y = _y; y = _y;
w = _w; w = _w;
if(!is_array(_data) || array_length(_data) == 0) return 0;
if(is_array(_data[0])) return 0;
var _h = h - ui(4); var _h = h - ui(4);
var _amo = array_length(_data);
var _shf = _amo % 6;
var points = (_amo - _shf) / 6;
var _shift = 0;
var _scale = 1;
var zoom_size = ui(12); var zoom_size = ui(12);
var zoom_padd = zoom_size + ui(8); var zoom_padd = zoom_size + ui(8);
var tbh = line_get_height(font) + ui(4);
cw = _w - zoom_padd; cw = _w - zoom_padd;
ch = _h - zoom_padd; ch = _h - zoom_padd - (tbh + ui(4)) * bool(_shf);
hovering = false; hovering = false;
curr_data = _data;
if(_shf == 1) { _shift = _data[0]; }
else if(_shf == 2) { _shift = _data[0]; _scale = _data[1]; }
if(!is_array(_data) || array_length(_data) == 0) return 0; display_pos_x = lerp(minx, maxx, (_m[0] - _x) / cw);
if(is_array(_data[0])) return 0; display_pos_y = lerp(miny, maxy, 1 - (_m[1] - _y) / ch);
display_sel = false;
var points = array_length(_data) / 6;
#region display
display_pos_x = lerp(minx, maxx, (_m[0] - _x) / cw);
display_pos_y = lerp(miny, maxy, 1 - (_m[1] - _y) / ch);
display_sel = false;
#endregion
curve_surface = surface_verify(curve_surface, cw, ch); curve_surface = surface_verify(curve_surface, cw, ch);
if(node_dragging != -1) { #region editing if(node_dragging != -1) { #region editing
show_coord = true; show_coord = true;
_data = array_clone(_data); _data = array_clone(_data);
@ -84,7 +121,7 @@ function curveBox(_onModify) : widget() constructor {
var _my = 1 - (_m[1] - _y) / ch; var _my = 1 - (_m[1] - _y) / ch;
_my = clamp(_my * (maxy - miny) + miny, 0, 1); _my = clamp(_my * (maxy - miny) + miny, 0, 1);
var node_point = (node_dragging - 2) / 6; var node_point = (node_dragging - _shf - 2) / 6;
if(node_point > 0 && node_point < points - 1) { if(node_point > 0 && node_point < points - 1) {
if(key_mod_press(CTRL) || grid_snap) if(key_mod_press(CTRL) || grid_snap)
@ -104,35 +141,7 @@ function curveBox(_onModify) : widget() constructor {
display_pos_y = _data[node_dragging + 1]; display_pos_y = _data[node_dragging + 1];
display_sel = 1; display_sel = 1;
//sort by x if(onModify(_data))
var _xindex = [];
var _pindex = [];
for( var i = 0; i < points; i++ ) {
var ind = i * 6;
var _x0 = _data[ind + 2];
array_push(_xindex, _x0);
array_push(_pindex, _x0);
}
array_sort(_xindex, true);
if(node_point > 0 && node_point < points - 1) {
var sorted = [];
for( var i = 0; i < points; i++ ) {
var prog = _xindex[i];
var ind = array_find(_pindex, prog);
array_push(sorted, _data[ind * 6 + 0]);
array_push(sorted, _data[ind * 6 + 1]);
array_push(sorted, _data[ind * 6 + 2]);
array_push(sorted, _data[ind * 6 + 3]);
array_push(sorted, _data[ind * 6 + 4]);
array_push(sorted, _data[ind * 6 + 5]);
}
if(onModify(sorted))
UNDO_HOLDING = true;
} else if(onModify(_data))
UNDO_HOLDING = true; UNDO_HOLDING = true;
} else { //control } else { //control
@ -215,8 +224,15 @@ function curveBox(_onModify) : widget() constructor {
draw_line(_px, 0, _px, ch); draw_line(_px, 0, _px, ch);
} }
// print("");
if(_shf) {
draw_set_color(merge_color(COLORS._main_icon, COLORS._main_icon_dark, 0.5));
draw_curve(0, 0, cw, ch, _data, minx, maxx, miny, maxy, _shift, _scale);
}
for( var i = 0; i < points; i++ ) { for( var i = 0; i < points; i++ ) {
var ind = i * 6; var ind = _shf + i * 6;
var _x0 = _data[ind + 2]; var _x0 = _data[ind + 2];
var _y0 = _data[ind + 3]; var _y0 = _data[ind + 3];
@ -227,7 +243,9 @@ function curveBox(_onModify) : widget() constructor {
var by0 = _y0 + _data[ind + 1] * _w_prev; var by0 = _y0 + _data[ind + 1] * _w_prev;
var ax0 = _x0 + _data[ind + 4] * _w_next; var ax0 = _x0 + _data[ind + 4] * _w_next;
var ay0 = _y0 + _data[ind + 5] * _w_next; var ay0 = _y0 + _data[ind + 5] * _w_next;
// print($"{_x0}, {_y0} | {_data[ind + 0]}, {_data[ind + 1]} | {_data[ind + 4]}, {_data[ind + 5]}");
bx0 = get_x(bx0); bx0 = get_x(bx0);
by0 = get_y(by0); by0 = get_y(by0);
_x0 = get_x(_x0); _x0 = get_x(_x0);
@ -285,7 +303,7 @@ function curveBox(_onModify) : widget() constructor {
draw_set_color(COLORS._main_accent); draw_set_color(COLORS._main_accent);
draw_curve(0, 0, cw, ch, _data, minx, maxx, miny, maxy); draw_curve(0, 0, cw, ch, _data, minx, maxx, miny, maxy);
surface_reset_target(); surface_reset_target();
#endregion #endregion
@ -297,7 +315,7 @@ function curveBox(_onModify) : widget() constructor {
var zminy = 0 - 1; var zminy = 0 - 1;
var zmaxy = 1 + 1; var zmaxy = 1 + 1;
var byH = _h - zoom_padd; var byH = ch;
var bx = _x + w - bs; var bx = _x + w - bs;
var by = _y; var by = _y;
@ -332,7 +350,7 @@ function curveBox(_onModify) : widget() constructor {
var bxW = _w - zoom_padd; var bxW = _w - zoom_padd;
var bx = _x; var bx = _x;
var by = _y + _h - bs; var by = _y + _h - bs - (tbh + ui(4)) * bool(_shf);
var zx0 = bx + bs / 2 + (bxW - bs) * (minx - zminx) / (zmaxx - zminx); var zx0 = bx + bs / 2 + (bxW - bs) * (minx - zminx) / (zmaxx - zminx);
var zx1 = bx + bs / 2 + (bxW - bs) * (maxx - zminx) / (zmaxx - zminx); var zx1 = bx + bs / 2 + (bxW - bs) * (maxx - zminx) / (zmaxx - zminx);
@ -394,7 +412,7 @@ function curveBox(_onModify) : widget() constructor {
} }
var _bhx = _x + _w - bs; var _bhx = _x + _w - bs;
var _bhy = _y + _h - bs; var _bhy = _y + _h - bs - (tbh + ui(4)) * bool(_shf);
var _hov = false; var _hov = false;
if(point_in_rectangle(_m[0], _m[1], _bhx, _bhy, _bhx + bs, _bhy + bs)) { if(point_in_rectangle(_m[0], _m[1], _bhx, _bhy, _bhx + bs, _bhy + bs)) {
@ -409,7 +427,6 @@ function curveBox(_onModify) : widget() constructor {
} }
draw_sprite_stretched_ext(THEME.menu_button_mask, 0, _bhx, _bhy, bs, bs, _hov? COLORS._main_icon : CDEF.main_dkgrey, 1); draw_sprite_stretched_ext(THEME.menu_button_mask, 0, _bhx, _bhy, bs, bs, _hov? COLORS._main_icon : CDEF.main_dkgrey, 1);
// draw_sprite_ext(THEME.circle, 0, _bhx + bs / 2, _bhy + bs / 2, 1, 1, 0, COLORS._main_icon_light, 1);
if(height_drag) { if(height_drag) {
h = height_ss + _m[1] - height_my; h = height_ss + _m[1] - height_my;
@ -426,29 +443,33 @@ function curveBox(_onModify) : widget() constructor {
if(mouse_press(mb_left, active)) { if(mouse_press(mb_left, active)) {
if(node_hovering == -1) { if(node_hovering == -1) {
var _ind = point_insert * 6; var _ind = _shf + point_insert * 6;
var _px = (_m[0] - _x) / cw; var _px = (_m[0] - _x) / cw;
var _py = 1 - (_m[1] - _y) / ch; var _py = 1 - (_m[1] - _y) / ch;
array_insert(_data, _ind + 0, -0.1); array_insert(_data, _ind + 0, -1 / 3);
array_insert(_data, _ind + 1, 0); array_insert(_data, _ind + 1, 0);
array_insert(_data, _ind + 2, _px); array_insert(_data, _ind + 2, _px);
array_insert(_data, _ind + 3, _py); array_insert(_data, _ind + 3, _py);
array_insert(_data, _ind + 4, 0.1); array_insert(_data, _ind + 4, 1 / 3);
array_insert(_data, _ind + 5, 0); array_insert(_data, _ind + 5, 0);
if(onModify(_data)) if(onModify(_data))
UNDO_HOLDING = true; UNDO_HOLDING = true;
node_dragging = _ind + 2; node_dragging = _ind + 2;
node_drag_typ = 0; node_drag_typ = 0;
} else { } else {
node_dragging = node_hovering; node_dragging = node_hovering;
node_drag_typ = node_hover_typ; node_drag_typ = node_hover_typ;
} }
} else if(mouse_press(mb_right, active)) { } else if(mouse_press(mb_right, active)) {
var node_point = (node_hovering - 2) / 6; var node_point = (node_hovering - _shf - 2) / 6;
if(node_hover_typ == 0 && node_point > 0 && node_point < points - 1) { if(node_hover_typ == 0 && node_point > 0 && node_point < points - 1) {
array_delete(_data, node_point * 6, 6); array_delete(_data, _shf + node_point * 6, 6);
if(onModify(_data)) if(onModify(_data))
UNDO_HOLDING = true; UNDO_HOLDING = true;
} }
@ -496,6 +517,24 @@ function curveBox(_onModify) : widget() constructor {
} }
show_coord = false; show_coord = false;
if(_shf) {
var tby = _y + h - tbh;
var tbw = _w / 2;
tb_shift.setFocusHover(active, hover);
tb_scale.setFocusHover(active, hover);
tb_shift.hide = true;
tb_scale.hide = true;
draw_sprite_stretched_ext(THEME.textbox, 3, _x, tby, _w, tbh, c_white, 1);
draw_sprite_stretched_ext(THEME.textbox, 0, _x, tby, _w, tbh, c_white, 0.5 + 0.5 * interactable);
tb_shift.draw(_x, tby, tbw, tbh, _data[0], _m);
tb_scale.draw(_x + tbw, tby, tbw, tbh, _data[1], _m);
}
resetFocus(); resetFocus();
return h; return h;

View file

@ -1,38 +1,78 @@
//curve format [-cx0, -cy0, x0, y0, +cx0, +cy0, -cx1, -cy1, x1, y1, +cx1, +cy1] //curve format [-cx0, -cy0, x0, y0, +cx0, +cy0, -cx1, -cy1, x1, y1, +cx1, +cy1]
//segment format [y0, +cx0, +cy0, -cx1, -cy1, y1] //segment format [y0, +cx0, +cy0, -cx1, -cy1, y1]
#macro CURVE_DEF_00 [0, 0, 0, 0, 1/3, 0, /**/ -1/3, 0, 1, 0, 0, 0] #macro CURVE_DEF_00 [0, 1, /**/ 0, 0, 0, 0, 1/3, 0, /**/ -1/3, 0, 1, 0, 0, 0]
#macro CURVE_DEF_01 [0, 0, 0, 0, 1/3, 1/3, /**/ -1/3, -1/3, 1, 1, 0, 0] #macro CURVE_DEF_01 [0, 1, /**/ 0, 0, 0, 0, 1/3, 1/3, /**/ -1/3, -1/3, 1, 1, 0, 0]
#macro CURVE_DEF_10 [0, 0, 0, 1, 1/3, -1/3, /**/ -1/3, 1/3, 1, 0, 0, 0] #macro CURVE_DEF_10 [0, 1, /**/ 0, 0, 0, 1, 1/3, -1/3, /**/ -1/3, 1/3, 1, 0, 0, 0]
#macro CURVE_DEF_11 [0, 0, 0, 1, 1/3, 0, /**/ -1/3, 0, 1, 1, 0, 0] #macro CURVE_DEF_11 [0, 1, /**/ 0, 0, 0, 1, 1/3, 0, /**/ -1/3, 0, 1, 1, 0, 0]
function draw_curve(x0, y0, _w, _h, _bz, minx = 0, maxx = 1, miny = 0, maxy = 1) { #region function draw_curve(x0, y0, _w, _h, _bz, minx = 0, maxx = 1, miny = 0, maxy = 1, _shift = 0, _scale = 1) { #region
var segments = array_length(_bz) / 6 - 1; var _amo = array_length(_bz);
var _shf = _amo % 6;
var segments = (_amo - _shf) / 6 - 1;
var _ox, _oy; var _ox, _oy;
var rngx = maxx - minx;
var rngy = maxy - miny;
for( var i = 0; i < segments; i++ ) { for( var i = 0; i < segments; i++ ) {
var ind = i * 6; var ind = _shf + i * 6;
var _x0 = _bz[ind + 2]; var _x0 = _bz[ind + 2];
var _y0 = _bz[ind + 3]; var _y0 = _bz[ind + 3];
var ax0 = _x0 + _bz[ind + 4]; var ax0 = _x0 + _bz[ind + 4];
var ay0 = _y0 + _bz[ind + 5]; var ay0 = _y0 + _bz[ind + 5];
var _x1 = _bz[ind + 6 + 2]; var _x1 = _bz[ind + 6 + 2];
var _y1 = _bz[ind + 6 + 3]; var _y1 = _bz[ind + 6 + 3];
var bx1 = _x1 + _bz[ind + 6 + 0]; var bx1 = _x1 + _bz[ind + 6 + 0];
var by1 = _y1 + _bz[ind + 6 + 1]; var by1 = _y1 + _bz[ind + 6 + 1];
var smp = ceil((_x1 - _x0) / (maxx - minx) * 32); var _xr = _x1 - _x0;
var smp = ceil(_xr / rngx * 32);
var bbz = [ _y0, ax0, ay0, bx1, by1, _y1 ]; var bbz = [ _y0, ax0, ay0, bx1, by1, _y1 ];
if(_x1 < minx) continue; //if(_x1 < minx) continue;
if(i == 0) {
var _rx = _x0 * _scale + _shift;
var _ry = _y0;
_rx = ( _rx - minx ) / rngx;
_ry = ( _ry - miny ) / rngy;
var _nx = x0 + _w * _rx;
var _ny = y0 + _h * (1 - _ry);
draw_line(x0, _ny, _nx, _ny);
}
if(i == segments - 1) {
var _rx = _x1 * _scale + _shift;
var _ry = _y1;
_rx = ( _rx - minx ) / rngx;
_ry = ( _ry - miny ) / rngy;
var _nx = x0 + _w * _rx;
var _ny = y0 + _h * (1 - _ry);
draw_line(x0 + _w, _ny, _nx, _ny);
}
for(var j = 0; j <= smp; j++) { for(var j = 0; j <= smp; j++) {
var t = j / smp; var t = j / smp;
var _r = eval_curve_segment_t_position(t, bbz); var _r = eval_curve_segment_t_position(t, bbz);
var _rx = ((_x0 + _r[0] * (_x1 - _x0)) - minx) / (maxx - minx);
var _ry = (_r[1] - miny) / (maxy - miny); var _rx = _r[0] * _xr + _x0;
var _ry = _r[1];
_rx = _rx * _scale + _shift;
_rx = ( _rx - minx ) / rngx;
_ry = ( _ry - miny ) / rngy;
var _nx = x0 + _w * _rx; var _nx = x0 + _w * _rx;
var _ny = y0 + _h * (1 - _ry); var _ny = y0 + _h * (1 - _ry);
@ -47,17 +87,23 @@ function draw_curve(x0, y0, _w, _h, _bz, minx = 0, maxx = 1, miny = 0, maxy = 1)
} }
} #endregion } #endregion
function eval_curve_segment_t_position(t, _bz) { #region function eval_curve_segment_t_position(_t, _bz) { #region
var _t2 = _t * _t;
var _t3 = _t * _t * _t;
var _T = 1 - _t;
var _T2 = _T * _T;
var _T3 = _T * _T * _T;
return [ return [
power(1 - t, 3) * 0 _T3 * 0
+ 3 * power(1 - t, 2) * t * _bz[1] + 3 * _T2 * _t * _bz[1]
+ 3 * (1 - t) * power(t, 2) * _bz[3] + 3 * _T * _t2 * _bz[3]
+ power(t, 3) * 1, + _t3 * 1,
power(1 - t, 3) * _bz[0] _T3 * _bz[0]
+ 3 * power(1 - t, 2) * t * _bz[2] + 3 * _T2 * _t * _bz[2]
+ 3 * (1 - t) * power(t, 2) * _bz[4] + 3 * _T * _t2 * _bz[4]
+ power(t, 3) * _bz[5] + _t3 * _bz[5]
]; ];
} #endregion } #endregion
@ -69,19 +115,30 @@ function eval_curve_segment_t(_bz, t) { #region
} #endregion } #endregion
function eval_curve_x(_bz, _x, _tolr = 0.00001) { #region function eval_curve_x(_bz, _x, _tolr = 0.00001) { #region
static _CURVE_DEF_01 = [0, 0, 0, 0, 1/3, 1/3, /**/ -1/3, -1/3, 1, 1, 0, 0]; static _CURVE_DEF_01 = [0, 1, /**/ 0, 0, 0, 0, 1/3, 1/3, /**/ -1/3, -1/3, 1, 1, 0, 0];
static _CURVE_DEF_10 = [0, 0, 0, 1, 1/3, -1/3, /**/ -1/3, 1/3, 1, 0, 0, 0]; static _CURVE_DEF_10 = [0, 1, /**/ 0, 0, 0, 1, 1/3, -1/3, /**/ -1/3, 1/3, 1, 0, 0, 0];
static _CURVE_DEF_11 = [0, 0, 0, 1, 1/3, 0, /**/ -1/3, 0, 1, 1, 0, 0]; static _CURVE_DEF_11 = [0, 1, /**/ 0, 0, 0, 1, 1/3, 0, /**/ -1/3, 0, 1, 1, 0, 0];
if(array_equals(_bz, _CURVE_DEF_11)) return 1; if(array_equals(_bz, _CURVE_DEF_11)) return 1;
if(array_equals(_bz, _CURVE_DEF_01)) return _x; if(array_equals(_bz, _CURVE_DEF_01)) return _x;
if(array_equals(_bz, _CURVE_DEF_10)) return 1 - _x; if(array_equals(_bz, _CURVE_DEF_10)) return 1 - _x;
var segments = array_length(_bz) / 6 - 1; var _amo = array_length(_bz);
var _shf = _amo % 6;
var _shift = 0;
var _scale = 1;
if(_shf) {
var _shift = _bz[0];
var _scale = _bz[1];
}
var segments = (_amo - _shf) / 6 - 1;
_x = _x / _scale - _shift;
_x = clamp(_x, 0, 1); _x = clamp(_x, 0, 1);
for( var i = 0; i < segments; i++ ) { for( var i = 0; i < segments; i++ ) {
var ind = i * 6; var ind = _shf + i * 6;
var _x0 = _bz[ind + 2]; var _x0 = _bz[ind + 2];
var _y0 = _bz[ind + 3]; var _y0 = _bz[ind + 3];
//var bx0 = _x0 + _bz[ind + 0]; //var bx0 = _x0 + _bz[ind + 0];

View file

@ -701,10 +701,16 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor {
if(is_array(value)) { if(is_array(value)) {
for(var j = 0; j < array_length(value); j++) for(var j = 0; j < array_length(value); j++)
_val[j] = processValue(value[j]); _val[j] = processValue(value[j]);
} else if(is_array(base)) { } else if(is_array(base)) {
for(var j = 0; j < array_length(base); j++) for(var j = 0; j < array_length(base); j++)
_val[j] = processValue(value); _val[j] = processValue(value);
} }
if(prop.type == VALUE_TYPE.curve && array_length(value) % 6 == 0) {
array_insert(_val, 0, 0);
array_insert(_val, 1, 1);
}
} }
//print($"Deserialize {prop.node.name}:{prop.name} = {_val} "); //print($"Deserialize {prop.node.name}:{prop.name} = {_val} ");

View file

@ -1,5 +1,6 @@
function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor {
name = "Line"; name = "Line";
batch_output = true;
inputs[| 0] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF ) inputs[| 0] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF )
.setDisplay(VALUE_DISPLAY.vector); .setDisplay(VALUE_DISPLAY.vector);
@ -43,7 +44,7 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
inputs[| 15] = nodeValue("Span color over path", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false, "Apply the full 'color over length' to the trimmed path."); inputs[| 15] = nodeValue("Span color over path", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false, "Apply the full 'color over length' to the trimmed path.");
inputs[| 16] = nodeValue("Greyscale over width", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false); inputs[| 16] = nodeValue("Width pass", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
inputs[| 17] = nodeValue("1px mode", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false, "Render pixel perfect 1px line."); inputs[| 17] = nodeValue("1px mode", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false, "Render pixel perfect 1px line.");
@ -79,6 +80,8 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
outputs[| 1] = nodeValue("Width Pass", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
lines = []; lines = [];
widthMap = ds_map_create(); widthMap = ds_map_create();
@ -133,7 +136,7 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
if(index == 11) ds_map_clear(widthMap); if(index == 11) ds_map_clear(widthMap);
} #endregion } #endregion
static processData = function(_outSurf, _data, _output_index, _array_index) { #region static processData = function(_outData, _data, _output_index, _array_index) { #region
#region data #region data
var _dim = _data[0]; var _dim = _data[0];
var _bg = _data[1]; var _bg = _data[1];
@ -195,7 +198,8 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
random_set_seed(_sed); random_set_seed(_sed);
var _sedIndex = 0; var _sedIndex = 0;
_outSurf = surface_verify(_outSurf, _dim[0], _dim[1], attrDepth()); var _colorPass = surface_verify(_outData[0], _dim[0], _dim[1], attrDepth());
var _widthPass = surface_verify(_outData[1], _dim[0], _dim[1], attrDepth());
var p = new __vec2(); var p = new __vec2();
var _ox, _nx, _nx1, _oy, _ny, _ny1; var _ox, _nx, _nx1, _oy, _ny, _ny1;
@ -281,9 +285,9 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
// print($"_pp = {_pp}, total = {_total}"); // print($"_pp = {_pp}, total = {_total}");
p = _pat.getPointDistance(_pp, i, p); p = _pat.getPointDistance(_pp, i, p);
if(struct_has(_pat, "getWeightDistance")) if(struct_has(_pat, "getWeightDistance"))
wght = _pat.getWeightDistance(_pp, i); wght = _pat.getWeightDistance(_pp, i);
} else { } else {
_prog_next = min(_prog_curr + _stepLen, 1); //Move forward _stepLen or _total (if less) stop at 1 _prog_next = min(_prog_curr + _stepLen, 1); //Move forward _stepLen or _total (if less) stop at 1
_pathPng = _ratInv? 1 - _prog_curr : _prog_curr; _pathPng = _ratInv? 1 - _prog_curr : _prog_curr;
@ -341,6 +345,7 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
array_resize(lines, _lineAmo); array_resize(lines, _lineAmo);
#endregion #endregion
} else { #region } else { #region
var x0, y0, x1, y1; var x0, y0, x1, y1;
var _0 = point_rectangle_overlap(_dim[0], _dim[1], (_ang + 180) % 360); var _0 = point_rectangle_overlap(_dim[0], _dim[1], (_ang + 180) % 360);
@ -385,143 +390,233 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
} #endregion } #endregion
#region draw #region draw
surface_set_target(_colorPass);
if(_bg) draw_clear_alpha(0, 1);
else DRAW_CLEAR
if(_useTex) { #region
var tex = surface_get_texture(_tex);
shader_set(sh_draw_mapping);
shader_set_f("position", _texPos);
shader_set_f("rotation", degtorad(_texRot));
shader_set_f("scale", _texSca);
shader_set_interpolation(_tex);
} #endregion
for( var i = 0, n = array_length(lines); i < n; i++ ) {
var points = lines[i];
if(array_length(points) < 2) continue;
var _caps = [];
if(_useTex) draw_primitive_begin_texture(pr_trianglestrip, tex);
else draw_primitive_begin(pr_trianglestrip);
random_set_seed(_sed + i);
var pxs = [];
var dat = array_safe_get_fast(_pathData, i, noone);
var _col_base = dat == noone? _colb.eval(random(1)) : dat.color;
for( var j = 0; j < array_length(points); j++ ) {
var p0 = points[j];
var _nx = p0.x - 0.5 * _1px;
var _ny = p0.y - 0.5 * _1px;
var prog = p0.prog;
var prgc = p0.progCrop;
var _dir = j? point_direction(_ox, _oy, _nx, _ny) : 0;
var widProg = value_snap_real(_widap? prog : prgc, 0.01);
_nw = random_range(_wid[0], _wid[1]);
if(!ds_map_exists(widthMap, widProg))
widthMap[? widProg] = eval_curve_x(_widc, widProg, 0.1);
_nw *= widthMap[? widProg];
_nw *= p0.weight;
_nc = colorMultiply(_col_base, _color.eval(_colP? prog : prgc));
if(_cap) { #region
if(j == 1) {
_d = _dir + 180;
_caps[0] = [ _oc, _ox, _oy, _ow / 2, _d - 90, _d ];
_caps[1] = [ _oc, _ox, _oy, _ow / 2, _d, _d + 90 ];
}
if(j == array_length(points) - 1) {
_d = _dir;
_caps[2] = [ _nc, _nx, _ny, _nw / 2, _d - 90, _d ];
_caps[3] = [ _nc, _nx, _ny, _nw / 2, _d, _d + 90 ];
}
} #endregion
if(_1px) { #region
if(j) {
var dst = point_distance(_ox, _oy, _nx, _ny);
if(dst <= 1 && i < array_length(points) - 1) continue;
draw_line_color(_ox, _oy, _nx, _ny, _oc, _nc);
}
_ox = _nx;
_oy = _ny;
_oc = _nc;
#endregion
} else { #region
if(j) {
var _nd0 = _dir;
var _nd1 = _nd0;
if(j < array_length(points) - 1) {
var p2 = points[j + 1];
var _nnx = p2.x;
var _nny = p2.y;
_nd1 = point_direction(_nx, _ny, _nnx, _nny);
_nd = _nd0 + angle_difference(_nd1, _nd0) / 2;
} else
_nd = _nd0;
if(_useTex) {
var _len = array_length(points) - 1;
var ox0 = _ox + lengthdir_x(_ow / 2, _od + 90);
var oy0 = _oy + lengthdir_y(_ow / 2, _od + 90);
var nx0 = _nx + lengthdir_x(_nw / 2, _nd + 90);
var ny0 = _ny + lengthdir_y(_nw / 2, _nd + 90);
surface_set_target(_outSurf); var ox1 = _ox + lengthdir_x(_ow / 2, _od + 90 + 180);
if(_bg) draw_clear_alpha(0, 1); var oy1 = _oy + lengthdir_y(_ow / 2, _od + 90 + 180);
else DRAW_CLEAR var nx1 = _nx + lengthdir_x(_nw / 2, _nd + 90 + 180);
var ny1 = _ny + lengthdir_y(_nw / 2, _nd + 90 + 180);
if(_useTex) { #region
var tex = surface_get_texture(_tex); draw_vertex_texture_color(ox0, oy0, 0, (j - 1) / _len, _oc, 1);
draw_vertex_texture_color(ox1, oy1, 1, (j - 1) / _len, _oc, 1);
shader_set(sh_draw_mapping); draw_vertex_texture_color(nx0, ny0, 0, (j - 0) / _len, _nc, 1);
shader_set_f("position", _texPos); draw_vertex_texture_color(nx1, ny1, 1, (j - 0) / _len, _nc, 1);
shader_set_f("rotation", degtorad(_texRot));
shader_set_f("scale", _texSca); } else
draw_line_width2_angle(_ox, _oy, _nx, _ny, _ow, _nw, _od + 90, _nd + 90, _oc, _nc);
shader_set_interpolation(_tex); } else {
} #endregion var p1 = points[j + 1];
_nd = point_direction(_nx, _ny, p1.x, p1.y);
for( var i = 0, n = array_length(lines); i < n; i++ ) { }
var points = lines[i];
if(array_length(points) < 2) continue;
var _caps = [];
if(_useTex) draw_primitive_begin_texture(pr_trianglestrip, tex);
else draw_primitive_begin(pr_trianglestrip);
random_set_seed(_sed + i);
var pxs = [];
var dat = array_safe_get_fast(_pathData, i, noone);
var _col_base = dat == noone? _colb.eval(random(1)) : dat.color;
for( var j = 0; j < array_length(points); j++ ) {
var p0 = points[j];
var _nx = p0.x - 0.5 * _1px;
var _ny = p0.y - 0.5 * _1px;
var prog = p0.prog;
var prgc = p0.progCrop;
var _dir = j? point_direction(_ox, _oy, _nx, _ny) : 0;
var widProg = value_snap_real(_widap? prog : prgc, 0.01);
_nw = random_range(_wid[0], _wid[1]);
if(!ds_map_exists(widthMap, widProg))
widthMap[? widProg] = eval_curve_x(_widc, widProg, 0.1);
_nw *= widthMap[? widProg];
_nw *= p0.weight;
_nc = colorMultiply(_col_base, _color.eval(_colP? prog : prgc));
if(_cap) { #region
if(j == 1) {
_d = _dir + 180;
_caps[0] = [ _oc, _ox, _oy, _ow / 2, _d - 90, _d ];
_caps[1] = [ _oc, _ox, _oy, _ow / 2, _d, _d + 90 ];
}
if(j == array_length(points) - 1) { _ox = _nx;
_d = _dir; _oy = _ny;
_caps[2] = [ _nc, _nx, _ny, _nw / 2, _d - 90, _d ]; _od = _nd;
_caps[3] = [ _nc, _nx, _ny, _nw / 2, _d, _d + 90 ]; _ow = _nw;
_oc = _nc;
} }
} #endregion
if(_1px) { #region
if(j) {
var dst = point_distance(_ox, _oy, _nx, _ny);
if(dst <= 1 && i < array_length(points) - 1) continue;
draw_line_color(_ox, _oy, _nx, _ny, _oc, _nc);
}
_ox = _nx;
_oy = _ny;
_oc = _nc;
#endregion #endregion
} else { #region
if(j) {
var _nd0 = _dir;
var _nd1 = _nd0;
if(j < array_length(points) - 1) {
var p2 = points[j + 1];
var _nnx = p2.x;
var _nny = p2.y;
_nd1 = point_direction(_nx, _ny, _nnx, _nny);
_nd = _nd0 + angle_difference(_nd1, _nd0) / 2;
} else
_nd = _nd0;
if(_useTex) {
var _len = array_length(points) - 1;
var ox0 = _ox + lengthdir_x(_ow / 2, _od + 90);
var oy0 = _oy + lengthdir_y(_ow / 2, _od + 90);
var nx0 = _nx + lengthdir_x(_nw / 2, _nd + 90);
var ny0 = _ny + lengthdir_y(_nw / 2, _nd + 90);
var ox1 = _ox + lengthdir_x(_ow / 2, _od + 90 + 180);
var oy1 = _oy + lengthdir_y(_ow / 2, _od + 90 + 180);
var nx1 = _nx + lengthdir_x(_nw / 2, _nd + 90 + 180);
var ny1 = _ny + lengthdir_y(_nw / 2, _nd + 90 + 180);
draw_vertex_texture_color(ox0, oy0, 0, (j - 1) / _len, _oc, 1);
draw_vertex_texture_color(ox1, oy1, 1, (j - 1) / _len, _oc, 1);
draw_vertex_texture_color(nx0, ny0, 0, (j - 0) / _len, _nc, 1);
draw_vertex_texture_color(nx1, ny1, 1, (j - 0) / _len, _nc, 1);
} else if(_colW)
draw_line_width2_angle_width(_ox, _oy, _nx, _ny, _ow, _nw, _od + 90, _nd + 90, merge_color(_oc, c_black, 0.5), merge_color(_nc, c_black, 0.5));
else
draw_line_width2_angle(_ox, _oy, _nx, _ny, _ow, _nw, _od + 90, _nd + 90, _oc, _nc);
} else {
var p1 = points[j + 1];
_nd = point_direction(_nx, _ny, p1.x, p1.y);
}
_ox = _nx;
_oy = _ny;
_od = _nd;
_ow = _nw;
_oc = _nc;
} }
#endregion
draw_primitive_end();
for( var j = 0, m = array_length(_caps); j < m; j++ ) {
var _cps = _caps[j];
draw_set_color(_cps[0]);
draw_circle_angle(_cps[1], _cps[2], _cps[3], _cps[4], _cps[5], _capP);
}
} }
draw_primitive_end(); if(_useTex) shader_reset();
surface_reset_target();
for( var j = 0, m = array_length(_caps); j < m; j++ ) {
var _cps = _caps[j];
draw_set_color(_cps[0]);
draw_circle_angle(_cps[1], _cps[2], _cps[3], _cps[4], _cps[5], _capP);
}
}
if(_useTex) shader_reset(); if(_colW && !_1px) {
surface_reset_target();
surface_set_target(_widthPass);
if(_bg) draw_clear_alpha(0, 1);
else DRAW_CLEAR
for( var i = 0, n = array_length(lines); i < n; i++ ) {
var points = lines[i];
if(array_length(points) < 2) continue;
var _caps = [];
draw_primitive_begin(pr_trianglestrip);
random_set_seed(_sed + i);
var pxs = [];
var dat = array_safe_get_fast(_pathData, i, noone);
var _col_base = dat == noone? _colb.eval(random(1)) : dat.color;
for( var j = 0; j < array_length(points); j++ ) {
var p0 = points[j];
var _nx = p0.x - 0.5 * _1px;
var _ny = p0.y - 0.5 * _1px;
var prog = p0.prog;
var prgc = p0.progCrop;
var _dir = j? point_direction(_ox, _oy, _nx, _ny) : 0;
var widProg = value_snap_real(_widap? prog : prgc, 0.01);
_nw = random_range(_wid[0], _wid[1]);
if(!ds_map_exists(widthMap, widProg))
widthMap[? widProg] = eval_curve_x(_widc, widProg, 0.1);
_nw *= widthMap[? widProg];
_nw *= p0.weight;
if(_cap) { #region
if(j == 1) {
_d = _dir + 180;
_caps[0] = [ c_grey, _ox, _oy, _ow / 2, _d - 90, _d ];
_caps[1] = [ c_grey, _ox, _oy, _ow / 2, _d, _d + 90 ];
}
if(j == array_length(points) - 1) {
_d = _dir;
_caps[2] = [ c_grey, _nx, _ny, _nw / 2, _d - 90, _d ];
_caps[3] = [ c_grey, _nx, _ny, _nw / 2, _d, _d + 90 ];
}
} #endregion
if(j) {
var _nd0 = _dir;
var _nd1 = _nd0;
if(j < array_length(points) - 1) {
var p2 = points[j + 1];
var _nnx = p2.x;
var _nny = p2.y;
_nd1 = point_direction(_nx, _ny, _nnx, _nny);
_nd = _nd0 + angle_difference(_nd1, _nd0) / 2;
} else
_nd = _nd0;
draw_line_width2_angle_width(_ox, _oy, _nx, _ny, _ow, _nw, _od + 90, _nd + 90, c_white, c_white);
} else {
var p1 = points[j + 1];
_nd = point_direction(_nx, _ny, p1.x, p1.y);
}
_ox = _nx;
_oy = _ny;
_od = _nd;
_ow = _nw;
#endregion
}
draw_primitive_end();
for( var j = 0, m = array_length(_caps); j < m; j++ ) {
var _cps = _caps[j];
draw_set_color(_cps[0]);
draw_circle_angle(_cps[1], _cps[2], _cps[3], _cps[4], _cps[5], _capP);
}
}
surface_reset_target();
}
#endregion #endregion
return _outSurf; return [ _colorPass, _widthPass ];
} #endregion } #endregion
} }

View file

@ -41,7 +41,8 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
["Anchors", false], ["Anchors", false],
]; ];
output_display_list = [ 1, 0, 2 ]; output_display_list = [ 1, 0, 2 ];
path_preview_surface = noone;
setDynamicInput(1, false); setDynamicInput(1, false);
@ -845,6 +846,50 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
lengthTotal += l; lengthTotal += l;
lengthAccs[i] = lengthTotal; lengthAccs[i] = lengthTotal;
} }
var minx = boundary.minx - 8, miny = boundary.miny - 8;
var maxx = boundary.maxx + 8, maxy = boundary.maxy + 8;
var rngx = maxx - minx, rngy = maxy - miny;
var prev_s = 128;
var _surf = surface_create(prev_s, prev_s);
_surf = surface_verify(_surf, prev_s, prev_s);
surface_set_target(_surf);
DRAW_CLEAR
var ox, oy, nx, ny;
draw_set_color(c_white);
for (var i = 0, n = array_length(segments); i < n; i++) {
var segment = segments[i];
for (var j = 0, m = array_length(segment); j < m; j += 2) {
nx = (segment[j + 0] - minx) / rngx * prev_s;
ny = (segment[j + 1] - miny) / rngy * prev_s;
if(j) draw_line_round(ox, oy, nx, ny, 3);
ox = nx;
oy = ny;
}
}
draw_set_color(COLORS._main_accent);
for (var i = 0, n = array_length(anchors); i < n; i++) {
var _a0 = anchors[i];
draw_circle((_a0[0] - minx) / rngx * prev_s, (_a0[1] - miny) / rngy * prev_s, 6, false);
}
surface_reset_target();
path_preview_surface = surface_verify(path_preview_surface, prev_s, prev_s);
surface_set_shader(path_preview_surface, sh_FXAA);
shader_set_f("dimension", prev_s, prev_s);
shader_set_f("cornerDis", 0.5);
shader_set_f("mixAmo", 1);
draw_surface(_surf, 0, 0);
surface_reset_shader();
surface_free(_surf);
} #endregion } #endregion
static getLineCount = function() { return 1; } static getLineCount = function() { return 1; }
@ -985,6 +1030,8 @@ function Node_Path(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region
var bbox = drawGetBbox(xx, yy, _s); var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(THEME.node_draw_path, 0, bbox.xc, bbox.yc, bbox.w, bbox.h); gpu_set_tex_filter(true);
draw_surface_bbox(path_preview_surface, bbox);
gpu_set_tex_filter(false);
} #endregion } #endregion
} }

View file

@ -1,5 +1,6 @@
function Node_Path_Scatter(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { function Node_Path_Scatter(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Scatter Path"; name = "Scatter Path";
setDimension(96, 48); setDimension(96, 48);
inputs[| 0] = nodeValue("Base Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.pathnode, noone) inputs[| 0] = nodeValue("Base Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.pathnode, noone)
@ -182,9 +183,18 @@ function Node_Path_Scatter(_x, _y, _group = noone) : Node(_x, _y, _group) constr
flip : _flip, flip : _flip,
} }
segment_counts[i] = array_clone(path_scat.getSegmentCount(0)); var _segment_counts = array_clone(path_scat.getSegmentCount(0));
line_lengths[i] = array_clone(path_scat.getLength(0)); var _line_lengths = array_clone(path_scat.getLength(0));
accu_lengths[i] = array_clone(path_scat.getAccuLength(0)); var _accu_lengths = array_clone(path_scat.getAccuLength(0));
_line_lengths *= _sca;
for (var j = 0, m = array_length(_accu_lengths); j < m; j++)
_accu_lengths[j] *= _sca;
segment_counts[i] = _segment_counts;
line_lengths[i] = _line_lengths;
accu_lengths[i] = _accu_lengths;
} }
outputs[| 0].setValue(self); outputs[| 0].setValue(self);